Commit 999777e73a

Alex Rønne Petersen <alex@alexrp.com>
2025-05-20 02:44:52
compiler: Scaffold stage2_powerpc backend.
Nothing interesting here; literally just the bare minimum so I can work on this on and off in a branch without worrying about merge conflicts in the non-backend code.
1 parent d000e53
lib/compiler/test_runner.zig
@@ -15,7 +15,9 @@ var fba_buffer: [8192]u8 = undefined;
 var fba = std.heap.FixedBufferAllocator.init(&fba_buffer);
 
 const crippled = switch (builtin.zig_backend) {
-    .stage2_riscv64 => true,
+    .stage2_powerpc,
+    .stage2_riscv64,
+    => true,
     else => false,
 };
 
lib/std/os/linux.zig
@@ -505,7 +505,12 @@ pub var elf_aux_maybe: ?[*]std.elf.Auxv = null;
 /// Whether an external or internal getauxval implementation is used.
 const extern_getauxval = switch (builtin.zig_backend) {
     // Calling extern functions is not yet supported with these backends
-    .stage2_aarch64, .stage2_arm, .stage2_riscv64, .stage2_sparc64 => false,
+    .stage2_aarch64,
+    .stage2_arm,
+    .stage2_powerpc,
+    .stage2_riscv64,
+    .stage2_sparc64,
+    => false,
     else => !builtin.link_libc,
 };
 
lib/std/builtin.zig
@@ -1110,6 +1110,9 @@ pub const CompilerBackend = enum(u64) {
     /// The reference implementation self-hosted compiler of Zig, using the
     /// spirv backend.
     stage2_spirv64 = 11,
+    /// The reference implementation self-hosted compiler of Zig, using the
+    /// powerpc backend.
+    stage2_powerpc = 12,
 
     _,
 };
