diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2023-08-24 20:43:43 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-09-21 14:48:40 -0700 |
| commit | accd5701c251c2741479fe08e56c8271c444f021 (patch) | |
| tree | 78871f150609687a9210063e90f8f4eb53997c38 /src/value.zig | |
| parent | 0345d7866347c9066b0646f9e46be9a068dcfaa3 (diff) | |
| download | zig-accd5701c251c2741479fe08e56c8271c444f021.tar.gz zig-accd5701c251c2741479fe08e56c8271c444f021.zip | |
compiler: move struct types into InternPool proper
Structs were previously using `SegmentedList` to be given indexes, but
were not actually backed by the InternPool arrays.
After this, the only remaining uses of `SegmentedList` in the compiler
are `Module.Decl` and `Module.Namespace`. Once those last two are
migrated to become backed by InternPool arrays as well, we can introduce
state serialization via writing these arrays to disk all at once.
Unfortunately there are a lot of source code locations that touch the
struct type API, so this commit is still work-in-progress. Once I get it
compiling and passing the test suite, I can provide some interesting
data points such as how it affected the InternPool memory size and
performance comparison against master branch.
I also couldn't resist migrating over a bunch of alignment API over to
use the log2 Alignment type rather than a mismash of u32 and u64 byte
units with 0 meaning something implicitly different and special at every
location. Turns out you can do all the math you need directly on the
log2 representation of alignments.
Diffstat (limited to 'src/value.zig')
| -rw-r--r-- | src/value.zig | 214 |
1 files changed, 112 insertions, 102 deletions
diff --git a/src/value.zig b/src/value.zig index 13eb9106b5..e317373b28 100644 --- a/src/value.zig +++ b/src/value.zig @@ -462,7 +462,7 @@ pub const Value = struct { if (opt_sema) |sema| try sema.resolveTypeLayout(ty.toType()); const x = switch (int.storage) { else => unreachable, - .lazy_align => ty.toType().abiAlignment(mod), + .lazy_align => ty.toType().abiAlignment(mod).toByteUnits(0), .lazy_size => ty.toType().abiSize(mod), }; return BigIntMutable.init(&space.limbs, x).toConst(); @@ -523,9 +523,9 @@ pub const Value = struct { .u64 => |x| x, .i64 => |x| std.math.cast(u64, x), .lazy_align => |ty| if (opt_sema) |sema| - (try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar + (try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar.toByteUnits(0) else - ty.toType().abiAlignment(mod), + ty.toType().abiAlignment(mod).toByteUnits(0), .lazy_size => |ty| if (opt_sema) |sema| (try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar else @@ -569,9 +569,9 @@ pub const Value = struct { .int => |int| switch (int.storage) { .big_int => |big_int| big_int.to(i64) catch unreachable, .i64 => |x| x, - .u64 => |x| @as(i64, @intCast(x)), - .lazy_align => |ty| @as(i64, @intCast(ty.toType().abiAlignment(mod))), - .lazy_size => |ty| @as(i64, @intCast(ty.toType().abiSize(mod))), + .u64 => |x| @intCast(x), + .lazy_align => |ty| @intCast(ty.toType().abiAlignment(mod).toByteUnits(0)), + .lazy_size => |ty| @intCast(ty.toType().abiSize(mod)), }, else => unreachable, }, @@ -612,10 +612,11 @@ pub const Value = struct { const target = mod.getTarget(); const endian = target.cpu.arch.endian(); if (val.isUndef(mod)) { - const size = @as(usize, @intCast(ty.abiSize(mod))); + const size: usize = @intCast(ty.abiSize(mod)); @memset(buffer[0..size], 0xaa); return; } + const ip = &mod.intern_pool; switch (ty.zigTypeTag(mod)) { .Void => {}, .Bool => { @@ -656,40 +657,44 @@ pub const Value = struct { const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); }, - .Struct => switch (ty.containerLayout(mod)) { - .Auto => return error.IllDefinedMemoryLayout, - .Extern => for (ty.structFields(mod).values(), 0..) |field, i| { - const off = @as(usize, @intCast(ty.structFieldOffset(i, mod))); - const field_val = switch (val.ip_index) { - .none => switch (val.tag()) { - .bytes => { - buffer[off] = val.castTag(.bytes).?.data[i]; - continue; - }, - .aggregate => val.castTag(.aggregate).?.data[i], - .repeated => val.castTag(.repeated).?.data, - else => unreachable, - }, - else => switch (mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage) { - .bytes => |bytes| { - buffer[off] = bytes[i]; - continue; + .Struct => { + const struct_type = mod.typeToStruct(ty) orelse return error.IllDefinedMemoryLayout; + switch (struct_type.layout) { + .Auto => return error.IllDefinedMemoryLayout, + .Extern => for (0..struct_type.field_types.len) |i| { + const off: usize = @intCast(ty.structFieldOffset(i, mod)); + const field_val = switch (val.ip_index) { + .none => switch (val.tag()) { + .bytes => { + buffer[off] = val.castTag(.bytes).?.data[i]; + continue; + }, + .aggregate => val.castTag(.aggregate).?.data[i], + .repeated => val.castTag(.repeated).?.data, + else => unreachable, }, - .elems => |elems| elems[i], - .repeated_elem => |elem| elem, - }.toValue(), - }; - try writeToMemory(field_val, field.ty, mod, buffer[off..]); - }, - .Packed => { - const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; - return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); - }, + else => switch (ip.indexToKey(val.toIntern()).aggregate.storage) { + .bytes => |bytes| { + buffer[off] = bytes[i]; + continue; + }, + .elems => |elems| elems[i], + .repeated_elem => |elem| elem, + }.toValue(), + }; + const field_ty = struct_type.field_types.get(ip)[i].toType(); + try writeToMemory(field_val, field_ty, mod, buffer[off..]); + }, + .Packed => { + const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; + return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); + }, + } }, .ErrorSet => { // TODO revisit this when we have the concept of the error tag type const Int = u16; - const name = switch (mod.intern_pool.indexToKey(val.toIntern())) { + const name = switch (ip.indexToKey(val.toIntern())) { .err => |err| err.name, .error_union => |error_union| error_union.val.err_name, else => unreachable, @@ -790,24 +795,24 @@ pub const Value = struct { bits += elem_bit_size; } }, - .Struct => switch (ty.containerLayout(mod)) { - .Auto => unreachable, // Sema is supposed to have emitted a compile error already - .Extern => unreachable, // Handled in non-packed writeToMemory - .Packed => { - var bits: u16 = 0; - const fields = ty.structFields(mod).values(); - const storage = ip.indexToKey(val.toIntern()).aggregate.storage; - for (fields, 0..) |field, i| { - const field_bits = @as(u16, @intCast(field.ty.bitSize(mod))); - const field_val = switch (storage) { - .bytes => unreachable, - .elems => |elems| elems[i], - .repeated_elem => |elem| elem, - }; - try field_val.toValue().writeToPackedMemory(field.ty, mod, buffer, bit_offset + bits); - bits += field_bits; - } - }, + .Struct => { + const struct_type = ip.indexToKey(ty.toIntern()).struct_type; + // Sema is supposed to have emitted a compile error already in the case of Auto, + // and Extern is handled in non-packed writeToMemory. + assert(struct_type.layout == .Packed); + var bits: u16 = 0; + const storage = ip.indexToKey(val.toIntern()).aggregate.storage; + for (0..struct_type.field_types.len) |i| { + const field_ty = struct_type.field_types.get(ip)[i].toType(); + const field_bits: u16 = @intCast(field_ty.bitSize(mod)); + const field_val = switch (storage) { + .bytes => unreachable, + .elems => |elems| elems[i], + .repeated_elem => |elem| elem, + }; + try field_val.toValue().writeToPackedMemory(field_ty, mod, buffer, bit_offset + bits); + bits += field_bits; + } }, .Union => { const union_obj = mod.typeToUnion(ty).?; @@ -852,6 +857,7 @@ pub const Value = struct { buffer: []const u8, arena: Allocator, ) Allocator.Error!Value { + const ip = &mod.intern_pool; const target = mod.getTarget(); const endian = target.cpu.arch.endian(); switch (ty.zigTypeTag(mod)) { @@ -926,25 +932,29 @@ pub const Value = struct { const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena); }, - .Struct => switch (ty.containerLayout(mod)) { - .Auto => unreachable, // Sema is supposed to have emitted a compile error already - .Extern => { - const fields = ty.structFields(mod).values(); - const field_vals = try arena.alloc(InternPool.Index, fields.len); - for (field_vals, fields, 0..) |*field_val, field, i| { - const off = @as(usize, @intCast(ty.structFieldOffset(i, mod))); - const sz = @as(usize, @intCast(field.ty.abiSize(mod))); - field_val.* = try (try readFromMemory(field.ty, mod, buffer[off..(off + sz)], arena)).intern(field.ty, mod); - } - return (try mod.intern(.{ .aggregate = .{ - .ty = ty.toIntern(), - .storage = .{ .elems = field_vals }, - } })).toValue(); - }, - .Packed => { - const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; - return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena); - }, + .Struct => { + const struct_type = mod.typeToStruct(ty).?; + switch (struct_type.layout) { + .Auto => unreachable, // Sema is supposed to have emitted a compile error already + .Extern => { + const field_types = struct_type.field_types; + const field_vals = try arena.alloc(InternPool.Index, field_types.len); + for (field_vals, 0..) |*field_val, i| { + const field_ty = field_types.get(ip)[i].toType(); + const off: usize = @intCast(ty.structFieldOffset(i, mod)); + const sz: usize = @intCast(field_ty.abiSize(mod)); + field_val.* = try (try readFromMemory(field_ty, mod, buffer[off..(off + sz)], arena)).intern(field_ty, mod); + } + return (try mod.intern(.{ .aggregate = .{ + .ty = ty.toIntern(), + .storage = .{ .elems = field_vals }, + } })).toValue(); + }, + .Packed => { + const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; + return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena); + }, + } }, .ErrorSet => { // TODO revisit this when we have the concept of the error tag type @@ -992,6 +1002,7 @@ pub const Value = struct { bit_offset: usize, arena: Allocator, ) Allocator.Error!Value { + const ip = &mod.intern_pool; const target = mod.getTarget(); const endian = target.cpu.arch.endian(); switch (ty.zigTypeTag(mod)) { @@ -1070,23 +1081,22 @@ pub const Value = struct { .storage = .{ .elems = elems }, } })).toValue(); }, - .Struct => switch (ty.containerLayout(mod)) { - .Auto => unreachable, // Sema is supposed to have emitted a compile error already - .Extern => unreachable, // Handled by non-packed readFromMemory - .Packed => { - var bits: u16 = 0; - const fields = ty.structFields(mod).values(); - const field_vals = try arena.alloc(InternPool.Index, fields.len); - for (fields, 0..) |field, i| { - const field_bits = @as(u16, @intCast(field.ty.bitSize(mod))); - field_vals[i] = try (try readFromPackedMemory(field.ty, mod, buffer, bit_offset + bits, arena)).intern(field.ty, mod); - bits += field_bits; - } - return (try mod.intern(.{ .aggregate = .{ - .ty = ty.toIntern(), - .storage = .{ .elems = field_vals }, - } })).toValue(); - }, + .Struct => { + // Sema is supposed to have emitted a compile error already for Auto layout structs, + // and Extern is handled by non-packed readFromMemory. + const struct_type = mod.typeToPackedStruct(ty).?; + var bits: u16 = 0; + const field_vals = try arena.alloc(InternPool.Index, struct_type.field_types.len); + for (field_vals, 0..) |*field_val, i| { + const field_ty = struct_type.field_types.get(ip)[i].toType(); + const field_bits: u16 = @intCast(field_ty.bitSize(mod)); + field_val.* = try (try readFromPackedMemory(field_ty, mod, buffer, bit_offset + bits, arena)).intern(field_ty, mod); + bits += field_bits; + } + return (try mod.intern(.{ .aggregate = .{ + .ty = ty.toIntern(), + .storage = .{ .elems = field_vals }, + } })).toValue(); }, .Pointer => { assert(!ty.isSlice(mod)); // No well defined layout. @@ -1105,18 +1115,18 @@ pub const Value = struct { pub fn toFloat(val: Value, comptime T: type, mod: *Module) T { return switch (mod.intern_pool.indexToKey(val.toIntern())) { .int => |int| switch (int.storage) { - .big_int => |big_int| @as(T, @floatCast(bigIntToFloat(big_int.limbs, big_int.positive))), + .big_int => |big_int| @floatCast(bigIntToFloat(big_int.limbs, big_int.positive)), inline .u64, .i64 => |x| { if (T == f80) { @panic("TODO we can't lower this properly on non-x86 llvm backend yet"); } - return @as(T, @floatFromInt(x)); + return @floatFromInt(x); }, - .lazy_align => |ty| @as(T, @floatFromInt(ty.toType().abiAlignment(mod))), - .lazy_size => |ty| @as(T, @floatFromInt(ty.toType().abiSize(mod))), + .lazy_align => |ty| @floatFromInt(ty.toType().abiAlignment(mod).toByteUnits(0)), + .lazy_size => |ty| @floatFromInt(ty.toType().abiSize(mod)), }, .float => |float| switch (float.storage) { - inline else => |x| @as(T, @floatCast(x)), + inline else => |x| @floatCast(x), }, else => unreachable, }; @@ -1875,9 +1885,9 @@ pub const Value = struct { }, inline .u64, .i64 => |x| floatFromIntInner(x, float_ty, mod), .lazy_align => |ty| if (opt_sema) |sema| { - return floatFromIntInner((try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod); + return floatFromIntInner((try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar.toByteUnits(0), float_ty, mod); } else { - return floatFromIntInner(ty.toType().abiAlignment(mod), float_ty, mod); + return floatFromIntInner(ty.toType().abiAlignment(mod).toByteUnits(0), float_ty, mod); }, .lazy_size => |ty| if (opt_sema) |sema| { return floatFromIntInner((try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod); @@ -1892,11 +1902,11 @@ pub const Value = struct { fn floatFromIntInner(x: anytype, dest_ty: Type, mod: *Module) !Value { const target = mod.getTarget(); const storage: InternPool.Key.Float.Storage = switch (dest_ty.floatBits(target)) { - 16 => .{ .f16 = @as(f16, @floatFromInt(x)) }, - 32 => .{ .f32 = @as(f32, @floatFromInt(x)) }, - 64 => .{ .f64 = @as(f64, @floatFromInt(x)) }, - 80 => .{ .f80 = @as(f80, @floatFromInt(x)) }, - 128 => .{ .f128 = @as(f128, @floatFromInt(x)) }, + 16 => .{ .f16 = @floatFromInt(x) }, + 32 => .{ .f32 = @floatFromInt(x) }, + 64 => .{ .f64 = @floatFromInt(x) }, + 80 => .{ .f80 = @floatFromInt(x) }, + 128 => .{ .f128 = @floatFromInt(x) }, else => unreachable, }; return (try mod.intern(.{ .float = .{ |
