authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-24 14:37:36-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-24 14:37:36-07:00
logc08c0fc6eddf601785abfbc5e5a9ab5c89d7cfbf
tree65cabc6acd2db112c1fa9557c2f34dfd04659113
parenta7088fd9a3edb037f0f51bb402a3c557334634f3

revert "compiler: packed structs cache bit offsets"

This is mostly a revert of a7088fd9a3edb037f0f51bb402a3c557334634f3. Measurement revealed the commit actually regressed performance.

9 files changed, 52 insertions(+), 67 deletions(-)

src/InternPool.zig+6-46
......@@ -105,25 +105,6 @@ pub const MapIndex = enum(u32) {
105105 }
106106};
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
127108pub const RuntimeIndex = enum(u32) {
128109 zero = 0,
129110 comptime_field_ptr = std.math.maxInt(u32),
......@@ -396,8 +377,6 @@ pub const Key = union(enum) {
396377 field_aligns: Alignment.Slice,
397378 runtime_order: RuntimeOrder.Slice,
398379 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.
401380 offsets: Offsets,
402381 names_map: OptionalMapIndex,
403382
......@@ -496,15 +475,6 @@ pub const Key = union(enum) {
496475 return s.field_names.get(ip)[i].toOptional();
497476 }
498477
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
508478 pub fn fieldIsComptime(s: @This(), ip: *const InternPool, i: usize) bool {
509479 return s.comptime_bits.getBit(ip, i);
510480 }
......@@ -623,11 +593,7 @@ pub const Key = union(enum) {
623593
624594 pub fn haveLayout(s: @This(), ip: *InternPool) bool {
625595 return switch (s.layout) {
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 },
596 .Packed => s.backingIntType(ip).* != .none,
631597 .Auto, .Extern => s.flagsPtr(ip).layout_resolved,
632598 };
633599 }
......@@ -2970,8 +2936,7 @@ pub const Tag = enum(u8) {
29702936 /// Trailing:
29712937 /// 0. type: Index for each fields_len
29722938 /// 1. name: NullTerminatedString for each fields_len
2973 /// 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
2939 /// 2. init: Index for each fields_len // if tag is type_struct_packed_inits
29752940 pub const TypeStructPacked = struct {
29762941 decl: Module.Decl.Index,
29772942 zir_index: Zir.Inst.Index,
......@@ -4229,12 +4194,8 @@ fn extraPackedStructType(ip: *const InternPool, extra_index: u32, inits: bool) K
42294194 .start = type_struct_packed.end + fields_len,
42304195 .len = fields_len,
42314196 },
4232 .offsets = .{
4233 .start = type_struct_packed.end + fields_len * 2,
4234 .len = fields_len,
4235 },
42364197 .field_inits = if (inits) .{
4237 .start = type_struct_packed.end + fields_len * 3,
4198 .start = type_struct_packed.end + fields_len * 2,
42384199 .len = fields_len,
42394200 } else .{
42404201 .start = 0,
......@@ -4243,6 +4204,7 @@ fn extraPackedStructType(ip: *const InternPool, extra_index: u32, inits: bool) K
42434204 .field_aligns = .{ .start = 0, .len = 0 },
42444205 .runtime_order = .{ .start = 0, .len = 0 },
42454206 .comptime_bits = .{ .start = 0, .len = 0 },
4207 .offsets = .{ .start = 0, .len = 0 },
42464208 .names_map = type_struct_packed.data.names_map.toOptional(),
42474209 };
42484210}
......@@ -5317,7 +5279,6 @@ pub fn getStructType(
53175279 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeStructPacked).Struct.fields.len +
53185280 ini.fields_len + // types
53195281 ini.fields_len + // names
5320 ini.fields_len + // offsets
53215282 ini.fields_len); // inits
53225283 try ip.items.append(gpa, .{
53235284 .tag = if (ini.any_default_inits) .type_struct_packed_inits else .type_struct_packed,
......@@ -5332,7 +5293,6 @@ pub fn getStructType(
53325293 });
53335294 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
53345295 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(OptionalNullTerminatedString.none), ini.fields_len);
5335 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(OptionalInt.none), ini.fields_len);
53365296 if (ini.any_default_inits) {
53375297 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
53385298 }
......@@ -7153,12 +7113,12 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
71537113 .type_struct_packed => b: {
71547114 const info = ip.extraData(Tag.TypeStructPacked, data);
71557115 break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).Struct.fields.len +
7156 info.fields_len + info.fields_len + info.fields_len);
7116 info.fields_len + info.fields_len);
71577117 },
71587118 .type_struct_packed_inits => b: {
71597119 const info = ip.extraData(Tag.TypeStructPacked, data);
71607120 break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).Struct.fields.len +
7161 info.fields_len + info.fields_len + info.fields_len + info.fields_len);
7121 info.fields_len + info.fields_len + info.fields_len);
71627122 },
71637123 .type_tuple_anon => b: {
71647124 const info = ip.extraData(TypeStructAnon, data);
src/Module.zig+23
......@@ -6649,3 +6649,26 @@ pub fn structFieldAlignmentExtern(mod: *Module, field_ty: Type) Alignment {
66496649
66506650 return ty_abi_align;
66516651}
6652
6653/// https://github.com/ziglang/zig/issues/17178 explored storing these bit offsets
6654/// into the packed struct InternPool data rather than computing this on the
6655/// fly, however it was found to perform worse when measured on real world
6656/// projects.
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-2
......@@ -21343,7 +21343,6 @@ fn reifyStruct(
2134321343
2134421344 var fields_bit_sum: u64 = 0;
2134521345 for (0..struct_type.field_types.len) |i| {
21346 struct_type.offsets.get(ip)[i] = @intCast(fields_bit_sum);
2134721346 const field_ty = struct_type.field_types.get(ip)[i].toType();
2134821347 fields_bit_sum += field_ty.bitSize(mod);
2134921348 }
......@@ -34774,7 +34773,6 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp
3477434773 var accumulator: u64 = 0;
3477534774 for (0..struct_type.field_types.len) |i| {
3477634775 const field_ty = struct_type.field_types.get(ip)[i].toType();
34777 struct_type.offsets.get(ip)[i] = @intCast(accumulator);
3477834776 accumulator += try field_ty.bitSizeAdvanced(mod, &sema);
3477934777 }
3478034778 break :blk accumulator;
src/arch/wasm/CodeGen.zig+1-1
......@@ -3779,7 +3779,7 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
37793779 .Packed => switch (struct_ty.zigTypeTag(mod)) {
37803780 .Struct => result: {
37813781 const packed_struct = mod.typeToPackedStruct(struct_ty).?;
3782 const offset = packed_struct.fieldBitOffset(ip, field_index);
3782 const offset = mod.structPackedFieldBitOffset(packed_struct, field_index);
37833783 const backing_ty = packed_struct.backingIntType(ip).toType();
37843784 const wasm_bits = toWasmBits(backing_ty.intInfo(mod).bits) orelse {
37853785 return func.fail("TODO: airStructFieldVal for packed structs larger than 128 bits", .{});
src/arch/x86_64/CodeGen.zig+2-4
......@@ -5593,7 +5593,6 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32
55935593
55945594fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
55955595 const mod = self.bin_file.options.module.?;
5596 const ip = &mod.intern_pool;
55975596 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
55985597 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
55995598 const result: MCValue = result: {
......@@ -5611,7 +5610,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
56115610 const field_off: u32 = switch (container_ty.containerLayout(mod)) {
56125611 .Auto, .Extern => @intCast(container_ty.structFieldOffset(index, mod) * 8),
56135612 .Packed => if (mod.typeToStruct(container_ty)) |struct_type|
5614 struct_type.fieldBitOffset(ip, index)
5613 mod.structPackedFieldBitOffset(struct_type, index)
56155614 else
56165615 0,
56175616 };
......@@ -11411,7 +11410,6 @@ fn airReduce(self: *Self, inst: Air.Inst.Index) !void {
1141111410
1141211411fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
1141311412 const mod = self.bin_file.options.module.?;
11414 const ip = &mod.intern_pool;
1141511413 const result_ty = self.typeOfIndex(inst);
1141611414 const len: usize = @intCast(result_ty.arrayLen(mod));
1141711415 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -11442,7 +11440,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
1144211440 }
1144311441 const elem_abi_size: u32 = @intCast(elem_ty.abiSize(mod));
1144411442 const elem_abi_bits = elem_abi_size * 8;
11445 const elem_off = struct_type.fieldBitOffset(ip, elem_i);
11443 const elem_off = mod.structPackedFieldBitOffset(struct_type, elem_i);
1144611444 const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size);
1144711445 const elem_bit_off = elem_off % elem_abi_bits;
1144811446 const elem_mcv = try self.resolveInst(elem);
src/codegen.zig+8-9
......@@ -630,8 +630,7 @@ fn lowerParentPtr(
630630 reloc_info: RelocInfo,
631631) CodeGenError!Result {
632632 const mod = bin_file.options.module.?;
633 const ip = &mod.intern_pool;
634 const ptr = ip.indexToKey(parent_ptr).ptr;
633 const ptr = mod.intern_pool.indexToKey(parent_ptr).ptr;
635634 assert(ptr.len == .none);
636635 return switch (ptr.addr) {
637636 .decl, .mut_decl => try lowerDeclRef(
......@@ -657,7 +656,7 @@ fn lowerParentPtr(
657656 code,
658657 debug_output,
659658 reloc_info.offset(@as(u32, @intCast(errUnionPayloadOffset(
660 ip.typeOf(eu_payload).toType(),
659 mod.intern_pool.typeOf(eu_payload).toType(),
661660 mod,
662661 )))),
663662 ),
......@@ -676,17 +675,17 @@ fn lowerParentPtr(
676675 code,
677676 debug_output,
678677 reloc_info.offset(@as(u32, @intCast(elem.index *
679 ip.typeOf(elem.base).toType().elemType2(mod).abiSize(mod)))),
678 mod.intern_pool.typeOf(elem.base).toType().elemType2(mod).abiSize(mod)))),
680679 ),
681680 .field => |field| {
682 const base_type = ip.indexToKey(ip.typeOf(field.base)).ptr_type.child;
681 const base_type = mod.intern_pool.indexToKey(mod.intern_pool.typeOf(field.base)).ptr_type.child;
683682 return lowerParentPtr(
684683 bin_file,
685684 src_loc,
686685 field.base,
687686 code,
688687 debug_output,
689 reloc_info.offset(switch (ip.indexToKey(base_type)) {
688 reloc_info.offset(switch (mod.intern_pool.indexToKey(base_type)) {
690689 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
691690 .One, .Many, .C => unreachable,
692691 .Slice => switch (field.index) {
......@@ -704,9 +703,9 @@ fn lowerParentPtr(
704703 mod,
705704 )),
706705 .Packed => if (mod.typeToStruct(base_type.toType())) |struct_type|
707 math.divExact(u32, struct_type.fieldBitOffset(
708 ip,
709 field.index,
706 math.divExact(u16, mod.structPackedFieldBitOffset(
707 struct_type,
708 @intCast(field.index),
710709 ), 8) catch |err| switch (err) {
711710 error.UnexpectedRemainder => 0,
712711 error.DivisionByZero => unreachable,
src/codegen/c.zig+1-1
......@@ -5429,7 +5429,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
54295429
54305430 const bit_offset_ty = try mod.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1));
54315431
5432 const bit_offset = struct_type.fieldBitOffset(ip, extra.field_index);
5432 const bit_offset = mod.structPackedFieldBitOffset(struct_type, extra.field_index);
54335433 const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);
54345434
54355435 const field_int_signedness = if (inst_ty.isAbiInt(mod))
src/codegen/llvm.zig+1-2
......@@ -6192,7 +6192,6 @@ pub const FuncGen = struct {
61926192 fn airStructFieldVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
61936193 const o = self.dg.object;
61946194 const mod = o.module;
6195 const ip = &mod.intern_pool;
61966195 const inst = body_tail[0];
61976196 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
61986197 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
......@@ -6208,7 +6207,7 @@ pub const FuncGen = struct {
62086207 .Struct => switch (struct_ty.containerLayout(mod)) {
62096208 .Packed => {
62106209 const struct_type = mod.typeToStruct(struct_ty).?;
6211 const bit_offset = struct_type.fieldBitOffset(ip, field_index);
6210 const bit_offset = mod.structPackedFieldBitOffset(struct_type, field_index);
62126211 const containing_int = struct_llvm_val;
62136212 const shift_amt =
62146213 try o.builder.intValue(containing_int.typeOfWip(&self.wip), bit_offset);
src/type.zig+10-2
......@@ -3025,8 +3025,16 @@ pub const Type = struct {
30253025 const ip = &mod.intern_pool;
30263026 const struct_type = ip.indexToKey(ty.toIntern()).struct_type;
30273027 assert(struct_type.layout == .Packed);
3028 assert(struct_type.haveLayout(ip));
3029 return struct_type.offsets.get(ip)[field_index];
3028 comptime assert(Type.packed_struct_layout_version == 2);
3029
3030 var running_bits: u32 = 0;
3031 for (struct_type.field_types.get(ip), 0..) |field_ty, i| {
3032 if (i == field_index) break;
3033 if (!field_ty.toType().hasRuntimeBits(mod)) continue;
3034 const field_bits: u32 = @intCast(field_ty.toType().bitSize(mod));
3035 running_bits += field_bits;
3036 }
3037 return running_bits;
30303038 }
30313039
30323040 pub fn packedStructFieldByteOffset(ty: Type, field_index: usize, mod: *Module) u32 {