@@ -1143,10 +1146,12 @@ pub const panic: type = p: {
     if (@hasDecl(root, "Panic")) {
         break :p root.Panic; // Deprecated; use `panic` instead.
     }
-    if (builtin.zig_backend == .stage2_riscv64) {
-        break :p std.debug.simple_panic;
-    }
-    break :p std.debug.FullPanic(std.debug.defaultPanic);
+    break :p switch (builtin.zig_backend) {
+        .stage2_powerpc,
+        .stage2_riscv64,
+        => std.debug.simple_panic,
+        else => std.debug.FullPanic(std.debug.defaultPanic),
+    };
 };
 
 pub noinline fn returnError() void {
lib/std/debug.zig
@@ -608,15 +608,20 @@ pub fn defaultPanic(
 
     // For backends that cannot handle the language features depended on by the
     // default panic handler, we have a simpler panic handler:
-    if (builtin.zig_backend == .stage2_wasm or
-        builtin.zig_backend == .stage2_arm or
-        builtin.zig_backend == .stage2_aarch64 or
-        builtin.zig_backend == .stage2_x86 or
-        (builtin.zig_backend == .stage2_x86_64 and (builtin.target.ofmt != .elf and builtin.target.ofmt != .macho)) or
-        builtin.zig_backend == .stage2_sparc64 or
-        builtin.zig_backend == .stage2_spirv64)
-    {
-        @trap();
+    switch (builtin.zig_backend) {
+        .stage2_aarch64,
+        .stage2_arm,
+        .stage2_powerpc,
+        .stage2_riscv64,
+        .stage2_spirv64,
+        .stage2_wasm,
+        .stage2_x86,
+        => @trap(),
+        .stage2_x86_64 => switch (builtin.target.ofmt) {
+            .elf, .macho => {},
+            else => @trap(),
+        },
+        else => {},
     }
 
     switch (builtin.os.tag) {
lib/std/mem.zig
@@ -675,10 +675,12 @@ test lessThan {
 }
 
 const eqlBytes_allowed = switch (builtin.zig_backend) {
+    // These backends don't support vectors yet.
+    .stage2_powerpc,
+    .stage2_riscv64,
+    => false,
     // The SPIR-V backend does not support the optimized path yet.
     .stage2_spirv64 => false,
-    // The RISC-V does not support vectors.
-    .stage2_riscv64 => false,
     // The naive memory comparison implementation is more useful for fuzzers to
     // find interesting inputs.
     else => !builtin.fuzz,
lib/std/start.zig
@@ -14,12 +14,16 @@ const start_sym_name = if (native_arch.isMIPS()) "__start" else "_start";
 // The self-hosted compiler is not fully capable of handling all of this start.zig file.
 // Until then, we have simplified logic here for self-hosted. TODO remove this once
 // self-hosted is capable enough to handle all of the real start.zig logic.
-pub const simplified_logic =
-    builtin.zig_backend == .stage2_x86 or
-    builtin.zig_backend == .stage2_aarch64 or
-    builtin.zig_backend == .stage2_arm or
-    builtin.zig_backend == .stage2_sparc64 or
-    builtin.zig_backend == .stage2_spirv64;
+pub const simplified_logic = switch (builtin.zig_backend) {
+    .stage2_aarch64,
+    .stage2_arm,
+    .stage2_powerpc,
+    .stage2_sparc64,
+    .stage2_spirv64,
+    .stage2_x86,
+    => true,
+    else => false,
+};
 
 comptime {
     // No matter what, we import the root file, so that any export, test, comptime
@@ -669,9 +673,14 @@ pub inline fn callMain() u8 {
             if (@typeInfo(ReturnType) != .error_union) @compileError(bad_main_ret);
 
             const result = root.main() catch |err| {
-                if (builtin.zig_backend == .stage2_riscv64) {
-                    std.debug.print("error: failed with error\n", .{});
-                    return 1;
+                switch (builtin.zig_backend) {
+                    .stage2_powerpc,
+                    .stage2_riscv64,
+                    => {
+                        std.debug.print("error: failed with error\n", .{});
+                        return 1;
+                    },
+                    else => {},
                 }
                 std.log.err("{s}", .{@errorName(err)});
                 if (@errorReturnTrace()) |trace| {
lib/std/testing.zig
@@ -32,7 +32,13 @@ pub var allocator_instance: std.heap.GeneralPurposeAllocator(.{
 pub var log_level = std.log.Level.warn;
 
 // Disable printing in tests for simple backends.
-pub const backend_can_print = !(builtin.zig_backend == .stage2_spirv64 or builtin.zig_backend == .stage2_riscv64);
+pub const backend_can_print = switch (builtin.zig_backend) {
+    .stage2_powerpc,
+    .stage2_riscv64,
+    .stage2_spirv64,
+    => false,
+    else => true,
+};
 
 fn print(comptime fmt: []const u8, args: anytype) void {
     if (@inComptime()) {
lib/ubsan_rt.zig
@@ -671,7 +671,9 @@ fn exportHandlerWithAbort(
 }
 
 const can_build_ubsan = switch (builtin.zig_backend) {
-    .stage2_riscv64 => false,
+    .stage2_powerpc,
+    .stage2_riscv64,
+    => false,
     else => true,
 };
 
src/arch/powerpc/CodeGen.zig
@@ -0,0 +1,52 @@
+const builtin = @import("builtin");
+const std = @import("std");
+
+const Air = @import("../../Air.zig");
+const codegen = @import("../../codegen.zig");
+const InternPool = @import("../../InternPool.zig");
+const link = @import("../../link.zig");
+const Liveness = @import("../../Liveness.zig");
+const Zcu = @import("../../Zcu.zig");
+
+const assert = std.debug.assert;
+const log = std.log.scoped(.codegen);
+
+pub fn generate(
+    bin_file: *link.File,
+    pt: Zcu.PerThread,
+    src_loc: Zcu.LazySrcLoc,
+    func_index: InternPool.Index,
+    air: Air,
+    liveness: Liveness,
+    code: *std.ArrayListUnmanaged(u8),
+    debug_output: link.File.DebugInfoOutput,
+) codegen.CodeGenError!void {
+    _ = bin_file;
+    _ = pt;
+    _ = src_loc;
+    _ = func_index;
+    _ = air;
+    _ = liveness;
+    _ = code;
+    _ = debug_output;
+
+    unreachable;
+}
+
+pub fn generateLazy(
+    bin_file: *link.File,
+    pt: Zcu.PerThread,
+    src_loc: Zcu.LazySrcLoc,
+    lazy_sym: link.File.LazySymbol,
+    code: *std.ArrayListUnmanaged(u8),
+    debug_output: link.File.DebugInfoOutput,
+) codegen.CodeGenError!void {
+    _ = bin_file;
+    _ = pt;
+    _ = src_loc;
+    _ = lazy_sym;
+    _ = code;
+    _ = debug_output;
+
+    unreachable;
+}
src/codegen.zig
@@ -37,6 +37,7 @@ fn importBackend(comptime backend: std.builtin.CompilerBackend) type {
     return switch (backend) {
         .stage2_aarch64 => @import("arch/aarch64/CodeGen.zig"),
         .stage2_arm => @import("arch/arm/CodeGen.zig"),
+        .stage2_powerpc => @import("arch/powerpc/CodeGen.zig"),
         .stage2_riscv64 => @import("arch/riscv64/CodeGen.zig"),
         .stage2_sparc64 => @import("arch/sparc64/CodeGen.zig"),
         .stage2_x86_64 => @import("arch/x86_64/CodeGen.zig"),
@@ -61,6 +62,7 @@ pub fn generateFunction(
         else => unreachable,
         inline .stage2_aarch64,
         .stage2_arm,
+        .stage2_powerpc,
         .stage2_riscv64,
         .stage2_sparc64,
         .stage2_x86_64,
@@ -86,7 +88,10 @@ pub fn generateLazyFunction(
         zcu.getTarget();
     switch (target_util.zigBackend(target, false)) {
         else => unreachable,
-        inline .stage2_x86_64, .stage2_riscv64 => |backend| {
+        inline .stage2_powerpc,
+        .stage2_riscv64,
+        .stage2_x86_64,
+        => |backend| {
             dev.check(devFeatureForBackend(backend));
             return importBackend(backend).generateLazy(lf, pt, src_loc, lazy_sym, code, debug_output);
         },
src/dev.zig
@@ -26,6 +26,10 @@ pub const Env = enum {
     /// - `zig build-* -fincremental -fno-llvm -fno-lld -target x86_64-linux --listen=-`
     @"x86_64-linux",
 
+    /// - sema
+    /// - `zig build-* -fincremental -fno-llvm -fno-lld -target powerpc(64)(le)-linux --listen=-`
+    @"powerpc-linux",
+
     /// - sema
     /// - `zig build-* -fno-llvm -fno-lld -target riscv64-linux`
     @"riscv64-linux",
@@ -70,6 +74,7 @@ pub const Env = enum {
                 .x86_64_backend,
                 .aarch64_backend,
                 .x86_backend,
+                .powerpc_backend,
                 .riscv64_backend,
                 .sparc64_backend,
                 .spirv64_backend,
@@ -144,6 +149,15 @@ pub const Env = enum {
                 => true,
                 else => Env.sema.supports(feature),
             },
+            .@"powerpc-linux" => switch (feature) {
+                .build_command,
+                .stdio_listen,
+                .incremental,
+                .x86_64_backend,
+                .elf_linker,
+                => true,
+                else => Env.sema.supports(feature),
+            },
             .@"riscv64-linux" => switch (feature) {
                 .riscv64_backend,
                 .elf_linker,
@@ -216,6 +230,7 @@ pub const Feature = enum {
     x86_64_backend,
     aarch64_backend,
     x86_backend,
+    powerpc_backend,
     riscv64_backend,
     sparc64_backend,
     spirv64_backend,
src/target.zig
@@ -736,6 +736,7 @@ pub fn supportsTailCall(target: std.Target, backend: std.builtin.CompilerBackend
 
 pub fn supportsThreads(target: std.Target, backend: std.builtin.CompilerBackend) bool {
     return switch (backend) {
+        .stage2_powerpc => true,
         .stage2_x86_64 => target.ofmt == .macho or target.ofmt == .elf,
         else => true,
     };
@@ -796,14 +797,15 @@ pub fn zigBackend(target: std.Target, use_llvm: bool) std.builtin.CompilerBacken
     if (use_llvm) return .stage2_llvm;
     if (target.ofmt == .c) return .stage2_c;
     return switch (target.cpu.arch) {
-        .wasm32, .wasm64 => .stage2_wasm,
-        .arm, .armeb, .thumb, .thumbeb => .stage2_arm,
-        .x86_64 => .stage2_x86_64,
-        .x86 => .stage2_x86,
         .aarch64, .aarch64_be => .stage2_aarch64,
+        .arm, .armeb, .thumb, .thumbeb => .stage2_arm,
+        .powerpc, .powerpcle, .powerpc64, .powerpc64le => .stage2_powerpc,
         .riscv64 => .stage2_riscv64,
         .sparc64 => .stage2_sparc64,
         .spirv64 => .stage2_spirv64,
+        .wasm32, .wasm64 => .stage2_wasm,
+        .x86 => .stage2_x86,
+        .x86_64 => .stage2_x86_64,
         else => .other,
     };
 }
src/Zcu.zig
@@ -4500,6 +4500,26 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu
             .naked => true,
             else => false,
         },
+        .stage2_powerpc => switch (target.cpu.arch) {
+            .powerpc, .powerpcle => switch (cc) {
+                .powerpc_sysv,
+                .powerpc_sysv_altivec,
+                .powerpc_aix,
+                .powerpc_aix_altivec,
+                .naked,
+                => true,
+                else => false,
+            },
+            .powerpc64, .powerpc64le => switch (cc) {
+                .powerpc64_elf,
+                .powerpc64_elf_altivec,
+                .powerpc64_elf_v2,
+                .naked,
+                => true,
+                else => false,
+            },
+            else => unreachable,
+        },
         .stage2_riscv64 => switch (cc) {
             .riscv64_lp64 => |opts| opts.incoming_stack_alignment == null,
             .naked => true,
test/cases/compile_errors/@import_zon_bad_type.zig
@@ -117,9 +117,9 @@ export fn testMutablePointer() void {
 // tmp.zig:37:38: note: imported here
 // neg_inf.zon:1:1: error: expected type '?u8'
 // tmp.zig:57:28: note: imported here
-// neg_inf.zon:1:1: error: expected type 'tmp.testNonExhaustiveEnum__enum_496'
+// neg_inf.zon:1:1: error: expected type 'tmp.testNonExhaustiveEnum__enum_499'
 // tmp.zig:62:39: note: imported here
-// neg_inf.zon:1:1: error: expected type 'tmp.testUntaggedUnion__union_498'
+// neg_inf.zon:1:1: error: expected type 'tmp.testUntaggedUnion__union_501'
 // tmp.zig:67:44: note: imported here
-// neg_inf.zon:1:1: error: expected type 'tmp.testTaggedUnionVoid__union_501'
+// neg_inf.zon:1:1: error: expected type 'tmp.testTaggedUnionVoid__union_504'
 // tmp.zig:72:50: note: imported here
test/cases/compile_errors/anytype_param_requires_comptime.zig
@@ -15,6 +15,6 @@ pub export fn entry() void {
 // error
 //
 // :7:25: error: unable to resolve comptime value
-// :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_470.C' must be comptime-known
+// :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_473.C' must be comptime-known
 // :4:16: note: struct requires comptime because of this field
 // :4:16: note: types are not available at runtime
test/cases/compile_errors/bogus_method_call_on_slice.zig
@@ -16,5 +16,5 @@ pub export fn entry2() void {
 //
 // :3:6: error: no field or member function named 'copy' in '[]const u8'
 // :9:8: error: no field or member function named 'bar' in '@TypeOf(.{})'
-// :12:18: error: no field or member function named 'bar' in 'tmp.entry2__struct_474'
+// :12:18: error: no field or member function named 'bar' in 'tmp.entry2__struct_477'
 // :12:6: note: struct declared here
test/cases/compile_errors/coerce_anon_struct.zig
@@ -6,6 +6,6 @@ export fn foo() void {
 
 // error
 //
-// :4:16: error: expected type 'tmp.T', found 'tmp.foo__struct_463'
+// :4:16: error: expected type 'tmp.T', found 'tmp.foo__struct_466'
 // :3:16: note: struct declared here
 // :1:11: note: struct declared here
test/cases/compile_errors/redundant_try.zig
@@ -44,9 +44,9 @@ comptime {
 //
 // :5:23: error: expected error union type, found 'comptime_int'
 // :10:23: error: expected error union type, found '@TypeOf(.{})'
-// :15:23: error: expected error union type, found 'tmp.test2__struct_500'
+// :15:23: error: expected error union type, found 'tmp.test2__struct_503'
 // :15:23: note: struct declared here
-// :20:27: error: expected error union type, found 'tmp.test3__struct_502'
+// :20:27: error: expected error union type, found 'tmp.test3__struct_505'
 // :20:27: note: struct declared here
 // :25:23: error: expected error union type, found 'struct { comptime *const [5:0]u8 = "hello" }'
 // :31:13: error: expected error union type, found 'u32'
CMakeLists.txt
@@ -543,6 +543,7 @@ set(ZIG_STAGE2_SOURCES
     src/arch/arm/Mir.zig
     src/arch/arm/abi.zig
     src/arch/arm/bits.zig
+    src/arch/powerpc/CodeGen.zig
     src/arch/riscv64/abi.zig
     src/arch/riscv64/bits.zig
     src/arch/riscv64/CodeGen.zig