[clang] [llvm] [clang] Support the Swift calling convention on 32-bit PowerPC (PR #205457)
Alsey Coleman Miller via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 23 21:06:57 PDT 2026
https://github.com/colemancda updated https://github.com/llvm/llvm-project/pull/205457
>From 4c89bc9cf9fd019225be748f544adf3c5fbcdd1e Mon Sep 17 00:00:00 2001
From: Alsey Coleman Miller <alseycmiller at gmail.com>
Date: Wed, 24 Jun 2026 00:05:58 -0400
Subject: [PATCH 1/2] [clang] Support the Swift calling convention on 32-bit
PowerPC
---
clang/lib/Basic/Targets/PPC.h | 11 +++++++++++
clang/lib/CodeGen/Targets/PPC.cpp | 16 +++++++++++++++-
llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 7 ++++---
3 files changed, 30 insertions(+), 4 deletions(-)
diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h
index e3bf5072d932d..165de12118eb8 100644
--- a/clang/lib/Basic/Targets/PPC.h
+++ b/clang/lib/Basic/Targets/PPC.h
@@ -433,6 +433,17 @@ class LLVM_LIBRARY_VISIBILITY PPC32TargetInfo : public PPCTargetInfo {
std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
return std::make_pair(32, 32);
}
+
+ CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
+ switch (CC) {
+ case CC_Swift:
+ return CCCR_OK;
+ case CC_SwiftAsync:
+ return CCCR_Error;
+ default:
+ return CCCR_Warning;
+ }
+ }
};
// Note: ABI differences may eventually require us to have a separate
diff --git a/clang/lib/CodeGen/Targets/PPC.cpp b/clang/lib/CodeGen/Targets/PPC.cpp
index ab069bfbd1b51..9024f9934c37e 100644
--- a/clang/lib/CodeGen/Targets/PPC.cpp
+++ b/clang/lib/CodeGen/Targets/PPC.cpp
@@ -382,12 +382,26 @@ class PPC32_SVR4_ABIInfo : public DefaultABIInfo {
AggValueSlot Slot) const override;
};
+/// Swift calling convention ABI for 32-bit PowerPC (SVR4/EABI).
+class PPC32SwiftABIInfo : public SwiftABIInfo {
+public:
+ explicit PPC32SwiftABIInfo(CodeGenTypes &CGT)
+ : SwiftABIInfo(CGT, /*SwiftErrorInRegister=*/false) {}
+
+ bool shouldPassIndirectly(ArrayRef<llvm::Type *> ComponentTys,
+ bool AsReturnValue) const override {
+ return occupiesMoreThan(ComponentTys, /*total=*/4);
+ }
+};
+
class PPC32TargetCodeGenInfo : public TargetCodeGenInfo {
public:
PPC32TargetCodeGenInfo(CodeGenTypes &CGT, bool SoftFloatABI,
bool RetSmallStructInRegABI)
: TargetCodeGenInfo(std::make_unique<PPC32_SVR4_ABIInfo>(
- CGT, SoftFloatABI, RetSmallStructInRegABI)) {}
+ CGT, SoftFloatABI, RetSmallStructInRegABI)) {
+ SwiftInfo = std::make_unique<PPC32SwiftABIInfo>(CGT);
+ }
static bool isStructReturnInRegABI(const llvm::Triple &Triple,
const CodeGenOptions &Opts);
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index 76cc06f2b4ed9..1c30846a3182c 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -5978,9 +5978,10 @@ SDValue PPCTargetLowering::LowerCall_32SVR4(
const bool IsVarArg = CFlags.IsVarArg;
const bool IsTailCall = CFlags.IsTailCall;
- assert((CallConv == CallingConv::C ||
- CallConv == CallingConv::Cold ||
- CallConv == CallingConv::Fast) && "Unknown calling convention!");
+ assert((CallConv == CallingConv::C || CallConv == CallingConv::Cold ||
+ CallConv == CallingConv::Fast || CallConv == CallingConv::Swift ||
+ CallConv == CallingConv::SwiftTail) &&
+ "Unknown calling convention!");
const Align PtrAlign(4);
>From a57a711abeb99d67fc6ee4a31b0be34e0758f2fa Mon Sep 17 00:00:00 2001
From: Alsey Coleman Miller <alseycmiller at gmail.com>
Date: Wed, 24 Jun 2026 00:06:42 -0400
Subject: [PATCH 2/2] [clang] Add tests for Swift CC on 32-bit PowerPC
---
clang/test/CodeGen/ppc-swiftcall.c | 61 ++++++++++++++++++++++
clang/test/Sema/ppc-swiftcall.c | 22 ++++++++
llvm/test/CodeGen/PowerPC/ppc32-swiftcc.ll | 38 ++++++++++++++
3 files changed, 121 insertions(+)
create mode 100644 clang/test/CodeGen/ppc-swiftcall.c
create mode 100644 clang/test/Sema/ppc-swiftcall.c
create mode 100644 llvm/test/CodeGen/PowerPC/ppc32-swiftcc.ll
diff --git a/clang/test/CodeGen/ppc-swiftcall.c b/clang/test/CodeGen/ppc-swiftcall.c
new file mode 100644
index 0000000000000..f61d30df23d27
--- /dev/null
+++ b/clang/test/CodeGen/ppc-swiftcall.c
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 -no-enable-noundef-analysis -triple powerpc-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -no-enable-noundef-analysis -triple powerpc-unknown-freebsd -emit-llvm -o - %s | FileCheck %s
+
+// REQUIRES: powerpc-registered-target
+
+// Verify that the Swift calling convention is emitted correctly for 32-bit
+// PowerPC (SVR4/EABI): functions are 'swiftcc', special parameters map to the
+// swiftself/swifterror attributes, and aggregates that occupy more than four
+// 32-bit units are passed/returned indirectly.
+
+#define SWIFTCALL __attribute__((swiftcall))
+#define OUT __attribute__((swift_indirect_result))
+#define ERROR __attribute__((swift_error_result))
+#define CONTEXT __attribute__((swift_context))
+
+/*****************************************************************************/
+/****************************** PARAMETER ABIS *******************************/
+/*****************************************************************************/
+
+SWIFTCALL void indirect_result_1(OUT int *arg0, OUT float *arg1) {}
+// CHECK-LABEL: define{{.*}} void @indirect_result_1(ptr noalias sret(ptr) align 4 dereferenceable(4){{.*}}, ptr noalias align 4 dereferenceable(4){{.*}})
+
+typedef struct { char array[1024]; } struct_reallybig;
+SWIFTCALL struct_reallybig indirect_result_3(OUT int *arg0, OUT float *arg1) { __builtin_unreachable(); }
+// CHECK-LABEL: define{{.*}} void @indirect_result_3(ptr{{.*}} sret(%struct.struct_reallybig) {{.*}}, ptr noalias align 4 dereferenceable(4){{.*}}, ptr noalias align 4 dereferenceable(4){{.*}})
+
+SWIFTCALL void context_1(CONTEXT void *self) {}
+// CHECK-LABEL: define{{.*}} void @context_1(ptr swiftself
+
+SWIFTCALL void context_2(void *arg0, CONTEXT void *self) {}
+// CHECK-LABEL: define{{.*}} void @context_2(ptr{{.*}}, ptr swiftself
+
+SWIFTCALL void context_error_1(CONTEXT int *self, ERROR float **error) {}
+// CHECK-LABEL: define{{.*}} void @context_error_1(ptr swiftself{{.*}}, ptr swifterror %0)
+
+void test_context_error_1(void) {
+ int x;
+ float *error;
+ context_error_1(&x, &error);
+}
+// CHECK-LABEL: define{{.*}} void @test_context_error_1()
+// CHECK: [[TEMP:%.*]] = alloca swifterror ptr, align 4
+// CHECK: call [[SWIFTCC:swiftcc]] void @context_error_1(ptr swiftself {{.*}}, ptr swifterror [[TEMP]])
+
+/*****************************************************************************/
+/********************************* AGGREGATES ********************************/
+/*****************************************************************************/
+
+// A struct that occupies exactly four 32-bit units is passed/returned
+// directly (it does not occupy *more than* four units).
+typedef struct { int x0, x1, x2, x3; } struct_4i;
+SWIFTCALL struct_4i return_struct_4i(void) { struct_4i r = {0,0,0,0}; return r; }
+// Returned directly: the result type is non-void and there is no sret
+// pointer, so the parameter list is empty.
+// CHECK-LABEL: define{{.*}} swiftcc {{.*}}@return_struct_4i()
+
+// A struct that occupies five 32-bit units occupies more than four and is
+// therefore returned indirectly via sret.
+typedef struct { int x0, x1, x2, x3, x4; } struct_5i;
+SWIFTCALL struct_5i return_struct_5i(void) { struct_5i r = {0,0,0,0,0}; return r; }
+// CHECK-LABEL: define{{.*}} swiftcc void @return_struct_5i(ptr{{.*}} sret(%struct.struct_5i)
diff --git a/clang/test/Sema/ppc-swiftcall.c b/clang/test/Sema/ppc-swiftcall.c
new file mode 100644
index 0000000000000..61b9842419f14
--- /dev/null
+++ b/clang/test/Sema/ppc-swiftcall.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple powerpc-unknown-linux-gnu -fsyntax-only %s -verify
+// RUN: %clang_cc1 -triple powerpc-unknown-freebsd -fsyntax-only %s -verify
+
+// The Swift calling convention is supported on 32-bit PowerPC (SVR4/EABI),
+// but the Swift async calling convention is not.
+
+// 'swiftcc' must be reported as an available extension.
+#if !__has_extension(swiftcc)
+#error "swiftcc should be supported on 32-bit PowerPC"
+#endif
+
+// 'swiftasynccc' must not be reported as available.
+#if __has_extension(swiftasynccc)
+#error "swiftasynccc should not be supported on 32-bit PowerPC"
+#endif
+
+// swiftcall is accepted without diagnostics.
+void __attribute__((swiftcall)) f(void) {}
+
+// swiftasynccall is rejected with an error on this target.
+// expected-error at +1 {{'swiftasynccall' calling convention is not supported for this target}}
+void __attribute__((swiftasynccall)) g(char *__attribute__((swift_async_context)) ctx) {}
diff --git a/llvm/test/CodeGen/PowerPC/ppc32-swiftcc.ll b/llvm/test/CodeGen/PowerPC/ppc32-swiftcc.ll
new file mode 100644
index 0000000000000..f4a7f72e88408
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/ppc32-swiftcc.ll
@@ -0,0 +1,38 @@
+; RUN: llc -verify-machineinstrs -mtriple=powerpc-unknown-linux-gnu < %s | FileCheck %s
+; RUN: llc -verify-machineinstrs -mtriple=powerpc-unknown-freebsd < %s | FileCheck %s
+
+; The 32-bit PowerPC SVR4/EABI lowering (LowerCall_32SVR4) must accept the
+; swiftcc and swifttailcc calling conventions instead of asserting on an
+; "Unknown calling convention". These tests confirm such calls lower cleanly;
+; the exact branch mnemonic (bl vs. a tail-call b) is intentionally not pinned.
+
+declare swiftcc i32 @callee_swift(i32 %x)
+
+define swiftcc i32 @caller_swift(i32 %x) {
+; CHECK-LABEL: caller_swift:
+; CHECK: callee_swift
+entry:
+ %r = call swiftcc i32 @callee_swift(i32 %x)
+ ret i32 %r
+}
+
+declare swifttailcc i32 @callee_swifttail(i32 %x)
+
+define swifttailcc i32 @caller_swifttail(i32 %x) {
+; CHECK-LABEL: caller_swifttail:
+; CHECK: callee_swifttail
+entry:
+ %r = call swifttailcc i32 @callee_swifttail(i32 %x)
+ ret i32 %r
+}
+
+; swiftself is passed through an ordinary argument register on the SVR4 ABI.
+declare swiftcc ptr @use_self(ptr swiftself %ctx)
+
+define swiftcc ptr @caller_swiftself(ptr %ctx) {
+; CHECK-LABEL: caller_swiftself:
+; CHECK: use_self
+entry:
+ %r = call swiftcc ptr @use_self(ptr swiftself %ctx)
+ ret ptr %r
+}
More information about the cfe-commits
mailing list