authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-23 23:06:08-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-23 23:06:08-07:00
loga7088fd9a3edb037f0f51bb402a3c557334634f3
treedba5fd9f32b341d1cb64b9813033e1558c1e8d2b
parent8eff0a0a669dbdacf9cebbc96fdf20536f3073ee

compiler: packed structs cache bit offsets

Instead of linear search every time a packed struct field's bit or byte offset is wanted, they are computed once during resolution of the packed struct's backing int type, and stored in InternPool for O(1) lookup. Closes #17178

9 files changed, 75 insertions(+), 62 deletions(-)

src/InternPool.zig+46-6
...@@ -105,6 +105,25 @@ pub const MapIndex = enum(u32) {...@@ -105,6 +105,25 @@ pub const MapIndex = enum(u32) {
105 }105 }
106};106};
107107
108pub const OptionalInt = enum(u32) {
109 none = std.math.maxInt(u32),
110 _,
111
112 pub fn init(x: u32) @This() {
113 const result: @This() = @enumFromInt(x);
114 assert(result != .none);
115 return result;
116 }
117
118 pub fn initOptional(opt_x: ?u32) @This() {
119 return @This().init(opt_x orelse return .none);
120 }
121
122 pub fn unwrap(this: @This()) ?u32 {
123 return if (this == .none) null else @intFromEnum(this);
124 }
125};
126
108pub const RuntimeIndex = enum(u32) {127pub const RuntimeIndex = enum(u32) {
109 zero = 0,128 zero = 0,
110 comptime_field_ptr = std.math.maxInt(u32),129 comptime_field_ptr = std.math.maxInt(u32),
...@@ -377,6 +396,8 @@ pub const Key = union(enum) {...@@ -377,6 +396,8 @@ pub const Key = union(enum) {
377 field_aligns: Alignment.Slice,396 field_aligns: Alignment.Slice,
378 runtime_order: RuntimeOrder.Slice,397 runtime_order: RuntimeOrder.Slice,
379 comptime_bits: ComptimeBits,398 comptime_bits: ComptimeBits,
399 /// In the case of packed structs these are bit offsets; in the case of
400 /// non-packed structs these are byte offsets.
380 offsets: Offsets,401 offsets: Offsets,
381 names_map: OptionalMapIndex,402 names_map: OptionalMapIndex,
382403
...@@ -475,6 +496,15 @@ pub const Key = union(enum) {...@@ -475,6 +496,15 @@ pub const Key = union(enum) {
475 return s.field_names.get(ip)[i].toOptional();496 return s.field_names.get(ip)[i].toOptional();
476 }497 }
477498
499 /// Asserts it is a packed struct.
500 /// Asserts the layout is resolved.
501 pub fn fieldBitOffset(s: @This(), ip: *InternPool, i: usize) u32 {
502 assert(s.layout == .Packed);
503 assert(s.haveLayout(ip));
504 const result: OptionalInt = @enumFromInt(s.offsets.get(ip)[i]);
505 return result.unwrap().?;
506 }
507
478 pub fn fieldIsComptime(s: @This(), ip: *const InternPool, i: usize) bool {508 pub fn fieldIsComptime(s: @This(), ip: *const InternPool, i: usize) bool {
479 return s.comptime_bits.getBit(ip, i);509 return s.comptime_bits.getBit(ip, i);
480 }510 }
...@@ -593,7 +623,11 @@ pub const Key = union(enum) {...@@ -593,7 +623,11 @@ pub const Key = union(enum) {
593623
594 pub fn haveLayout(s: @This(), ip: *InternPool) bool {624 pub fn haveLayout(s: @This(), ip: *InternPool) bool {
595 return switch (s.layout) {625 return switch (s.layout) {
596 .Packed => s.backingIntType(ip).* != .none,626 .Packed => {
627 if (s.offsets.len == 0) return true;
628 const first_offset: OptionalInt = @enumFromInt(ip.extra.items[s.offsets.start]);
629 return first_offset != .none;
630 },
597 .Auto, .Extern => s.flagsPtr(ip).layout_resolved,631 .Auto, .Extern => s.flagsPtr(ip).layout_resolved,
598 };632 };
599 }633 }
...@@ -2936,7 +2970,8 @@ pub const Tag = enum(u8) {...@@ -2936,7 +2970,8 @@ pub const Tag = enum(u8) {
2936 /// Trailing:2970 /// Trailing:
2937 /// 0. type: Index for each fields_len2971 /// 0. type: Index for each fields_len
2938 /// 1. name: NullTerminatedString for each fields_len2972 /// 1. name: NullTerminatedString for each fields_len
2939 /// 2. init: Index for each fields_len // if tag is type_struct_packed_inits2973 /// 2. bit_offset: OptionalInt for each fields_len // none until layout resolved
2974 /// 3. init: Index for each fields_len // if tag is type_struct_packed_inits
2940 pub const TypeStructPacked = struct {2975 pub const TypeStructPacked = struct {
2941 decl: Module.Decl.Index,2976 decl: Module.Decl.Index,
2942 zir_index: Zir.Inst.Index,2977 zir_index: Zir.Inst.Index,
...@@ -4194,8 +4229,12 @@ fn extraPackedStructType(ip: *const InternPool, extra_index: u32, inits: bool) K...@@ -4194,8 +4229,12 @@ fn extraPackedStructType(ip: *const InternPool, extra_index: u32, inits: bool) K
4194 .start = type_struct_packed.end + fields_len,4229 .start = type_struct_packed.end + fields_len,
4195 .len = fields_len,4230 .len = fields_len,
4196 },4231 },
4232 .offsets = .{
4233 .start = type_struct_packed.end + fields_len * 2,
4234 .len = fields_len,
4235 },
4197 .field_inits = if (inits) .{4236 .field_inits = if (inits) .{
4198 .start = type_struct_packed.end + fields_len + fields_len,4237 .start = type_struct_packed.end + fields_len * 3,
4199 .len = fields_len,4238 .len = fields_len,
4200 } else .{4239 } else .{
4201 .start = 0,4240 .start = 0,
...@@ -4204,7 +4243,6 @@ fn extraPackedStructType(ip: *const InternPool, extra_index: u32, inits: bool) K...@@ -4204,7 +4243,6 @@ fn extraPackedStructType(ip: *const InternPool, extra_index: u32, inits: bool) K
4204 .field_aligns = .{ .start = 0, .len = 0 },4243 .field_aligns = .{ .start = 0, .len = 0 },
4205 .runtime_order = .{ .start = 0, .len = 0 },4244 .runtime_order = .{ .start = 0, .len = 0 },
4206 .comptime_bits = .{ .start = 0, .len = 0 },4245 .comptime_bits = .{ .start = 0, .len = 0 },
4207 .offsets = .{ .start = 0, .len = 0 },
4208 .names_map = type_struct_packed.data.names_map.toOptional(),4246 .names_map = type_struct_packed.data.names_map.toOptional(),
4209 };4247 };
4210}4248}
...@@ -5279,6 +5317,7 @@ pub fn getStructType(...@@ -5279,6 +5317,7 @@ pub fn getStructType(
5279 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeStructPacked).Struct.fields.len +5317 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeStructPacked).Struct.fields.len +
5280 ini.fields_len + // types5318 ini.fields_len + // types
5281 ini.fields_len + // names5319 ini.fields_len + // names
5320 ini.fields_len + // offsets
5282 ini.fields_len); // inits5321 ini.fields_len); // inits
5283 try ip.items.append(gpa, .{5322 try ip.items.append(gpa, .{
5284 .tag = if (ini.any_default_inits) .type_struct_packed_inits else .type_struct_packed,5323 .tag = if (ini.any_default_inits) .type_struct_packed_inits else .type_struct_packed,
...@@ -5293,6 +5332,7 @@ pub fn getStructType(...@@ -5293,6 +5332,7 @@ pub fn getStructType(
5293 });5332 });
5294 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);5333 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
5295 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(OptionalNullTerminatedString.none), ini.fields_len);5334 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(OptionalNullTerminatedString.none), ini.fields_len);
5335 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(OptionalInt.none), ini.fields_len);
5296 if (ini.any_default_inits) {5336 if (ini.any_default_inits) {
5297 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);5337 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
5298 }5338 }
...@@ -7113,12 +7153,12 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -7113,12 +7153,12 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
7113 .type_struct_packed => b: {7153 .type_struct_packed => b: {
7114 const info = ip.extraData(Tag.TypeStructPacked, data);7154 const info = ip.extraData(Tag.TypeStructPacked, data);
7115 break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).Struct.fields.len +7155 break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).Struct.fields.len +
7116 info.fields_len + info.fields_len);7156 info.fields_len + info.fields_len + info.fields_len);
7117 },7157 },
7118 .type_struct_packed_inits => b: {7158 .type_struct_packed_inits => b: {
7119 const info = ip.extraData(Tag.TypeStructPacked, data);7159 const info = ip.extraData(Tag.TypeStructPacked, data);
7120 break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).Struct.fields.len +7160 break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).Struct.fields.len +
7121 info.fields_len + info.fields_len + info.fields_len);7161 info.fields_len + info.fields_len + info.fields_len + info.fields_len);
7122 },7162 },
7123 .type_tuple_anon => b: {7163 .type_tuple_anon => b: {
7124 const info = ip.extraData(TypeStructAnon, data);7164 const info = ip.extraData(TypeStructAnon, data);
src/Module.zig-23
...@@ -6649,26 +6649,3 @@ pub fn structFieldAlignmentExtern(mod: *Module, field_ty: Type) Alignment {...@@ -6649,26 +6649,3 @@ pub fn structFieldAlignmentExtern(mod: *Module, field_ty: Type) Alignment {
66496649
6650 return ty_abi_align;6650 return ty_abi_align;
6651}6651}
6652
6653/// TODO: avoid linear search by storing these in trailing data of packed struct types
6654/// then packedStructFieldByteOffset can be expressed in terms of bits / 8, fixing
6655/// that one too.
6656/// https://github.com/ziglang/zig/issues/17178
6657pub fn structPackedFieldBitOffset(
6658 mod: *Module,
6659 struct_type: InternPool.Key.StructType,
6660 field_index: u32,
6661) u16 {
6662 const ip = &mod.intern_pool;
6663 assert(struct_type.layout == .Packed);
6664 assert(struct_type.haveLayout(ip));
6665 var bit_sum: u64 = 0;
6666 for (0..struct_type.field_types.len) |i| {
6667 if (i == field_index) {
6668 return @intCast(bit_sum);
6669 }
6670 const field_ty = struct_type.field_types.get(ip)[i].toType();
6671 bit_sum += field_ty.bitSize(mod);
6672 }
6673 unreachable; // index out of bounds
6674}
src/Sema.zig+5-2
...@@ -21342,8 +21342,10 @@ fn reifyStruct(...@@ -21342,8 +21342,10 @@ fn reifyStruct(
21342 }21342 }
2134321343
21344 var fields_bit_sum: u64 = 0;21344 var fields_bit_sum: u64 = 0;
21345 for (struct_type.field_types.get(ip)) |field_ty| {21345 for (0..struct_type.field_types.len) |i| {
21346 fields_bit_sum += field_ty.toType().bitSize(mod);21346 struct_type.offsets.get(ip)[i] = @intCast(fields_bit_sum);
21347 const field_ty = struct_type.field_types.get(ip)[i].toType();
21348 fields_bit_sum += field_ty.bitSize(mod);
21347 }21349 }
2134821350
21349 if (backing_int_val.optionalValue(mod)) |backing_int_ty_val| {21351 if (backing_int_val.optionalValue(mod)) |backing_int_ty_val| {
...@@ -34772,6 +34774,7 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp...@@ -34772,6 +34774,7 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp
34772 var accumulator: u64 = 0;34774 var accumulator: u64 = 0;
34773 for (0..struct_type.field_types.len) |i| {34775 for (0..struct_type.field_types.len) |i| {
34774 const field_ty = struct_type.field_types.get(ip)[i].toType();34776 const field_ty = struct_type.field_types.get(ip)[i].toType();
34777 struct_type.offsets.get(ip)[i] = @intCast(accumulator);
34775 accumulator += try field_ty.bitSizeAdvanced(mod, &sema);34778 accumulator += try field_ty.bitSizeAdvanced(mod, &sema);
34776 }34779 }
34777 break :blk accumulator;34780 break :blk accumulator;
src/arch/wasm/CodeGen.zig+1-1
...@@ -3779,7 +3779,7 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -3779,7 +3779,7 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3779 .Packed => switch (struct_ty.zigTypeTag(mod)) {3779 .Packed => switch (struct_ty.zigTypeTag(mod)) {
3780 .Struct => result: {3780 .Struct => result: {
3781 const packed_struct = mod.typeToPackedStruct(struct_ty).?;3781 const packed_struct = mod.typeToPackedStruct(struct_ty).?;
3782 const offset = mod.structPackedFieldBitOffset(packed_struct, field_index);3782 const offset = packed_struct.fieldBitOffset(ip, field_index);
3783 const backing_ty = packed_struct.backingIntType(ip).toType();3783 const backing_ty = packed_struct.backingIntType(ip).toType();
3784 const wasm_bits = toWasmBits(backing_ty.intInfo(mod).bits) orelse {3784 const wasm_bits = toWasmBits(backing_ty.intInfo(mod).bits) orelse {
3785 return func.fail("TODO: airStructFieldVal for packed structs larger than 128 bits", .{});3785 return func.fail("TODO: airStructFieldVal for packed structs larger than 128 bits", .{});
src/arch/x86_64/CodeGen.zig+4-2
...@@ -5593,6 +5593,7 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32...@@ -5593,6 +5593,7 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32
55935593
5594fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {5594fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
5595 const mod = self.bin_file.options.module.?;5595 const mod = self.bin_file.options.module.?;
5596 const ip = &mod.intern_pool;
5596 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;5597 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
5597 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;5598 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
5598 const result: MCValue = result: {5599 const result: MCValue = result: {
...@@ -5610,7 +5611,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -5610,7 +5611,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
5610 const field_off: u32 = switch (container_ty.containerLayout(mod)) {5611 const field_off: u32 = switch (container_ty.containerLayout(mod)) {
5611 .Auto, .Extern => @intCast(container_ty.structFieldOffset(index, mod) * 8),5612 .Auto, .Extern => @intCast(container_ty.structFieldOffset(index, mod) * 8),
5612 .Packed => if (mod.typeToStruct(container_ty)) |struct_type|5613 .Packed => if (mod.typeToStruct(container_ty)) |struct_type|
5613 mod.structPackedFieldBitOffset(struct_type, index)5614 struct_type.fieldBitOffset(ip, index)
5614 else5615 else
5615 0,5616 0,
5616 };5617 };
...@@ -11410,6 +11411,7 @@ fn airReduce(self: *Self, inst: Air.Inst.Index) !void {...@@ -11410,6 +11411,7 @@ fn airReduce(self: *Self, inst: Air.Inst.Index) !void {
1141011411
11411fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {11412fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
11412 const mod = self.bin_file.options.module.?;11413 const mod = self.bin_file.options.module.?;
11414 const ip = &mod.intern_pool;
11413 const result_ty = self.typeOfIndex(inst);11415 const result_ty = self.typeOfIndex(inst);
11414 const len: usize = @intCast(result_ty.arrayLen(mod));11416 const len: usize = @intCast(result_ty.arrayLen(mod));
11415 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;11417 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -11440,7 +11442,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -11440,7 +11442,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
11440 }11442 }
11441 const elem_abi_size: u32 = @intCast(elem_ty.abiSize(mod));11443 const elem_abi_size: u32 = @intCast(elem_ty.abiSize(mod));
11442 const elem_abi_bits = elem_abi_size * 8;11444 const elem_abi_bits = elem_abi_size * 8;
11443 const elem_off = mod.structPackedFieldBitOffset(struct_type, elem_i);11445 const elem_off = struct_type.fieldBitOffset(ip, elem_i);
11444 const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size);11446 const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size);
11445 const elem_bit_off = elem_off % elem_abi_bits;11447 const elem_bit_off = elem_off % elem_abi_bits;
11446 const elem_mcv = try self.resolveInst(elem);11448 const elem_mcv = try self.resolveInst(elem);
src/codegen.zig+9-8
...@@ -630,7 +630,8 @@ fn lowerParentPtr(...@@ -630,7 +630,8 @@ fn lowerParentPtr(
630 reloc_info: RelocInfo,630 reloc_info: RelocInfo,
631) CodeGenError!Result {631) CodeGenError!Result {
632 const mod = bin_file.options.module.?;632 const mod = bin_file.options.module.?;
633 const ptr = mod.intern_pool.indexToKey(parent_ptr).ptr;633 const ip = &mod.intern_pool;
634 const ptr = ip.indexToKey(parent_ptr).ptr;
634 assert(ptr.len == .none);635 assert(ptr.len == .none);
635 return switch (ptr.addr) {636 return switch (ptr.addr) {
636 .decl, .mut_decl => try lowerDeclRef(637 .decl, .mut_decl => try lowerDeclRef(
...@@ -656,7 +657,7 @@ fn lowerParentPtr(...@@ -656,7 +657,7 @@ fn lowerParentPtr(
656 code,657 code,
657 debug_output,658 debug_output,
658 reloc_info.offset(@as(u32, @intCast(errUnionPayloadOffset(659 reloc_info.offset(@as(u32, @intCast(errUnionPayloadOffset(
659 mod.intern_pool.typeOf(eu_payload).toType(),660 ip.typeOf(eu_payload).toType(),
660 mod,661 mod,
661 )))),662 )))),
662 ),663 ),
...@@ -675,17 +676,17 @@ fn lowerParentPtr(...@@ -675,17 +676,17 @@ fn lowerParentPtr(
675 code,676 code,
676 debug_output,677 debug_output,
677 reloc_info.offset(@as(u32, @intCast(elem.index *678 reloc_info.offset(@as(u32, @intCast(elem.index *
678 mod.intern_pool.typeOf(elem.base).toType().elemType2(mod).abiSize(mod)))),679 ip.typeOf(elem.base).toType().elemType2(mod).abiSize(mod)))),
679 ),680 ),
680 .field => |field| {681 .field => |field| {
681 const base_type = mod.intern_pool.indexToKey(mod.intern_pool.typeOf(field.base)).ptr_type.child;682 const base_type = ip.indexToKey(ip.typeOf(field.base)).ptr_type.child;
682 return lowerParentPtr(683 return lowerParentPtr(
683 bin_file,684 bin_file,
684 src_loc,685 src_loc,
685 field.base,686 field.base,
686 code,687 code,
687 debug_output,688 debug_output,
688 reloc_info.offset(switch (mod.intern_pool.indexToKey(base_type)) {689 reloc_info.offset(switch (ip.indexToKey(base_type)) {
689 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {690 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
690 .One, .Many, .C => unreachable,691 .One, .Many, .C => unreachable,
691 .Slice => switch (field.index) {692 .Slice => switch (field.index) {
...@@ -703,9 +704,9 @@ fn lowerParentPtr(...@@ -703,9 +704,9 @@ fn lowerParentPtr(
703 mod,704 mod,
704 )),705 )),
705 .Packed => if (mod.typeToStruct(base_type.toType())) |struct_type|706 .Packed => if (mod.typeToStruct(base_type.toType())) |struct_type|
706 math.divExact(u16, mod.structPackedFieldBitOffset(707 math.divExact(u32, struct_type.fieldBitOffset(
707 struct_type,708 ip,
708 @intCast(field.index),709 field.index,
709 ), 8) catch |err| switch (err) {710 ), 8) catch |err| switch (err) {
710 error.UnexpectedRemainder => 0,711 error.UnexpectedRemainder => 0,
711 error.DivisionByZero => unreachable,712 error.DivisionByZero => unreachable,
src/codegen/c.zig+1-1
...@@ -5429,7 +5429,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5429,7 +5429,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
54295429
5430 const bit_offset_ty = try mod.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1));5430 const bit_offset_ty = try mod.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1));
54315431
5432 const bit_offset = mod.structPackedFieldBitOffset(struct_type, extra.field_index);5432 const bit_offset = struct_type.fieldBitOffset(ip, extra.field_index);
5433 const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);5433 const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);
54345434
5435 const field_int_signedness = if (inst_ty.isAbiInt(mod))5435 const field_int_signedness = if (inst_ty.isAbiInt(mod))
src/codegen/llvm.zig+2-1
...@@ -6192,6 +6192,7 @@ pub const FuncGen = struct {...@@ -6192,6 +6192,7 @@ pub const FuncGen = struct {
6192 fn airStructFieldVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {6192 fn airStructFieldVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
6193 const o = self.dg.object;6193 const o = self.dg.object;
6194 const mod = o.module;6194 const mod = o.module;
6195 const ip = &mod.intern_pool;
6195 const inst = body_tail[0];6196 const inst = body_tail[0];
6196 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;6197 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
6197 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;6198 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
...@@ -6207,7 +6208,7 @@ pub const FuncGen = struct {...@@ -6207,7 +6208,7 @@ pub const FuncGen = struct {
6207 .Struct => switch (struct_ty.containerLayout(mod)) {6208 .Struct => switch (struct_ty.containerLayout(mod)) {
6208 .Packed => {6209 .Packed => {
6209 const struct_type = mod.typeToStruct(struct_ty).?;6210 const struct_type = mod.typeToStruct(struct_ty).?;
6210 const bit_offset = mod.structPackedFieldBitOffset(struct_type, field_index);6211 const bit_offset = struct_type.fieldBitOffset(ip, field_index);
6211 const containing_int = struct_llvm_val;6212 const containing_int = struct_llvm_val;
6212 const shift_amt =6213 const shift_amt =
6213 try o.builder.intValue(containing_int.typeOfWip(&self.wip), bit_offset);6214 try o.builder.intValue(containing_int.typeOfWip(&self.wip), bit_offset);
src/type.zig+7-18
...@@ -3021,27 +3021,16 @@ pub const Type = struct {...@@ -3021,27 +3021,16 @@ pub const Type = struct {
3021 };3021 };
3022 }3022 }
30233023
3024 pub fn packedStructFieldByteOffset(ty: Type, field_index: usize, mod: *Module) u32 {3024 pub fn packedStructFieldBitOffset(ty: Type, field_index: usize, mod: *Module) u32 {
3025 const ip = &mod.intern_pool;3025 const ip = &mod.intern_pool;
3026 const struct_type = ip.indexToKey(ty.toIntern()).struct_type;3026 const struct_type = ip.indexToKey(ty.toIntern()).struct_type;
3027 assert(struct_type.layout == .Packed);3027 assert(struct_type.layout == .Packed);
3028 comptime assert(Type.packed_struct_layout_version == 2);3028 assert(struct_type.haveLayout(ip));
30293029 return struct_type.offsets.get(ip)[field_index];
3030 var bit_offset: u16 = undefined;3030 }
3031 var elem_size_bits: u16 = undefined;3031
3032 var running_bits: u16 = 0;3032 pub fn packedStructFieldByteOffset(ty: Type, field_index: usize, mod: *Module) u32 {
3033 for (struct_type.field_types.get(ip), 0..) |field_ty, i| {3033 return packedStructFieldBitOffset(ty, field_index, mod) / 8;
3034 if (!field_ty.toType().hasRuntimeBits(mod)) continue;
3035
3036 const field_bits: u16 = @intCast(field_ty.toType().bitSize(mod));
3037 if (i == field_index) {
3038 bit_offset = running_bits;
3039 elem_size_bits = field_bits;
3040 }
3041 running_bits += field_bits;
3042 }
3043 const byte_offset = bit_offset / 8;
3044 return byte_offset;
3045 }3034 }
30463035
3047 pub const FieldOffset = struct {3036 pub const FieldOffset = struct {