Commit c970dbdfec
Changed files (1)
src
codegen
src/codegen/llvm.zig
@@ -825,6 +825,18 @@ pub const Object = struct {
/// Memoizes a null `?usize` value.
null_opt_usize: Builder.Constant,
+ /// When an LLVM struct type is created, an entry is inserted into this
+ /// table for every zig source field of the struct that has a corresponding
+ /// LLVM struct field. comptime fields and 0 bit fields are not included.
+ /// The value is the LLVM struct field index.
+ /// This is denormalized data.
+ struct_field_map: std.AutoHashMapUnmanaged(ZigStructField, c_uint),
+
+ const ZigStructField = struct {
+ struct_ty: InternPool.Index,
+ field_index: u32,
+ };
+
pub const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, Builder.Type);
/// This is an ArrayHashMap as opposed to a HashMap because in `flushModule` we
@@ -979,6 +991,7 @@ pub const Object = struct {
.error_name_table = .none,
.extern_collisions = .{},
.null_opt_usize = .no_init,
+ .struct_field_map = .{},
};
}
@@ -994,6 +1007,7 @@ pub const Object = struct {
self.type_map.deinit(gpa);
self.extern_collisions.deinit(gpa);
self.builder.deinit();
+ self.struct_field_map.deinit(gpa);
self.* = undefined;
}
@@ -3274,7 +3288,10 @@ pub const Object = struct {
var llvm_field_types = std.ArrayListUnmanaged(Builder.Type){};
defer llvm_field_types.deinit(o.gpa);
+ // Although we can estimate how much capacity to add, these cannot be
+ // relied upon because of the recursive calls to lowerType below.
try llvm_field_types.ensureUnusedCapacity(o.gpa, struct_obj.fields.count());
+ try o.struct_field_map.ensureUnusedCapacity(o.gpa, @intCast(struct_obj.fields.count()));
comptime assert(struct_layout_version == 2);
var offset: u64 = 0;
@@ -3296,6 +3313,10 @@ pub const Object = struct {
o.gpa,
try o.builder.arrayType(padding_len, .i8),
);
+ try o.struct_field_map.put(o.gpa, .{
+ .struct_ty = t.toIntern(),
+ .field_index = field_and_index.index,
+ }, @intCast(llvm_field_types.items.len));
try llvm_field_types.append(o.gpa, try o.lowerType(field.ty));
offset += field.ty.abiSize(mod);
@@ -3319,7 +3340,10 @@ pub const Object = struct {
.anon_struct_type => |anon_struct_type| {
var llvm_field_types: std.ArrayListUnmanaged(Builder.Type) = .{};
defer llvm_field_types.deinit(o.gpa);
+ // Although we can estimate how much capacity to add, these cannot be
+ // relied upon because of the recursive calls to lowerType below.
try llvm_field_types.ensureUnusedCapacity(o.gpa, anon_struct_type.types.len);
+ try o.struct_field_map.ensureUnusedCapacity(o.gpa, anon_struct_type.types.len);
comptime assert(struct_layout_version == 2);
var offset: u64 = 0;
@@ -3328,7 +3352,8 @@ pub const Object = struct {
for (
anon_struct_type.types.get(ip),
anon_struct_type.values.get(ip),
- ) |field_ty, field_val| {
+ 0..,
+ ) |field_ty, field_val, field_index| {
if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue;
const field_align = field_ty.toType().abiAlignment(mod);
@@ -3341,6 +3366,10 @@ pub const Object = struct {
o.gpa,
try o.builder.arrayType(padding_len, .i8),
);
+ try o.struct_field_map.put(o.gpa, .{
+ .struct_ty = t.toIntern(),
+ .field_index = @intCast(field_index),
+ }, @intCast(llvm_field_types.items.len));
try llvm_field_types.append(o.gpa, try o.lowerType(field_ty.toType()));
offset += field_ty.toType().abiSize(mod);
@@ -4237,9 +4266,9 @@ pub const Object = struct {
try o.lowerType(parent_ty),
parent_ptr,
null,
- if (llvmField(parent_ty, field_index, mod)) |llvm_field| &.{
+ if (o.llvmFieldIndex(parent_ty, field_index)) |llvm_field_index| &.{
try o.builder.intConst(.i32, 0),
- try o.builder.intConst(.i32, llvm_field.index),
+ try o.builder.intConst(.i32, llvm_field_index),
} else &.{
try o.builder.intConst(.i32, @intFromBool(
parent_ty.hasRuntimeBitsIgnoreComptime(mod),
@@ -4396,6 +4425,13 @@ pub const Object = struct {
try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = alignment }, &o.builder);
if (byval) try attributes.addParamAttr(llvm_arg_i, .{ .byval = param_llvm_ty }, &o.builder);
}
+
+ fn llvmFieldIndex(o: *Object, struct_ty: Type, field_index: usize) ?c_uint {
+ return o.struct_field_map.get(.{
+ .struct_ty = struct_ty.toIntern(),
+ .field_index = @intCast(field_index),
+ });
+ }
};
pub const DeclGen = struct {
@@ -6142,7 +6178,7 @@ pub const FuncGen = struct {
return self.wip.cast(.trunc, shifted_value, elem_llvm_ty, "");
},
else => {
- const llvm_field_index = llvmField(struct_ty, field_index, mod).?.index;
+ const llvm_field_index = o.llvmFieldIndex(struct_ty, field_index).?;
return self.wip.extractValue(struct_llvm_val, &.{llvm_field_index}, "");
},
},
@@ -6169,23 +6205,25 @@ pub const FuncGen = struct {
switch (struct_ty.zigTypeTag(mod)) {
.Struct => {
- assert(struct_ty.containerLayout(mod) != .Packed);
- const llvm_field = llvmField(struct_ty, field_index, mod).?;
+ const layout = struct_ty.containerLayout(mod);
+ assert(layout != .Packed);
const struct_llvm_ty = try o.lowerType(struct_ty);
+ const llvm_field_index = o.llvmFieldIndex(struct_ty, field_index).?;
const field_ptr =
- try self.wip.gepStruct(struct_llvm_ty, struct_llvm_val, llvm_field.index, "");
+ try self.wip.gepStruct(struct_llvm_ty, struct_llvm_val, llvm_field_index, "");
+ const alignment = struct_ty.structFieldAlign(field_index, mod);
const field_ptr_ty = try mod.ptrType(.{
- .child = llvm_field.ty.toIntern(),
+ .child = field_ty.toIntern(),
.flags = .{
- .alignment = InternPool.Alignment.fromNonzeroByteUnits(llvm_field.alignment),
+ .alignment = InternPool.Alignment.fromNonzeroByteUnits(alignment),
},
});
if (isByRef(field_ty, mod)) {
if (canElideLoad(self, body_tail))
return field_ptr;
- assert(llvm_field.alignment != 0);
- const field_alignment = Builder.Alignment.fromByteUnits(llvm_field.alignment);
+ assert(alignment != 0);
+ const field_alignment = Builder.Alignment.fromByteUnits(alignment);
return self.loadByRef(field_ptr, field_ty, field_alignment, .normal);
} else {
return self.load(field_ptr, field_ptr_ty);
@@ -7080,15 +7118,17 @@ pub const FuncGen = struct {
const field_index = ty_pl.payload;
const mod = o.module;
- const llvm_field = llvmField(struct_ty, field_index, mod).?;
const struct_llvm_ty = try o.lowerType(struct_ty);
+ const llvm_field_index = o.llvmFieldIndex(struct_ty, field_index).?;
assert(self.err_ret_trace != .none);
const field_ptr =
- try self.wip.gepStruct(struct_llvm_ty, self.err_ret_trace, llvm_field.index, "");
+ try self.wip.gepStruct(struct_llvm_ty, self.err_ret_trace, llvm_field_index, "");
+ const field_alignment = struct_ty.structFieldAlign(field_index, mod);
+ const field_ty = struct_ty.structFieldType(field_index, mod);
const field_ptr_ty = try mod.ptrType(.{
- .child = llvm_field.ty.toIntern(),
+ .child = field_ty.toIntern(),
.flags = .{
- .alignment = InternPool.Alignment.fromNonzeroByteUnits(llvm_field.alignment),
+ .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_alignment),
},
});
return self.load(field_ptr, field_ptr_ty);
@@ -7640,8 +7680,8 @@ pub const FuncGen = struct {
const result_val = try self.wip.extractValue(results, &.{0}, "");
const overflow_bit = try self.wip.extractValue(results, &.{1}, "");
- const result_index = llvmField(inst_ty, 0, mod).?.index;
- const overflow_index = llvmField(inst_ty, 1, mod).?.index;
+ const result_index = o.llvmFieldIndex(inst_ty, 0).?;
+ const overflow_index = o.llvmFieldIndex(inst_ty, 1).?;
if (isByRef(inst_ty, mod)) {
const result_alignment = Builder.Alignment.fromByteUnits(inst_ty.abiAlignment(mod));
@@ -7998,8 +8038,8 @@ pub const FuncGen = struct {
const overflow_bit = try self.wip.icmp(.ne, lhs, reconstructed, "");
- const result_index = llvmField(dest_ty, 0, mod).?.index;
- const overflow_index = llvmField(dest_ty, 1, mod).?.index;
+ const result_index = o.llvmFieldIndex(dest_ty, 0).?;
+ const overflow_index = o.llvmFieldIndex(dest_ty, 1).?;
if (isByRef(dest_ty, mod)) {
const result_alignment = Builder.Alignment.fromByteUnits(dest_ty.abiAlignment(mod));
@@ -9616,7 +9656,7 @@ pub const FuncGen = struct {
if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue;
const llvm_elem = try self.resolveInst(elem);
- const llvm_i = llvmField(result_ty, i, mod).?.index;
+ const llvm_i = o.llvmFieldIndex(result_ty, i).?;
const field_ptr =
try self.wip.gepStruct(llvm_result_ty, alloca_inst, llvm_i, "");
const field_ptr_ty = try mod.ptrType(.{
@@ -9637,7 +9677,7 @@ pub const FuncGen = struct {
if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue;
const llvm_elem = try self.resolveInst(elem);
- const llvm_i = llvmField(result_ty, i, mod).?.index;
+ const llvm_i = o.llvmFieldIndex(result_ty, i).?;
result = try self.wip.insertValue(result, llvm_elem, &.{llvm_i}, "");
}
return result;
@@ -10059,8 +10099,8 @@ pub const FuncGen = struct {
else => {
const struct_llvm_ty = try o.lowerPtrElemTy(struct_ty);
- if (llvmField(struct_ty, field_index, mod)) |llvm_field| {
- return self.wip.gepStruct(struct_llvm_ty, struct_ptr, llvm_field.index, "");
+ if (o.llvmFieldIndex(struct_ty, field_index)) |llvm_field_index| {
+ return self.wip.gepStruct(struct_llvm_ty, struct_ptr, llvm_field_index, "");
} else {
// If we found no index then this means this is a zero sized field at the
// end of the struct. Treat our struct pointer as an array of two and get
@@ -10527,90 +10567,6 @@ fn toLlvmGlobalAddressSpace(wanted_address_space: std.builtin.AddressSpace, targ
};
}
-const LlvmField = struct {
- index: c_uint,
- ty: Type,
- alignment: u32,
-};
-
-/// Take into account 0 bit fields and padding. Returns null if an llvm
-/// field could not be found.
-/// This only happens if you want the field index of a zero sized field at
-/// the end of the struct.
-fn llvmField(ty: Type, field_index: usize, mod: *Module) ?LlvmField {
- // Detects where we inserted extra padding fields so that we can skip
- // over them in this function.
- comptime assert(struct_layout_version == 2);
- var offset: u64 = 0;
- var big_align: u32 = 0;
-
- const ip = &mod.intern_pool;
- const struct_type = switch (ip.indexToKey(ty.toIntern())) {
- .anon_struct_type => |tuple| {
- var llvm_field_index: c_uint = 0;
- for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| {
- if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue;
-
- const field_align = field_ty.toType().abiAlignment(mod);
- big_align = @max(big_align, field_align);
- const prev_offset = offset;
- offset = std.mem.alignForward(u64, offset, field_align);
-
- const padding_len = offset - prev_offset;
- if (padding_len > 0) {
- llvm_field_index += 1;
- }
-
- if (field_index <= i) {
- return .{
- .index = llvm_field_index,
- .ty = field_ty.toType(),
- .alignment = field_align,
- };
- }
-
- llvm_field_index += 1;
- offset += field_ty.toType().abiSize(mod);
- }
- return null;
- },
- .struct_type => |s| s,
- else => unreachable,
- };
- const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
- const layout = struct_obj.layout;
- assert(layout != .Packed);
-
- var llvm_field_index: c_uint = 0;
- var it = struct_obj.runtimeFieldIterator(mod);
- while (it.next()) |field_and_index| {
- const field = field_and_index.field;
- const field_align = field.alignment(mod, layout);
- big_align = @max(big_align, field_align);
- const prev_offset = offset;
- offset = std.mem.alignForward(u64, offset, field_align);
-
- const padding_len = offset - prev_offset;
- if (padding_len > 0) {
- llvm_field_index += 1;
- }
-
- if (field_index == field_and_index.index) {
- return .{
- .index = llvm_field_index,
- .ty = field.ty,
- .alignment = field_align,
- };
- }
-
- llvm_field_index += 1;
- offset += field.ty.abiSize(mod);
- } else {
- // We did not find an llvm field that corresponds to this zig field.
- return null;
- }
-}
-
fn firstParamSRet(fn_info: InternPool.Key.FuncType, mod: *Module) bool {
const return_type = fn_info.return_type.toType();
if (!return_type.hasRuntimeBitsIgnoreComptime(mod)) return false;