diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 44b86af985..d8dbbfb068 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -694,6 +694,61 @@ pub const ExternOptions = struct { is_thread_local: bool = false, }; +/// This enum is set by the compiler and communicates which compiler backend is +/// used to produce machine code. +/// Think carefully before deciding to observe this value. Nearly all code should +/// be agnostic to the backend that implements the language. The use case +/// to use this value is to **work around problems with compiler implementations.** +/// +/// Avoid failing the compilation if the compiler backend does not match a +/// whitelist of backends; rather one should detect that a known problem would +/// occur in a blacklist of backends. +/// +/// The enum is nonexhaustive so that alternate Zig language implementations may +/// choose a number as their tag (please use a random number generator rather +/// than a "cute" number) and codebases can interact with these values even if +/// this upstream enum does not have a name for the number. Of course, upstream +/// is happy to accept pull requests to add Zig implementations to this enum. +/// +/// This data structure is part of the Zig language specification. +pub const CompilerBackend = enum(u64) { + /// It is allowed for a compiler implementation to not reveal its identity, + /// in which case this value is appropriate. Be cool and make sure your + /// code supports `other` Zig compilers! + other = 0, + /// The original Zig compiler created in 2015 by Andrew Kelley. + /// Implemented in C++. Uses LLVM. + stage1 = 1, + /// The reference implementation self-hosted compiler of Zig, using the + /// LLVM backend. + stage2_llvm = 2, + /// The reference implementation self-hosted compiler of Zig, using the + /// backend that generates C source code. + /// Note that one can observe whether the compilation will output C code + /// directly with `object_format` value rather than the `compiler_backend` value. + stage2_c = 3, + /// The reference implementation self-hosted compiler of Zig, using the + /// WebAssembly backend. + stage2_wasm = 4, + /// The reference implementation self-hosted compiler of Zig, using the + /// arm backend. + stage2_arm = 5, + /// The reference implementation self-hosted compiler of Zig, using the + /// x86_64 backend. + stage2_x86_64 = 6, + /// The reference implementation self-hosted compiler of Zig, using the + /// aarch64 backend. + stage2_aarch64 = 7, + /// The reference implementation self-hosted compiler of Zig, using the + /// x86 backend. + stage2_x86 = 8, + /// The reference implementation self-hosted compiler of Zig, using the + /// riscv64 backend. + stage2_riscv64 = 9, + + _, +}; + /// This function type is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const TestFn = struct { diff --git a/src/Compilation.zig b/src/Compilation.zig index cbb44c1e18..40aabcae36 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -4538,12 +4538,28 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca const stage2_x86_cx16 = target.cpu.arch == .x86_64 and std.Target.x86.featureSetHas(target.cpu.features, .cx16); + const zig_backend: std.builtin.CompilerBackend = blk: { + if (use_stage1) break :blk .stage1; + if (build_options.have_llvm and comp.bin_file.options.use_llvm) break :blk .stage2_llvm; + if (comp.bin_file.options.object_format == .c) break :blk .stage2_c; + break :blk switch (target.cpu.arch) { + .wasm32, .wasm64 => std.builtin.CompilerBackend.stage2_wasm, + .arm, .armeb, .thumb, .thumbeb => .stage2_arm, + .x86_64 => .stage2_x86_64, + .i386 => .stage2_x86, + .aarch64, .aarch64_be, .aarch64_32 => .stage2_aarch64, + .riscv64 => .stage2_riscv64, + else => .other, + }; + }; + @setEvalBranchQuota(4000); try buffer.writer().print( \\const std = @import("std"); \\/// Zig version. When writing code that supports multiple versions of Zig, prefer \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks. \\pub const zig_version = std.SemanticVersion.parse("{s}") catch unreachable; + \\pub const zig_backend = std.builtin.CompilerBackend.{}; \\/// Temporary until self-hosted is feature complete. \\pub const zig_is_stage2 = {}; \\/// Temporary until self-hosted supports the `cpu.arch` value. @@ -4563,6 +4579,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca \\ , .{ build_options.version, + std.zig.fmtId(@tagName(zig_backend)), !use_stage1, std.zig.fmtId(@tagName(target.cpu.arch)), stage2_x86_cx16, diff --git a/test/behavior.zig b/test/behavior.zig index 04c9fc41fa..7d28109fa3 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -7,7 +7,7 @@ test { _ = @import("behavior/bugs/3586.zig"); _ = @import("behavior/slice_sentinel_comptime.zig"); - if (!builtin.zig_is_stage2 or builtin.stage2_arch != .x86_64) { + if (builtin.zig_backend != .stage2_x86_64) { // Tests that pass for stage1, llvm backend, C backend, wasm backend, and arm backend. _ = @import("behavior/bugs/679.zig"); _ = @import("behavior/bugs/4560.zig"); @@ -19,7 +19,7 @@ test { _ = @import("behavior/type_info.zig"); _ = @import("behavior/type.zig"); - if (!builtin.zig_is_stage2 or builtin.stage2_arch != .arm) { + if (builtin.zig_backend != .stage2_arm) { // Tests that pass for stage1, llvm backend, C backend, wasm backend. _ = @import("behavior/basic.zig"); _ = @import("behavior/bitcast.zig"); @@ -57,7 +57,7 @@ test { _ = @import("behavior/void.zig"); _ = @import("behavior/while.zig"); - if (!builtin.zig_is_stage2 or builtin.stage2_arch != .wasm32) { + if (builtin.zig_backend != .stage2_wasm) { // Tests that pass for stage1, llvm backend, C backend _ = @import("behavior/align.zig"); _ = @import("behavior/array.zig"); @@ -67,7 +67,7 @@ test { _ = @import("behavior/optional.zig"); _ = @import("behavior/translate_c_macros.zig"); - if (builtin.object_format != .c) { + if (builtin.zig_backend != .stage2_c) { // Tests that pass for stage1 and the llvm backend. _ = @import("behavior/align_llvm.zig"); _ = @import("behavior/alignof.zig"); @@ -109,7 +109,7 @@ test { _ = @import("behavior/union.zig"); _ = @import("behavior/widening.zig"); - if (builtin.zig_is_stage2) { + if (builtin.zig_backend != .stage1) { // When all comptime_memory.zig tests pass, #9646 can be closed. // _ = @import("behavior/comptime_memory.zig"); _ = @import("behavior/slice_stage2.zig");