authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-01-16 10:09:41+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-01-16 12:49:48+00:00
logb6abe1dbf7b5ad14ad1b0a011f109694fd5f36a8
tree5dc848161f3765e7af2923d67bc3b1e0eb070a83
parentd00e05f18609921c1a051a637c24e47cfa304243
signature Commit is signed but in an unrecognized format.

compiler: make it easier to apply breaking changes to `std.builtin`

Documentation for this will be on the wiki shortly. Resolves: #21842

6 files changed, 151 insertions(+), 67 deletions(-)

bootstrap.c+1
...@@ -141,6 +141,7 @@ int main(int argc, char **argv) {...@@ -141,6 +141,7 @@ int main(int argc, char **argv) {
141 "pub const skip_non_native = false;\n"141 "pub const skip_non_native = false;\n"
142 "pub const force_gpa = false;\n"142 "pub const force_gpa = false;\n"
143 "pub const dev = .core;\n"143 "pub const dev = .core;\n"
144 "pub const value_interpret_mode = .direct;\n"
144 , zig_version);145 , zig_version);
145 if (written < 100)146 if (written < 100)
146 panic("unable to write to config.zig file");147 panic("unable to write to config.zig file");
build.zig+20
...@@ -9,6 +9,7 @@ const fs = std.fs;...@@ -9,6 +9,7 @@ const fs = std.fs;
9const InstallDirectoryOptions = std.Build.InstallDirectoryOptions;9const InstallDirectoryOptions = std.Build.InstallDirectoryOptions;
10const assert = std.debug.assert;10const assert = std.debug.assert;
11const DevEnv = @import("src/dev.zig").Env;11const DevEnv = @import("src/dev.zig").Env;
12const ValueInterpretMode = enum { direct, by_name };
1213
13const zig_version: std.SemanticVersion = .{ .major = 0, .minor = 14, .patch = 0 };14const zig_version: std.SemanticVersion = .{ .major = 0, .minor = 14, .patch = 0 };
14const stack_size = 46 * 1024 * 1024;15const stack_size = 46 * 1024 * 1024;
...@@ -177,6 +178,7 @@ pub fn build(b: *std.Build) !void {...@@ -177,6 +178,7 @@ pub fn build(b: *std.Build) !void {
177 const strip = b.option(bool, "strip", "Omit debug information");178 const strip = b.option(bool, "strip", "Omit debug information");
178 const valgrind = b.option(bool, "valgrind", "Enable valgrind integration");179 const valgrind = b.option(bool, "valgrind", "Enable valgrind integration");
179 const pie = b.option(bool, "pie", "Produce a Position Independent Executable");180 const pie = b.option(bool, "pie", "Produce a Position Independent Executable");
181 const value_interpret_mode = b.option(ValueInterpretMode, "value-interpret-mode", "How the compiler translates between 'std.builtin' types and its internal datastructures") orelse .direct;
180 const value_tracing = b.option(bool, "value-tracing", "Enable extra state tracking to help troubleshoot bugs in the compiler (using the std.debug.Trace API)") orelse false;182 const value_tracing = b.option(bool, "value-tracing", "Enable extra state tracking to help troubleshoot bugs in the compiler (using the std.debug.Trace API)") orelse false;
181183
182 const mem_leak_frames: u32 = b.option(u32, "mem-leak-frames", "How many stack frames to print when a memory leak occurs. Tests get 2x this amount.") orelse blk: {184 const mem_leak_frames: u32 = b.option(u32, "mem-leak-frames", "How many stack frames to print when a memory leak occurs. Tests get 2x this amount.") orelse blk: {
...@@ -234,6 +236,7 @@ pub fn build(b: *std.Build) !void {...@@ -234,6 +236,7 @@ pub fn build(b: *std.Build) !void {
234 exe_options.addOption(bool, "llvm_has_xtensa", llvm_has_xtensa);236 exe_options.addOption(bool, "llvm_has_xtensa", llvm_has_xtensa);
235 exe_options.addOption(bool, "force_gpa", force_gpa);237 exe_options.addOption(bool, "force_gpa", force_gpa);
236 exe_options.addOption(DevEnv, "dev", b.option(DevEnv, "dev", "Build a compiler with a reduced feature set for development of specific features") orelse if (only_c) .bootstrap else .full);238 exe_options.addOption(DevEnv, "dev", b.option(DevEnv, "dev", "Build a compiler with a reduced feature set for development of specific features") orelse if (only_c) .bootstrap else .full);
239 exe_options.addOption(ValueInterpretMode, "value_interpret_mode", value_interpret_mode);
237240
238 if (link_libc) {241 if (link_libc) {
239 exe.root_module.link_libc = true;242 exe.root_module.link_libc = true;
...@@ -620,6 +623,23 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {...@@ -620,6 +623,23 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
620 exe_options.addOption(bool, "value_tracing", false);623 exe_options.addOption(bool, "value_tracing", false);
621 exe_options.addOption(DevEnv, "dev", .bootstrap);624 exe_options.addOption(DevEnv, "dev", .bootstrap);
622625
626 // zig1 chooses to interpret values by name. The tradeoff is as follows:
627 //
628 // * We lose a small amount of performance. This is essentially irrelevant for zig1.
629 //
630 // * We lose the ability to perform trivial renames on certain `std.builtin` types without
631 // zig1.wasm updates. For instance, we cannot rename an enum from PascalCase fields to
632 // snake_case fields without an update.
633 //
634 // * We gain the ability to add and remove fields to and from `std.builtin` types without
635 // zig1.wasm updates. For instance, we can add a new tag to `CallingConvention` without
636 // an update.
637 //
638 // Because field renames only happen when we apply a breaking change to the language (which
639 // is becoming progressively rarer), but tags may be added to or removed from target-dependent
640 // types over time in response to new targets coming into use, we gain more than we lose here.
641 exe_options.addOption(ValueInterpretMode, "value_interpret_mode", .by_name);
642
623 const run_opt = b.addSystemCommand(&.{643 const run_opt = b.addSystemCommand(&.{
624 "wasm-opt",644 "wasm-opt",
625 "-Oz",645 "-Oz",
src/Sema.zig+29-40
...@@ -2713,8 +2713,18 @@ fn analyzeValueAsCallconv(...@@ -2713,8 +2713,18 @@ fn analyzeValueAsCallconv(
2713 src: LazySrcLoc,2713 src: LazySrcLoc,
2714 unresolved_val: Value,2714 unresolved_val: Value,
2715) !std.builtin.CallingConvention {2715) !std.builtin.CallingConvention {
2716 return interpretBuiltinType(sema, block, src, unresolved_val, std.builtin.CallingConvention);
2717}
2718
2719fn interpretBuiltinType(
2720 sema: *Sema,
2721 block: *Block,
2722 src: LazySrcLoc,
2723 unresolved_val: Value,
2724 comptime T: type,
2725) !T {
2716 const resolved_val = try sema.resolveLazyValue(unresolved_val);2726 const resolved_val = try sema.resolveLazyValue(unresolved_val);
2717 return resolved_val.interpret(std.builtin.CallingConvention, sema.pt) catch |err| switch (err) {2727 return resolved_val.interpret(T, sema.pt) catch |err| switch (err) {
2718 error.OutOfMemory => |e| return e,2728 error.OutOfMemory => |e| return e,
2719 error.UndefinedValue => return sema.failWithUseOfUndef(block, src),2729 error.UndefinedValue => return sema.failWithUseOfUndef(block, src),
2720 error.TypeMismatch => @panic("std.builtin is corrupt"),2730 error.TypeMismatch => @panic("std.builtin is corrupt"),
...@@ -21536,19 +21546,8 @@ fn zirReify(...@@ -21536,19 +21546,8 @@ fn zirReify(
21536 .@"anyframe" => return sema.failWithUseOfAsync(block, src),21546 .@"anyframe" => return sema.failWithUseOfAsync(block, src),
21537 .enum_literal => return .enum_literal_type,21547 .enum_literal => return .enum_literal_type,
21538 .int => {21548 .int => {
21539 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));21549 const int = try sema.interpretBuiltinType(block, operand_src, .fromInterned(union_val.val), std.builtin.Type.Int);
21540 const signedness_val = try Value.fromInterned(union_val.val).fieldValue(21550 const ty = try pt.intType(int.signedness, int.bits);
21541 pt,
21542 struct_type.nameIndex(ip, try ip.getOrPutString(gpa, pt.tid, "signedness", .no_embedded_nulls)).?,
21543 );
21544 const bits_val = try Value.fromInterned(union_val.val).fieldValue(
21545 pt,
21546 struct_type.nameIndex(ip, try ip.getOrPutString(gpa, pt.tid, "bits", .no_embedded_nulls)).?,
21547 );
21548
21549 const signedness = zcu.toEnum(std.builtin.Signedness, signedness_val);
21550 const bits: u16 = @intCast(try bits_val.toUnsignedIntSema(pt));
21551 const ty = try pt.intType(signedness, bits);
21552 return Air.internedToRef(ty.toIntern());21551 return Air.internedToRef(ty.toIntern());
21553 },21552 },
21554 .vector => {21553 .vector => {
...@@ -21574,20 +21573,15 @@ fn zirReify(...@@ -21574,20 +21573,15 @@ fn zirReify(
21574 return Air.internedToRef(ty.toIntern());21573 return Air.internedToRef(ty.toIntern());
21575 },21574 },
21576 .float => {21575 .float => {
21577 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));21576 const float = try sema.interpretBuiltinType(block, operand_src, .fromInterned(union_val.val), std.builtin.Type.Float);
21578 const bits_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
21579 ip,
21580 try ip.getOrPutString(gpa, pt.tid, "bits", .no_embedded_nulls),
21581 ).?);
2158221577
21583 const bits: u16 = @intCast(try bits_val.toUnsignedIntSema(pt));21578 const ty = switch (float.bits) {
21584 const ty = switch (bits) {
21585 16 => Type.f16,21579 16 => Type.f16,
21586 32 => Type.f32,21580 32 => Type.f32,
21587 64 => Type.f64,21581 64 => Type.f64,
21588 80 => Type.f80,21582 80 => Type.f80,
21589 128 => Type.f128,21583 128 => Type.f128,
21590 else => return sema.fail(block, src, "{}-bit float unsupported", .{bits}),21584 else => return sema.fail(block, src, "{}-bit float unsupported", .{float.bits}),
21591 };21585 };
21592 return Air.internedToRef(ty.toIntern());21586 return Air.internedToRef(ty.toIntern());
21593 },21587 },
...@@ -21641,7 +21635,7 @@ fn zirReify(...@@ -21641,7 +21635,7 @@ fn zirReify(
21641 try elem_ty.resolveLayout(pt);21635 try elem_ty.resolveLayout(pt);
21642 }21636 }
2164321637
21644 const ptr_size = zcu.toEnum(std.builtin.Type.Pointer.Size, size_val);21638 const ptr_size = try sema.interpretBuiltinType(block, operand_src, size_val, std.builtin.Type.Pointer.Size);
2164521639
21646 const actual_sentinel: InternPool.Index = s: {21640 const actual_sentinel: InternPool.Index = s: {
21647 if (!sentinel_val.isNull(zcu)) {21641 if (!sentinel_val.isNull(zcu)) {
...@@ -21691,7 +21685,7 @@ fn zirReify(...@@ -21691,7 +21685,7 @@ fn zirReify(
21691 .is_const = is_const_val.toBool(),21685 .is_const = is_const_val.toBool(),
21692 .is_volatile = is_volatile_val.toBool(),21686 .is_volatile = is_volatile_val.toBool(),
21693 .alignment = abi_align,21687 .alignment = abi_align,
21694 .address_space = zcu.toEnum(std.builtin.AddressSpace, address_space_val),21688 .address_space = try sema.interpretBuiltinType(block, operand_src, address_space_val, std.builtin.AddressSpace),
21695 .is_allowzero = is_allowzero_val.toBool(),21689 .is_allowzero = is_allowzero_val.toBool(),
21696 },21690 },
21697 });21691 });
...@@ -21813,7 +21807,7 @@ fn zirReify(...@@ -21813,7 +21807,7 @@ fn zirReify(
21813 try ip.getOrPutString(gpa, pt.tid, "is_tuple", .no_embedded_nulls),21807 try ip.getOrPutString(gpa, pt.tid, "is_tuple", .no_embedded_nulls),
21814 ).?);21808 ).?);
2181521809
21816 const layout = zcu.toEnum(std.builtin.Type.ContainerLayout, layout_val);21810 const layout = try sema.interpretBuiltinType(block, operand_src, layout_val, std.builtin.Type.ContainerLayout);
2181721811
21818 // Decls21812 // Decls
21819 if (try decls_val.sliceLen(pt) > 0) {21813 if (try decls_val.sliceLen(pt) > 0) {
...@@ -21929,7 +21923,7 @@ fn zirReify(...@@ -21929,7 +21923,7 @@ fn zirReify(
21929 if (try decls_val.sliceLen(pt) > 0) {21923 if (try decls_val.sliceLen(pt) > 0) {
21930 return sema.fail(block, src, "reified unions must have no decls", .{});21924 return sema.fail(block, src, "reified unions must have no decls", .{});
21931 }21925 }
21932 const layout = zcu.toEnum(std.builtin.Type.ContainerLayout, layout_val);21926 const layout = try sema.interpretBuiltinType(block, operand_src, layout_val, std.builtin.Type.ContainerLayout);
2193321927
21934 const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ .simple = .union_fields });21928 const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ .simple = .union_fields });
2193521929
...@@ -24456,7 +24450,7 @@ fn resolveExportOptions(...@@ -24456,7 +24450,7 @@ fn resolveExportOptions(
2445624450
24457 const linkage_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "linkage", .no_embedded_nulls), linkage_src);24451 const linkage_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "linkage", .no_embedded_nulls), linkage_src);
24458 const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_operand, .{ .simple = .export_options });24452 const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_operand, .{ .simple = .export_options });
24459 const linkage = zcu.toEnum(std.builtin.GlobalLinkage, linkage_val);24453 const linkage = try sema.interpretBuiltinType(block, linkage_src, linkage_val, std.builtin.GlobalLinkage);
2446024454
24461 const section_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "section", .no_embedded_nulls), section_src);24455 const section_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "section", .no_embedded_nulls), section_src);
24462 const section_opt_val = try sema.resolveConstDefinedValue(block, section_src, section_operand, .{ .simple = .export_options });24456 const section_opt_val = try sema.resolveConstDefinedValue(block, section_src, section_operand, .{ .simple = .export_options });
...@@ -24467,7 +24461,7 @@ fn resolveExportOptions(...@@ -24467,7 +24461,7 @@ fn resolveExportOptions(
2446724461
24468 const visibility_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "visibility", .no_embedded_nulls), visibility_src);24462 const visibility_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "visibility", .no_embedded_nulls), visibility_src);
24469 const visibility_val = try sema.resolveConstDefinedValue(block, visibility_src, visibility_operand, .{ .simple = .export_options });24463 const visibility_val = try sema.resolveConstDefinedValue(block, visibility_src, visibility_operand, .{ .simple = .export_options });
24470 const visibility = zcu.toEnum(std.builtin.SymbolVisibility, visibility_val);24464 const visibility = try sema.interpretBuiltinType(block, visibility_src, visibility_val, std.builtin.SymbolVisibility);
2447124465
24472 if (name.len < 1) {24466 if (name.len < 1) {
24473 return sema.fail(block, name_src, "exported symbol name cannot be empty", .{});24467 return sema.fail(block, name_src, "exported symbol name cannot be empty", .{});
...@@ -24495,12 +24489,11 @@ fn resolveBuiltinEnum(...@@ -24495,12 +24489,11 @@ fn resolveBuiltinEnum(
24495 comptime name: Zcu.BuiltinDecl,24489 comptime name: Zcu.BuiltinDecl,
24496 reason: ComptimeReason,24490 reason: ComptimeReason,
24497) CompileError!@field(std.builtin, @tagName(name)) {24491) CompileError!@field(std.builtin, @tagName(name)) {
24498 const pt = sema.pt;
24499 const ty = try sema.getBuiltinType(src, name);24492 const ty = try sema.getBuiltinType(src, name);
24500 const air_ref = try sema.resolveInst(zir_ref);24493 const air_ref = try sema.resolveInst(zir_ref);
24501 const coerced = try sema.coerce(block, ty, air_ref, src);24494 const coerced = try sema.coerce(block, ty, air_ref, src);
24502 const val = try sema.resolveConstDefinedValue(block, src, coerced, reason);24495 const val = try sema.resolveConstDefinedValue(block, src, coerced, reason);
24503 return pt.zcu.toEnum(@field(std.builtin, @tagName(name)), val);24496 return sema.interpretBuiltinType(block, src, val, @field(std.builtin, @tagName(name)));
24504}24497}
2450524498
24506fn resolveAtomicOrder(24499fn resolveAtomicOrder(
...@@ -25293,7 +25286,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -25293,7 +25286,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
25293 const air_ref = try sema.resolveInst(extra.modifier);25286 const air_ref = try sema.resolveInst(extra.modifier);
25294 const modifier_ref = try sema.coerce(block, modifier_ty, air_ref, modifier_src);25287 const modifier_ref = try sema.coerce(block, modifier_ty, air_ref, modifier_src);
25295 const modifier_val = try sema.resolveConstDefinedValue(block, modifier_src, modifier_ref, .{ .simple = .call_modifier });25288 const modifier_val = try sema.resolveConstDefinedValue(block, modifier_src, modifier_ref, .{ .simple = .call_modifier });
25296 var modifier = zcu.toEnum(std.builtin.CallModifier, modifier_val);25289 var modifier = try sema.interpretBuiltinType(block, modifier_src, modifier_val, std.builtin.CallModifier);
25297 switch (modifier) {25290 switch (modifier) {
25298 // These can be upgraded to comptime or nosuspend calls.25291 // These can be upgraded to comptime or nosuspend calls.
25299 .auto, .never_tail, .no_async => {25292 .auto, .never_tail, .no_async => {
...@@ -26468,9 +26461,9 @@ fn resolvePrefetchOptions(...@@ -26468,9 +26461,9 @@ fn resolvePrefetchOptions(
26468 const cache_val = try sema.resolveConstDefinedValue(block, cache_src, cache, .{ .simple = .prefetch_options });26461 const cache_val = try sema.resolveConstDefinedValue(block, cache_src, cache, .{ .simple = .prefetch_options });
2646926462
26470 return std.builtin.PrefetchOptions{26463 return std.builtin.PrefetchOptions{
26471 .rw = zcu.toEnum(std.builtin.PrefetchOptions.Rw, rw_val),26464 .rw = try sema.interpretBuiltinType(block, rw_src, rw_val, std.builtin.PrefetchOptions.Rw),
26472 .locality = @intCast(try locality_val.toUnsignedIntSema(pt)),26465 .locality = @intCast(try locality_val.toUnsignedIntSema(pt)),
26473 .cache = zcu.toEnum(std.builtin.PrefetchOptions.Cache, cache_val),26466 .cache = try sema.interpretBuiltinType(block, cache_src, cache_val, std.builtin.PrefetchOptions.Cache),
26474 };26467 };
26475}26468}
2647626469
...@@ -26536,7 +26529,7 @@ fn resolveExternOptions(...@@ -26536,7 +26529,7 @@ fn resolveExternOptions(
2653626529
26537 const linkage_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "linkage", .no_embedded_nulls), linkage_src);26530 const linkage_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "linkage", .no_embedded_nulls), linkage_src);
26538 const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_ref, .{ .simple = .extern_options });26531 const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_ref, .{ .simple = .extern_options });
26539 const linkage = zcu.toEnum(std.builtin.GlobalLinkage, linkage_val);26532 const linkage = try sema.interpretBuiltinType(block, linkage_src, linkage_val, std.builtin.GlobalLinkage);
2654026533
26541 const is_thread_local = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "is_thread_local", .no_embedded_nulls), thread_local_src);26534 const is_thread_local = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "is_thread_local", .no_embedded_nulls), thread_local_src);
26542 const is_thread_local_val = try sema.resolveConstDefinedValue(block, thread_local_src, is_thread_local, .{ .simple = .extern_options });26535 const is_thread_local_val = try sema.resolveConstDefinedValue(block, thread_local_src, is_thread_local, .{ .simple = .extern_options });
...@@ -26770,9 +26763,6 @@ fn zirInplaceArithResultTy(sema: *Sema, extended: Zir.Inst.Extended.InstData) Co...@@ -26770,9 +26763,6 @@ fn zirInplaceArithResultTy(sema: *Sema, extended: Zir.Inst.Extended.InstData) Co
26770}26763}
2677126764
26772fn zirBranchHint(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {26765fn zirBranchHint(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
26773 const pt = sema.pt;
26774 const zcu = pt.zcu;
26775
26776 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;26766 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
26777 const uncoerced_hint = try sema.resolveInst(extra.operand);26767 const uncoerced_hint = try sema.resolveInst(extra.operand);
26778 const operand_src = block.builtinCallArgSrc(extra.node, 0);26768 const operand_src = block.builtinCallArgSrc(extra.node, 0);
...@@ -26784,7 +26774,7 @@ fn zirBranchHint(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat...@@ -26784,7 +26774,7 @@ fn zirBranchHint(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
26784 // We only apply the first hint in a branch.26774 // We only apply the first hint in a branch.
26785 // This allows user-provided hints to override implicit cold hints.26775 // This allows user-provided hints to override implicit cold hints.
26786 if (sema.branch_hint == null) {26776 if (sema.branch_hint == null) {
26787 sema.branch_hint = zcu.toEnum(std.builtin.BranchHint, hint_val);26777 sema.branch_hint = try sema.interpretBuiltinType(block, operand_src, hint_val, std.builtin.BranchHint);
26788 }26778 }
26789}26779}
2679026780
...@@ -37136,11 +37126,10 @@ pub fn analyzeAsAddressSpace(...@@ -37136,11 +37126,10 @@ pub fn analyzeAsAddressSpace(
37136 ctx: AddressSpaceContext,37126 ctx: AddressSpaceContext,
37137) !std.builtin.AddressSpace {37127) !std.builtin.AddressSpace {
37138 const pt = sema.pt;37128 const pt = sema.pt;
37139 const zcu = pt.zcu;
37140 const addrspace_ty = try sema.getBuiltinType(src, .AddressSpace);37129 const addrspace_ty = try sema.getBuiltinType(src, .AddressSpace);
37141 const coerced = try sema.coerce(block, addrspace_ty, air_ref, src);37130 const coerced = try sema.coerce(block, addrspace_ty, air_ref, src);
37142 const addrspace_val = try sema.resolveConstDefinedValue(block, src, coerced, .{ .simple = .@"addrspace" });37131 const addrspace_val = try sema.resolveConstDefinedValue(block, src, coerced, .{ .simple = .@"addrspace" });
37143 const address_space = zcu.toEnum(std.builtin.AddressSpace, addrspace_val);37132 const address_space = try sema.interpretBuiltinType(block, src, addrspace_val, std.builtin.AddressSpace);
37144 const target = pt.zcu.getTarget();37133 const target = pt.zcu.getTarget();
37145 const arch = target.cpu.arch;37134 const arch = target.cpu.arch;
3714637135
src/Value.zig+100-23
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const build_options = @import("build_options");
3const Type = @import("Type.zig");4const Type = @import("Type.zig");
4const assert = std.debug.assert;5const assert = std.debug.assert;
5const BigIntConst = std.math.big.int.Const;6const BigIntConst = std.math.big.int.Const;
...@@ -4531,6 +4532,20 @@ pub fn resolveLazy(...@@ -4531,6 +4532,20 @@ pub fn resolveLazy(
4531 }4532 }
4532}4533}
45334534
4535const InterpretMode = enum {
4536 /// In this mode, types are assumed to match what the compiler was built with in terms of field
4537 /// order, field types, etc. This improves compiler performance. However, it means that certain
4538 /// modifications to `std.builtin` will result in compiler crashes.
4539 direct,
4540 /// In this mode, various details of the type are allowed to differ from what the compiler was built
4541 /// with. Fields are matched by name rather than index; added struct fields are ignored, and removed
4542 /// struct fields use their default value if one exists. This is slower than `.direct`, but permits
4543 /// making certain changes to `std.builtin` (in particular reordering/adding/removing fields), so it
4544 /// is useful when applying breaking changes.
4545 by_name,
4546};
4547const interpret_mode: InterpretMode = @field(InterpretMode, @tagName(build_options.value_interpret_mode));
4548
4534/// Given a `Value` representing a comptime-known value of type `T`, unwrap it into an actual `T` known to the compiler.4549/// Given a `Value` representing a comptime-known value of type `T`, unwrap it into an actual `T` known to the compiler.
4535/// This is useful for accessing `std.builtin` structures received from comptime logic.4550/// This is useful for accessing `std.builtin` structures received from comptime logic.
4536/// `val` must be fully resolved.4551/// `val` must be fully resolved.
...@@ -4583,11 +4598,20 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe...@@ -4583,11 +4598,20 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe
4583 else4598 else
4584 null,4599 null,
45854600
4586 .@"enum" => zcu.toEnum(T, val),4601 .@"enum" => switch (interpret_mode) {
4602 .direct => {
4603 const int = val.getUnsignedInt(zcu) orelse return error.TypeMismatch;
4604 return std.meta.intToEnum(T, int) catch error.TypeMismatch;
4605 },
4606 .by_name => {
4607 const field_index = ty.enumTagFieldIndex(val, zcu) orelse return error.TypeMismatch;
4608 const field_name = ty.enumFieldName(field_index, zcu);
4609 return std.meta.stringToEnum(T, field_name.toSlice(ip)) orelse error.TypeMismatch;
4610 },
4611 },
45874612
4588 .@"union" => |@"union"| {4613 .@"union" => |@"union"| {
4589 const union_obj = zcu.typeToUnion(ty) orelse return error.TypeMismatch;4614 // No need to handle `interpret_mode`, because the `.@"enum"` handling already deals with it.
4590 if (union_obj.field_types.len != @"union".fields.len) return error.TypeMismatch;
4591 const tag_val = val.unionTag(zcu) orelse return error.TypeMismatch;4615 const tag_val = val.unionTag(zcu) orelse return error.TypeMismatch;
4592 const tag = try tag_val.interpret(@"union".tag_type.?, pt);4616 const tag = try tag_val.interpret(@"union".tag_type.?, pt);
4593 return switch (tag) {4617 return switch (tag) {
...@@ -4599,14 +4623,31 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe...@@ -4599,14 +4623,31 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe
4599 };4623 };
4600 },4624 },
46014625
4602 .@"struct" => |@"struct"| {4626 .@"struct" => |@"struct"| switch (interpret_mode) {
4603 if (ty.structFieldCount(zcu) != @"struct".fields.len) return error.TypeMismatch;4627 .direct => {
4604 var result: T = undefined;4628 if (ty.structFieldCount(zcu) != @"struct".fields.len) return error.TypeMismatch;
4605 inline for (@"struct".fields, 0..) |field, field_idx| {4629 var result: T = undefined;
4606 const field_val = try val.fieldValue(pt, field_idx);4630 inline for (@"struct".fields, 0..) |field, field_idx| {
4607 @field(result, field.name) = try field_val.interpret(field.type, pt);4631 const field_val = try val.fieldValue(pt, field_idx);
4608 }4632 @field(result, field.name) = try field_val.interpret(field.type, pt);
4609 return result;4633 }
4634 return result;
4635 },
4636 .by_name => {
4637 const struct_obj = zcu.typeToStruct(ty) orelse return error.TypeMismatch;
4638 var result: T = undefined;
4639 inline for (@"struct".fields) |field| {
4640 const field_name_ip = try ip.getOrPutString(zcu.gpa, pt.tid, field.name, .no_embedded_nulls);
4641 @field(result, field.name) = if (struct_obj.nameIndex(ip, field_name_ip)) |field_idx| f: {
4642 const field_val = try val.fieldValue(pt, field_idx);
4643 break :f try field_val.interpret(field.type, pt);
4644 } else if (field.default_value) |ptr| f: {
4645 const typed_ptr: *const field.type = @ptrCast(@alignCast(ptr));
4646 break :f typed_ptr.*;
4647 } else return error.TypeMismatch;
4648 }
4649 return result;
4650 },
4610 },4651 },
4611 };4652 };
4612}4653}
...@@ -4618,6 +4659,7 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory...@@ -4618,6 +4659,7 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory
4618 const T = @TypeOf(val);4659 const T = @TypeOf(val);
46194660
4620 const zcu = pt.zcu;4661 const zcu = pt.zcu;
4662 const ip = &zcu.intern_pool;
4621 if (ty.zigTypeTag(zcu) != @typeInfo(T)) return error.TypeMismatch;4663 if (ty.zigTypeTag(zcu) != @typeInfo(T)) return error.TypeMismatch;
46224664
4623 return switch (@typeInfo(T)) {4665 return switch (@typeInfo(T)) {
...@@ -4657,9 +4699,17 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory...@@ -4657,9 +4699,17 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory
4657 else4699 else
4658 try pt.nullValue(ty),4700 try pt.nullValue(ty),
46594701
4660 .@"enum" => try pt.enumValue(ty, (try uninterpret(@intFromEnum(val), ty.intTagType(zcu), pt)).toIntern()),4702 .@"enum" => switch (interpret_mode) {
4703 .direct => try pt.enumValue(ty, (try uninterpret(@intFromEnum(val), ty.intTagType(zcu), pt)).toIntern()),
4704 .by_name => {
4705 const field_name_ip = try ip.getOrPutString(zcu.gpa, pt.tid, @tagName(val), .no_embedded_nulls);
4706 const field_idx = ty.enumFieldIndex(field_name_ip, zcu) orelse return error.TypeMismatch;
4707 return pt.enumValueFieldIndex(ty, field_idx);
4708 },
4709 },
46614710
4662 .@"union" => |@"union"| {4711 .@"union" => |@"union"| {
4712 // No need to handle `interpret_mode`, because the `.@"enum"` handling already deals with it.
4663 const tag: @"union".tag_type.? = val;4713 const tag: @"union".tag_type.? = val;
4664 const tag_val = try uninterpret(tag, ty.unionTagType(zcu).?, pt);4714 const tag_val = try uninterpret(tag, ty.unionTagType(zcu).?, pt);
4665 const field_ty = ty.unionFieldType(tag_val, zcu) orelse return error.TypeMismatch;4715 const field_ty = ty.unionFieldType(tag_val, zcu) orelse return error.TypeMismatch;
...@@ -4672,17 +4722,44 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory...@@ -4672,17 +4722,44 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory
4672 };4722 };
4673 },4723 },
46744724
4675 .@"struct" => |@"struct"| {4725 .@"struct" => |@"struct"| switch (interpret_mode) {
4676 if (ty.structFieldCount(zcu) != @"struct".fields.len) return error.TypeMismatch;4726 .direct => {
4677 var field_vals: [@"struct".fields.len]InternPool.Index = undefined;4727 if (ty.structFieldCount(zcu) != @"struct".fields.len) return error.TypeMismatch;
4678 inline for (&field_vals, @"struct".fields, 0..) |*field_val, field, field_idx| {4728 var field_vals: [@"struct".fields.len]InternPool.Index = undefined;
4679 const field_ty = ty.fieldType(field_idx, zcu);4729 inline for (&field_vals, @"struct".fields, 0..) |*field_val, field, field_idx| {
4680 field_val.* = (try uninterpret(@field(val, field.name), field_ty, pt)).toIntern();4730 const field_ty = ty.fieldType(field_idx, zcu);
4681 }4731 field_val.* = (try uninterpret(@field(val, field.name), field_ty, pt)).toIntern();
4682 return .fromInterned(try pt.intern(.{ .aggregate = .{4732 }
4683 .ty = ty.toIntern(),4733 return .fromInterned(try pt.intern(.{ .aggregate = .{
4684 .storage = .{ .elems = &field_vals },4734 .ty = ty.toIntern(),
4685 } }));4735 .storage = .{ .elems = &field_vals },
4736 } }));
4737 },
4738 .by_name => {
4739 const struct_obj = zcu.typeToStruct(ty) orelse return error.TypeMismatch;
4740 const want_fields_len = struct_obj.field_types.len;
4741 const field_vals = try zcu.gpa.alloc(InternPool.Index, want_fields_len);
4742 defer zcu.gpa.free(field_vals);
4743 @memset(field_vals, .none);
4744 inline for (@"struct".fields) |field| {
4745 const field_name_ip = try ip.getOrPutString(zcu.gpa, pt.tid, field.name, .no_embedded_nulls);
4746 if (struct_obj.nameIndex(ip, field_name_ip)) |field_idx| {
4747 const field_ty = ty.fieldType(field_idx, zcu);
4748 field_vals[field_idx] = (try uninterpret(@field(val, field.name), field_ty, pt)).toIntern();
4749 }
4750 }
4751 for (field_vals, 0..) |*field_val, field_idx| {
4752 if (field_val.* == .none) {
4753 const default_init = struct_obj.field_inits.get(ip)[field_idx];
4754 if (default_init == .none) return error.TypeMismatch;
4755 field_val.* = default_init;
4756 }
4757 }
4758 return .fromInterned(try pt.intern(.{ .aggregate = .{
4759 .ty = ty.toIntern(),
4760 .storage = .{ .elems = field_vals },
4761 } }));
4762 },
4686 },4763 },
4687 };4764 };
4688}4765}
src/Zcu.zig-4
...@@ -3486,10 +3486,6 @@ pub fn funcInfo(zcu: *const Zcu, func_index: InternPool.Index) InternPool.Key.Fu...@@ -3486,10 +3486,6 @@ pub fn funcInfo(zcu: *const Zcu, func_index: InternPool.Index) InternPool.Key.Fu
3486 return zcu.intern_pool.toFunc(func_index);3486 return zcu.intern_pool.toFunc(func_index);
3487}3487}
34883488
3489pub fn toEnum(zcu: *const Zcu, comptime E: type, val: Value) E {
3490 return zcu.intern_pool.toEnum(E, val.toIntern());
3491}
3492
3493pub const UnionLayout = struct {3489pub const UnionLayout = struct {
3494 abi_size: u64,3490 abi_size: u64,
3495 abi_align: Alignment,3491 abi_align: Alignment,
stage1/config.zig.in+1
...@@ -13,3 +13,4 @@ pub const value_tracing = false;...@@ -13,3 +13,4 @@ pub const value_tracing = false;
13pub const skip_non_native = false;13pub const skip_non_native = false;
14pub const force_gpa = false;14pub const force_gpa = false;
15pub const dev = .core;15pub const dev = .core;
16pub const value_interpret_mode = .direct;