diff -ruN a/compiler/rustc_target/src/callconv/powerpc.rs b/compiler/rustc_target/src/callconv/powerpc.rs --- a/compiler/rustc_target/src/callconv/powerpc.rs 2026-07-22 21:59:42.235692385 +0000 +++ b/compiler/rustc_target/src/callconv/powerpc.rs 2026-07-22 22:00:22.773722882 +0000 @@ -1,4 +1,4 @@ -use crate::callconv::{ArgAbi, FnAbi}; +use crate::callconv::{Align, ArgAbi, FnAbi}; use crate::spec::HasTargetSpec; fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { @@ -21,7 +21,15 @@ return; } if arg.layout.is_aggregate() { - arg.make_indirect(); + if cx.target_spec().is_like_darwin { + // The Darwin (PowerOpen-derived) C ABI passes aggregates by value, + // laid out in registers / the parameter save area with 4-byte + // alignment (everything except vectors has 4-byte on-stack + // alignment). Mirrors clang's PPC32_DarwinABIInfo byval handling. + arg.pass_by_stack_offset(Some(Align::from_bytes(4).unwrap())); + } else { + arg.make_indirect(); + } } else { arg.extend_integer_width_to(32); } diff -ruN a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs --- a/compiler/rustc_target/src/spec/base/apple/mod.rs 2026-07-22 21:59:42.232692309 +0000 +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs 2026-07-22 22:00:22.772722856 +0000 @@ -25,6 +25,8 @@ I686, X86_64, X86_64h, + PowerPc, + PowerPc64, } impl Arch { @@ -39,6 +41,8 @@ I686 => "i686", X86_64 => "x86_64", X86_64h => "x86_64h", + PowerPc => "ppc", + PowerPc64 => "ppc64", } } @@ -48,6 +52,8 @@ Arm64 | Arm64e | Arm64_32 => "aarch64", I386 | I686 => "x86", X86_64 | X86_64h => "x86_64", + PowerPc => "powerpc", + PowerPc64 => "powerpc64", }) } @@ -71,6 +77,11 @@ // comments (and disabled features) in `x86_64h_apple_darwin` for // details. It is a higher baseline then `penryn` however. X86_64h => "core-avx2", + // The lowest CPU each OS release runs on: macOS 10.4 (Tiger) + // supports the G4 and up, the 64-bit userspace of 10.5 (Leopard) + // needs a G5. + PowerPc => "g4", + PowerPc64 => "g5", } } @@ -78,6 +89,7 @@ match self { Armv7k | Armv7s => StackProbeType::None, Arm64 | Arm64e | Arm64_32 | I386 | I686 | X86_64 | X86_64h => StackProbeType::Inline, + PowerPc | PowerPc64 => StackProbeType::Inline, } } } @@ -130,6 +142,8 @@ // clang supports omitting frame pointers for the rest, but... don't? Arm64 | Arm64e | Arm64_32 => FramePointer::NonLeaf, I386 | I686 | X86_64 | X86_64h => FramePointer::Always, + // Apple's PowerPC ABI reserves r30 as the frame pointer. + PowerPc | PowerPc64 => FramePointer::Always, }, has_rpath: true, dll_suffix: ".dylib".into(), @@ -311,6 +325,10 @@ pub fn minimum_deployment_target(target: &Target) -> Self { let (major, minor, patch) = match (&*target.os, &*target.arch, &*target.abi) { ("macos", "aarch64", _) => (11, 0, 0), + // PowerPC macOS: 10.4 (Tiger) is the oldest supported release, + // 10.5 (Leopard) the only one with a 64-bit userspace. + ("macos", "powerpc", _) => (10, 4, 0), + ("macos", "powerpc64", _) => (10, 5, 0), ("ios", "aarch64", "macabi") => (14, 0, 0), ("ios", "aarch64", "sim") => (14, 0, 0), ("ios", _, _) if target.llvm_target.starts_with("arm64e") => (14, 0, 0), diff -ruN a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs --- a/compiler/rustc_target/src/spec/mod.rs 2026-07-22 21:59:42.224692106 +0000 +++ b/compiler/rustc_target/src/spec/mod.rs 2026-07-22 22:00:22.772722856 +0000 @@ -2007,6 +2007,8 @@ ("x86_64-apple-darwin", x86_64_apple_darwin), ("x86_64h-apple-darwin", x86_64h_apple_darwin), ("i686-apple-darwin", i686_apple_darwin), + ("powerpc-apple-darwin", powerpc_apple_darwin), + ("powerpc64-apple-darwin", powerpc64_apple_darwin), ("aarch64-unknown-fuchsia", aarch64_unknown_fuchsia), ("riscv64gc-unknown-fuchsia", riscv64gc_unknown_fuchsia), diff -ruN a/compiler/rustc_target/src/spec/targets/powerpc64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/powerpc64_apple_darwin.rs --- a/compiler/rustc_target/src/spec/targets/powerpc64_apple_darwin.rs 1970-01-01 00:00:00.000000000 +0000 +++ b/compiler/rustc_target/src/spec/targets/powerpc64_apple_darwin.rs 2026-07-22 22:05:02.629860947 +0000 @@ -0,0 +1,37 @@ +use rustc_abi::Endian; + +use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::{Target, TargetMetadata, TargetOptions}; + +pub(crate) fn target() -> Target { + let (mut opts, llvm_target, arch) = base("macos", Arch::PowerPc64, TargetAbi::Normal); + opts.max_atomic_width = Some(64); + + Target { + llvm_target, + metadata: TargetMetadata { + description: Some("PowerPC 64-bit macOS (10.5 Leopard)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), + }, + pointer_width: 64, + // Darwin ppc64 uses natural alignment throughout (GCC's + // TARGET_ALIGN_NATURAL on rs6000-darwin -m64; no "power" alignment + // quirks). `Fn32`: Darwin has no function descriptors, function + // pointers are plain 4-byte-aligned code addresses. + // + // NOTE: upstream LLVM is not an ABI reference for Darwin PPC (see + // powerpc_apple_darwin.rs); unpatched LLVM reports + // "E-m:o-Fi64-i64:64-i128:128-n32:64" for this triple (`Fi64` being + // a function-descriptor assumption Darwin never had), and the + // patched LLVM must be brought in line with the string below. + data_layout: "E-m:o-Fn32-i64:64-i128:128-n32:64".into(), + arch, + options: TargetOptions { + endian: Endian::Big, + mcount: "\u{1}mcount".into(), + ..opts + }, + } +} diff -ruN a/compiler/rustc_target/src/spec/targets/powerpc_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/powerpc_apple_darwin.rs --- a/compiler/rustc_target/src/spec/targets/powerpc_apple_darwin.rs 1970-01-01 00:00:00.000000000 +0000 +++ b/compiler/rustc_target/src/spec/targets/powerpc_apple_darwin.rs 2026-07-22 22:05:02.629860947 +0000 @@ -0,0 +1,46 @@ +use rustc_abi::Endian; + +use crate::spec::base::apple::{Arch, TargetAbi, base}; +use crate::spec::{Target, TargetMetadata, TargetOptions}; + +pub(crate) fn target() -> Target { + let (mut opts, llvm_target, arch) = base("macos", Arch::PowerPc, TargetAbi::Normal); + // lwarx/stwcx. only handle word-sized atomics. + opts.max_atomic_width = Some(32); + + Target { + llvm_target, + metadata: TargetMetadata { + description: Some("PowerPC 32-bit macOS (10.4 Tiger - 10.6 Snow Leopard)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), + }, + pointer_width: 32, + // Darwin's "power" alignment, per the GCC rs6000-darwin sources + // (`ADJUST_FIELD_ALIGN`/`darwin_rs6000_special_round_type_align`), + // which are the ABI authority for this platform: i64/f64 are + // naturally aligned as globals/locals ("preferred" alignment 8) but + // only 4-byte aligned inside aggregates unless they are the first + // field, so their ABI alignment is 4. Iain Sandoe's out-of-tree + // clang/LLVM Darwin PPC work encodes the same rule as `i64:32:64`. + // + // NOTE: upstream LLVM has *never* implemented the Darwin PowerPC ABI + // correctly (and later dropped Darwin PPC support altogether), so it + // is not a reference for any of this. rustc does however require this + // string to be byte-identical to the one the LLVM backend reports for + // the triple, so the (necessarily patched) LLVM must have + // PPCTargetMachine::getDataLayoutString emit exactly the string + // below; with unpatched LLVM (which reports + // "E-m:o-p:32:32-Fn32-i64:64-n32") rustc refuses to start, which is + // correct, since repr(C) layout would not match the platform C ABI. + data_layout: "E-m:o-p:32:32-Fn32-i64:32:64-f64:32:64-n32".into(), + arch, + options: TargetOptions { + endian: Endian::Big, + // Darwin ppc profiling calls `mcount` with no leading underscore. + mcount: "\u{1}mcount".into(), + ..opts + }, + } +}