https://github.com/colemancda updated 
https://github.com/llvm/llvm-project/pull/213448

>From 71291dbdfb5954f7cc3ba2c0abe983db8223675a Mon Sep 17 00:00:00 2001
From: Alsey Coleman Miller <[email protected]>
Date: Sat, 1 Aug 2026 09:29:03 -0400
Subject: [PATCH 1/2] [clang][RISCV] Support the Swift calling convention

RISCVTargetCodeGenInfo already registers a SwiftABIInfo, but
RISCVTargetInfo::checkCallingConvention never accepts CC_Swift, so sema
drops the attribute and substitutes the default convention before
CodeGen is reached - every swift_context parameter then fails with
'swift_context' parameter can only be used with swiftcall or
swiftasynccall calling convention.

Accept CC_Swift and let LowerFormalArguments lower it; it needs no
separate assignment, since CC_RISCV is what the C convention already
uses and swift errors are passed indirectly. CC_SwiftAsync is refused
the way SystemZ and PPC64 refuse it, so __has_extension(swiftasynccc)
stays false and callers fall back to swiftcall rather than emitting a
convention with no lowering.

The riscv32 line in Sema/swift-call-conv.c asserted the opposite; it is
replaced by a dedicated test covering both conventions.
---
 clang/lib/Basic/Targets/RISCV.cpp           |  3 +++
 clang/test/Sema/riscv-swiftcall.c           | 18 ++++++++++++++
 clang/test/Sema/swift-call-conv.c           |  2 --
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp |  1 +
 llvm/test/CodeGen/RISCV/swiftcc.ll          | 26 +++++++++++++++++++++
 5 files changed, 48 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/Sema/riscv-swiftcall.c
 create mode 100644 llvm/test/CodeGen/RISCV/swiftcc.ll

diff --git a/clang/lib/Basic/Targets/RISCV.cpp 
b/clang/lib/Basic/Targets/RISCV.cpp
index 6afef3e2c7c48..801cfe9e60cd1 100644
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -612,7 +612,10 @@ RISCVTargetInfo::checkCallingConvention(CallingConv CC) 
const {
   case CC_RISCVVLSCall_16384:
   case CC_RISCVVLSCall_32768:
   case CC_RISCVVLSCall_65536:
+  case CC_Swift:
     return CCCR_OK;
+  case CC_SwiftAsync:
+    return CCCR_Error;
   }
 }
 
diff --git a/clang/test/Sema/riscv-swiftcall.c 
b/clang/test/Sema/riscv-swiftcall.c
new file mode 100644
index 0000000000000..e9ebbbef91745
--- /dev/null
+++ b/clang/test/Sema/riscv-swiftcall.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple riscv32-unknown-elf -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple riscv64-unknown-linux-gnu -fsyntax-only -verify %s
+
+// swiftcall is supported on RISC-V; swiftasynccall is not, because lowering
+// it needs guaranteed tail calls the backend does not provide.
+
+void __attribute__((swiftcall)) f(void *__attribute__((swift_context)) ctx) {}
+
+#if !__has_extension(swiftcc)
+#error swiftcc should be available on RISC-V
+#endif
+
+#if __has_extension(swiftasynccc)
+#error swiftasynccc should not be available on RISC-V
+#endif
+
+// expected-error@+1 {{'swiftasynccall' calling convention is not supported 
for this target}}
+void __attribute__((swiftasynccall)) g(void 
*__attribute__((swift_async_context)) ctx) {}
diff --git a/clang/test/Sema/swift-call-conv.c 
b/clang/test/Sema/swift-call-conv.c
index 2c9be84055848..42351f7e85d61 100644
--- a/clang/test/Sema/swift-call-conv.c
+++ b/clang/test/Sema/swift-call-conv.c
@@ -1,8 +1,6 @@
 // RUN: %clang_cc1 -triple aarch64-unknown-windows-msvc -fsyntax-only %s 
-verify
 // RUN: %clang_cc1 -triple thumbv7-unknown-windows-msvc -fsyntax-only %s 
-verify
 // RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -fsyntax-only %s -verify
-// RISC-V does not support swiftcall
-// RUN: %clang_cc1 -triple riscv32-unknown-elf -fsyntax-only %s -verify
 
 #if __has_extension(swiftcc)
 // expected-no-diagnostics
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp 
b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index aad62e7d40c54..99b908f2ea6b9 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -25738,6 +25738,7 @@ SDValue RISCVTargetLowering::LowerFormalArguments(
   case CallingConv::PreserveMost:
   case CallingConv::GRAAL:
   case CallingConv::RISCV_VectorCall:
+  case CallingConv::Swift:
 #define CC_VLS_CASE(ABI_VLEN) case CallingConv::RISCV_VLSCall_##ABI_VLEN:
     CC_VLS_CASE(32)
     CC_VLS_CASE(64)
diff --git a/llvm/test/CodeGen/RISCV/swiftcc.ll 
b/llvm/test/CodeGen/RISCV/swiftcc.ll
new file mode 100644
index 0000000000000..0d505fd4d5862
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/swiftcc.ll
@@ -0,0 +1,26 @@
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s | FileCheck %s
+
+; swiftcc is lowered like the C convention on RISC-V. Check that it is
+; accepted at all: LowerFormalArguments used to reject it with
+; "Unsupported calling convention".
+
+define swiftcc i32 @swiftcc_param(i32 %a, i32 %b) {
+; CHECK-LABEL: swiftcc_param:
+; CHECK: ret
+  %r = add i32 %a, %b
+  ret i32 %r
+}
+
+define swiftcc i32 @call_swiftcc(i32 %a, i32 %b) {
+; CHECK-LABEL: call_swiftcc:
+; CHECK: call swiftcc_param
+  %r = call swiftcc i32 @swiftcc_param(i32 %a, i32 %b)
+  ret i32 %r
+}
+
+define swiftcc ptr @swiftself_param(ptr swiftself %addr) {
+; CHECK-LABEL: swiftself_param:
+; CHECK: ret
+  ret ptr %addr
+}

>From 699ed30c6163739a706ba97865b04bfa594361d8 Mon Sep 17 00:00:00 2001
From: Alsey Coleman Miller <[email protected]>
Date: Mon, 10 Aug 2026 22:20:08 +0000
Subject: [PATCH 2/2] [RISCV] Define the Swift calling convention instead of
 borrowing the C one

Address review feedback on the initial swiftcall enablement, which
lowered the convention identically to the C convention:

- Pass the Swift context (swiftself) in x20 (s4), mirroring AArch64's
  x20. The register is already callee-saved under the standard ABIs, so
  the callee preserves it across ordinary calls with no CSR changes.
  x21/x22 are informally reserved for future swifterror/swiftasync use.

- Return values directly in up to four registers (a0-a3 / fa0-fa3)
  instead of two, matching the four-register limit clang's generic
  SwiftABIInfo::shouldPassIndirectly uses to classify direct returns.
  Larger returns fail CanLowerReturn and demote to sret as before.

- Floating-point register use follows the selected floating-point ABI:
  hard-float ABIs pass FP components in fa-registers, the soft-float
  ABIs use GPRs.

- Guard tail calls with parametersInCSRMatch: an argument passed in a
  caller-preserved register (the swiftself x20) is clobbered by the
  epilogue's CSR restore unless the outgoing value is the caller's own
  incoming value forwarded unchanged.

- Reject the convention on the E ABIs, where x20 is not callee-saved
  (or does not exist) and the reduced register file cannot hold a
  four-value soft-float f64 return. __has_extension(swiftcc) now
  reports false for ilp32e/lp64e.

- Install a RISCVSwiftABIInfo in clang that scalarizes vector
  components, since the base ISA has no fixed-width SIMD; keep
  SwiftErrorInRegister=false (swifterror remains indirect).

- Document that swiftcall is only a stable ABI on platforms where the
  Swift project has declared one, which is a platform-specific rather
  than architecture-specific property.
---
 clang/docs/ReleaseNotes.md                  |   7 ++
 clang/include/clang/Basic/AttrDocs.td       |   9 ++
 clang/lib/Basic/Targets/RISCV.cpp           |   5 +
 clang/lib/CodeGen/Targets/RISCV.cpp         |  17 ++-
 clang/test/CodeGen/riscv-swiftcall.c        |  93 +++++++++++++++
 clang/test/Sema/riscv-swiftcall-e.c         |  16 +++
 llvm/lib/Target/RISCV/RISCVCallingConv.cpp  |  27 ++++-
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp |  21 +++-
 llvm/test/CodeGen/RISCV/swift-return.ll     | 118 ++++++++++++++++++++
 llvm/test/CodeGen/RISCV/swiftself.ll        |  83 ++++++++++++++
 10 files changed, 387 insertions(+), 9 deletions(-)
 create mode 100644 clang/test/CodeGen/riscv-swiftcall.c
 create mode 100644 clang/test/Sema/riscv-swiftcall-e.c
 create mode 100644 llvm/test/CodeGen/RISCV/swift-return.ll
 create mode 100644 llvm/test/CodeGen/RISCV/swiftself.ll

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index a38b99ff8e075..b444ee317a0fe 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -479,6 +479,13 @@ features cannot lower the translation-unit ABI level;
 
 #### RISC-V Support
 
+- The `swiftcall` calling convention is now supported, except on the E ABIs.
+  The Swift context (`swift_context`) is passed in `x20`, values are returned
+  directly in up to four registers, and floating-point register use follows
+  the selected floating-point ABI. As on all platforms without a declared
+  stable Swift ABI, the convention's lowering is subject to change between
+  releases. `swiftasynccall` is not supported.
+
 #### CUDA/HIP Language Changes
 
 #### CUDA Support
diff --git a/clang/include/clang/Basic/AttrDocs.td 
b/clang/include/clang/Basic/AttrDocs.td
index 05e4cb0870652..f6268f5f1fb41 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -6427,6 +6427,15 @@ with ``__has_attribute(swiftcall)``. Query if the target 
supports the
 calling convention with ``__has_extension(swiftcc)``. This implies
 support for the ``swift_context``, ``swift_error_result``, and
 ``swift_indirect_result`` attributes.
+
+The Swift calling convention is a stable ABI only on platforms for which
+the Swift project has declared a stable ABI (currently, Apple platforms).
+This is a platform-specific property, not an architecture-specific one:
+for example, the convention is stable on Darwin x86-64 but not on Linux
+x86-64. On platforms where it is not stable, the convention's lowering
+may change between compiler releases, and it must not be used in
+ABI-stable binary interfaces; it remains usable for code built and
+distributed as a unit, such as when bringing up a new Swift port.
   }];
 }
 
diff --git a/clang/lib/Basic/Targets/RISCV.cpp 
b/clang/lib/Basic/Targets/RISCV.cpp
index 801cfe9e60cd1..b60286772d6f4 100644
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -612,7 +612,12 @@ RISCVTargetInfo::checkCallingConvention(CallingConv CC) 
const {
   case CC_RISCVVLSCall_16384:
   case CC_RISCVVLSCall_32768:
   case CC_RISCVVLSCall_65536:
+    return CCCR_OK;
   case CC_Swift:
+    // The Swift context register (x20) does not exist under the reduced
+    // register set of the E ABIs, so the convention is unsupported there.
+    if (ABI == "ilp32e" || ABI == "lp64e")
+      return CCCR_Error;
     return CCCR_OK;
   case CC_SwiftAsync:
     return CCCR_Error;
diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp 
b/clang/lib/CodeGen/Targets/RISCV.cpp
index ce2352ca76284..ba0efc2814614 100644
--- a/clang/lib/CodeGen/Targets/RISCV.cpp
+++ b/clang/lib/CodeGen/Targets/RISCV.cpp
@@ -1085,14 +1085,27 @@ void RISCVABIInfo::createCoercedStore(llvm::Value *Val, 
Address Dst,
 }
 
 namespace {
+class RISCVSwiftABIInfo : public SwiftABIInfo {
+public:
+  explicit RISCVSwiftABIInfo(CodeGen::CodeGenTypes &CGT)
+      : SwiftABIInfo(CGT, /*SwiftErrorInRegister=*/false) {}
+
+  bool isLegalVectorType(CharUnits VectorSize, llvm::Type *EltTy,
+                         unsigned NumElts) const override {
+    // The base calling convention has no vector registers; lower vectors
+    // into scalar components rather than relying on the default's
+    // assumption of 128-bit SIMD registers.
+    return false;
+  }
+};
+
 class RISCVTargetCodeGenInfo : public TargetCodeGenInfo {
 public:
   RISCVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen,
                          unsigned FLen, bool EABI)
       : TargetCodeGenInfo(
             std::make_unique<RISCVABIInfo>(CGT, XLen, FLen, EABI)) {
-    SwiftInfo =
-        std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false);
+    SwiftInfo = std::make_unique<RISCVSwiftABIInfo>(CGT);
   }
 
   void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
diff --git a/clang/test/CodeGen/riscv-swiftcall.c 
b/clang/test/CodeGen/riscv-swiftcall.c
new file mode 100644
index 0000000000000..15cd771854063
--- /dev/null
+++ b/clang/test/CodeGen/riscv-swiftcall.c
@@ -0,0 +1,93 @@
+// RUN: %clang_cc1 -no-enable-noundef-analysis -triple riscv64 -emit-llvm -o - 
%s | FileCheck %s --check-prefixes=CHECK,RV64
+// RUN: %clang_cc1 -no-enable-noundef-analysis -triple riscv32 -emit-llvm -o - 
%s | FileCheck %s --check-prefixes=CHECK,RV32
+// RUN: %clang_cc1 -no-enable-noundef-analysis -triple riscv64 -target-feature 
+d -target-abi lp64d -emit-llvm -o - %s | FileCheck %s 
--check-prefixes=CHECK,RV64
+
+// REQUIRES: riscv-registered-target
+
+#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){{.*}})
+
+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)
+
+/*****************************************************************************/
+/********************************** LOWERING *********************************/
+/*****************************************************************************/
+
+#define TEST(TYPE)                       \
+  SWIFTCALL TYPE return_##TYPE(void) {   \
+    TYPE result = {};                    \
+    return result;                       \
+  }                                      \
+  SWIFTCALL void take_##TYPE(TYPE v) {   \
+  }                                      \
+  void test_##TYPE(void) {               \
+    take_##TYPE(return_##TYPE());        \
+  }
+
+// Sub-pointer-sized fields merge into XLen chunks.
+typedef struct {
+  int x;
+  int y;
+} struct_2ints;
+TEST(struct_2ints)
+// RV64-LABEL: define {{.*}} swiftcc i64 @return_struct_2ints()
+// RV32-LABEL: define {{.*}} swiftcc { i32, i32 } @return_struct_2ints()
+// RV64-LABEL: define {{.*}} swiftcc void @take_struct_2ints(i64
+// RV32-LABEL: define {{.*}} swiftcc void @take_struct_2ints(i32 %0, i32 %1)
+
+// Four XLen-sized components are returned directly; the backend returns
+// them in a0-a3. On riscv32 the same struct occupies eight registers and is
+// returned indirectly.
+typedef struct {
+  long long a, b, c, d;
+} struct_4i64;
+TEST(struct_4i64)
+// RV64-LABEL: define {{.*}} swiftcc { i64, i64, i64, i64 } 
@return_struct_4i64()
+// RV32-LABEL: define {{.*}} swiftcc void @return_struct_4i64(ptr 
dead_on_unwind noalias writable sret
+// RV64-LABEL: define {{.*}} swiftcc void @take_struct_4i64(i64 %0, i64 %1, 
i64 %2, i64 %3)
+// RV32-LABEL: define {{.*}} swiftcc void @take_struct_4i64(ptr
+
+// Five components exceed the four-register return budget everywhere.
+typedef struct {
+  long long a, b, c, d, e;
+} struct_5i64;
+TEST(struct_5i64)
+// CHECK-LABEL: define {{.*}} swiftcc void @return_struct_5i64(ptr 
dead_on_unwind noalias writable sret
+// RV64-LABEL: define {{.*}} swiftcc void @take_struct_5i64(ptr
+// RV32-LABEL: define {{.*}} swiftcc void @take_struct_5i64(ptr
+
+// The mixed case from the swiftcall review: three components, returned
+// directly on riscv64 (a0/fa0/a1 under a hard-float ABI).
+typedef struct {
+  long long a;
+  float f;
+  long long b;
+} struct_mixed;
+TEST(struct_mixed)
+// RV64-LABEL: define {{.*}} swiftcc { i64, float, i64 } @return_struct_mixed()
+// RV32-LABEL: define {{.*}} swiftcc void @return_struct_mixed(ptr 
dead_on_unwind noalias writable sret
+// RV64-LABEL: define {{.*}} swiftcc void @take_struct_mixed(i64 %0, float %1, 
i64 %2)
+
+// Vector types are lowered into scalar components: the base RISC-V calling
+// convention has no vector registers.
+typedef float float4 __attribute__((ext_vector_type(4)));
+TEST(float4)
+// RV64-LABEL: define {{.*}} swiftcc { float, float, float, float } 
@return_float4()
+// RV32-LABEL: define {{.*}} swiftcc { float, float, float, float } 
@return_float4()
+// RV64-LABEL: define {{.*}} swiftcc void @take_float4(float %0, float %1, 
float %2, float %3)
diff --git a/clang/test/Sema/riscv-swiftcall-e.c 
b/clang/test/Sema/riscv-swiftcall-e.c
new file mode 100644
index 0000000000000..fa4a8b6f23c55
--- /dev/null
+++ b/clang/test/Sema/riscv-swiftcall-e.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple riscv32-unknown-elf -target-abi ilp32e 
-fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple riscv64-unknown-elf -target-feature +e -target-abi 
lp64e -fsyntax-only -verify %s
+
+// The Swift calling convention is not supported on the E ABIs: the Swift
+// context register (x20) does not exist under the reduced register set.
+
+#if __has_extension(swiftcc)
+#error swiftcc should not be available on the E ABIs
+#endif
+
+#if __has_extension(swiftasynccc)
+#error swiftasynccc should not be available on RISC-V
+#endif
+
+// expected-error@+1 {{'swiftcall' calling convention is not supported for 
this target}}
+void __attribute__((swiftcall)) f(void *__attribute__((swift_context)) ctx) {}
diff --git a/llvm/lib/Target/RISCV/RISCVCallingConv.cpp 
b/llvm/lib/Target/RISCV/RISCVCallingConv.cpp
index 381ab62e2bd64..982ceede7212a 100644
--- a/llvm/lib/Target/RISCV/RISCVCallingConv.cpp
+++ b/llvm/lib/Target/RISCV/RISCVCallingConv.cpp
@@ -434,10 +434,30 @@ static bool CC_RISCV_Impl(unsigned ValNo, MVT ValVT, MVT 
LocVT,
     }
   }
 
-  // Any return value split in to more than two values can't be returned
-  // directly. Vectors are returned via the available vector registers.
+  RISCVABI::ABI ABI = Subtarget.getTargetABI();
+  bool IsEABI = ABI == RISCVABI::ABI_ILP32E || ABI == RISCVABI::ABI_LP64E;
+
+  // A swiftself (Swift context) argument is passed in x20 (s4), a register
+  // that is otherwise callee-saved so that the callee preserves it across
+  // ordinary calls, mirroring AArch64's use of x20. The E ABIs do not treat
+  // x20 as callee-saved, and the Swift calling convention is rejected there.
+  if (!IsRet && ArgFlags.isSwiftSelf() && LocVT == XLenVT && !IsEABI) {
+    if (MCRegister Reg = State.AllocateReg(RISCV::X20)) {
+      State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+      return false;
+    }
+  }
+
+  // Swift returns values directly in up to four registers (a0-a3/fa0-fa3);
+  // other conventions return in at most two. This must cover everything
+  // clang's SwiftABIInfo::shouldPassIndirectly (limit: four registers)
+  // classifies as a direct return. Any return value split in to more values
+  // than this can't be returned directly. Vectors are returned via the
+  // available vector registers.
+  unsigned MaxDirectRetVals =
+      State.getCallingConv() == CallingConv::Swift && !IsEABI ? 4 : 2;
   if ((!LocVT.isVector() || Subtarget.isPExtPackedType(LocVT)) && IsRet &&
-      ValNo > 1)
+      ValNo >= MaxDirectRetVals)
     return true;
 
   // Double wide packed types require 2 GPRs so we can only return 1 of them.
@@ -450,7 +470,6 @@ static bool CC_RISCV_Impl(unsigned ValNo, MVT ValVT, MVT 
LocVT,
   // UseFPRForF64 if targeting an FLEN>=64 ABI and the argument isn't variadic.
   bool AllowFPRForF64 = false;
 
-  RISCVABI::ABI ABI = Subtarget.getTargetABI();
   switch (ABI) {
   default:
     llvm_unreachable("Unexpected ABI");
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp 
b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 99b908f2ea6b9..d69363db892e0 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -25738,7 +25738,6 @@ SDValue RISCVTargetLowering::LowerFormalArguments(
   case CallingConv::PreserveMost:
   case CallingConv::GRAAL:
   case CallingConv::RISCV_VectorCall:
-  case CallingConv::Swift:
 #define CC_VLS_CASE(ABI_VLEN) case CallingConv::RISCV_VLSCall_##ABI_VLEN:
     CC_VLS_CASE(32)
     CC_VLS_CASE(64)
@@ -25754,6 +25753,12 @@ SDValue RISCVTargetLowering::LowerFormalArguments(
     CC_VLS_CASE(65536)
 #undef CC_VLS_CASE
     break;
+  case CallingConv::Swift:
+    if (Subtarget.getTargetABI() == RISCVABI::ABI_ILP32E ||
+        Subtarget.getTargetABI() == RISCVABI::ABI_LP64E)
+      reportFatalUsageError(
+          "Swift calling convention is not supported on the E ABIs");
+    break;
   case CallingConv::GHC:
     if (Subtarget.hasStdExtE())
       reportFatalUsageError("GHC calling convention is not supported on RVE!");
@@ -25980,6 +25985,18 @@ bool 
RISCVTargetLowering::isEligibleForTailCallOptimization(
     if (Arg.Flags.isByVal())
       return false;
 
+  // Any argument passed in a register that the caller's convention treats as
+  // callee-saved (e.g. a swiftself context in x20) is clobbered when the
+  // epilogue restores callee-saved registers before the tail-call jump,
+  // unless the outgoing value is the caller's own incoming value forwarded
+  // unchanged. This applies to musttail too: rejecting here surfaces a fatal
+  // error in LowerCall rather than a miscompile.
+  const RISCVRegisterInfo *TRI = Subtarget.getRegisterInfo();
+  const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC);
+  if (!parametersInCSRMatch(MF.getRegInfo(), CallerPreserved, ArgLocs,
+                            CLI.OutVals))
+    return false;
+
   // musttail bypasses the remaining checks: the checks either reject cases
   // we handle specially (indirect args are forwarded via incoming pointers,
   // stack-passed args reuse the matching incoming layout, sret is forwarded
@@ -26009,8 +26026,6 @@ bool 
RISCVTargetLowering::isEligibleForTailCallOptimization(
     return false;
 
   // The callee has to preserve all registers the caller needs to preserve.
-  const RISCVRegisterInfo *TRI = Subtarget.getRegisterInfo();
-  const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC);
   if (CalleeCC != CallerCC) {
     const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC);
     if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved))
diff --git a/llvm/test/CodeGen/RISCV/swift-return.ll 
b/llvm/test/CodeGen/RISCV/swift-return.ll
new file mode 100644
index 0000000000000..7921bd3924f00
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/swift-return.ll
@@ -0,0 +1,118 @@
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s --check-prefixes=CHECK,RV32
+; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s --check-prefixes=CHECK,RV64,RV64-SOFT
+; RUN: llc -mtriple=riscv64 -mattr=+d -target-abi=lp64d -verify-machineinstrs \
+; RUN:   < %s | FileCheck %s --check-prefixes=CHECK,RV64,RV64D
+
+; The Swift calling convention returns values directly in up to four
+; registers, twice the limit of the standard convention.
+
+; A four-element aggregate is returned directly in a0-a3.
+; CHECK-LABEL: gen4:
+; CHECK-DAG: mv a1, a0
+; CHECK-DAG: mv a2, a0
+; CHECK-DAG: mv a3, a0
+; CHECK: ret
+define swiftcc { i32, i32, i32, i32 } @gen4(i32 %key) {
+  %v0 = insertvalue { i32, i32, i32, i32 } undef, i32 %key, 0
+  %v1 = insertvalue { i32, i32, i32, i32 } %v0, i32 %key, 1
+  %v2 = insertvalue { i32, i32, i32, i32 } %v1, i32 %key, 2
+  %v3 = insertvalue { i32, i32, i32, i32 } %v2, i32 %key, 3
+  ret { i32, i32, i32, i32 } %v3
+}
+
+; CHECK-LABEL: call_gen4:
+; CHECK: call gen4
+; CHECK-DAG: add{{w?}} {{.*}}, a0, a1
+; CHECK-DAG: add{{w?}} {{.*}}, a2, a3
+; CHECK: ret
+define i32 @call_gen4(i32 %key) {
+  %res = call swiftcc { i32, i32, i32, i32 } @gen4(i32 %key)
+  %v0 = extractvalue { i32, i32, i32, i32 } %res, 0
+  %v1 = extractvalue { i32, i32, i32, i32 } %res, 1
+  %v2 = extractvalue { i32, i32, i32, i32 } %res, 2
+  %v3 = extractvalue { i32, i32, i32, i32 } %res, 3
+  %s0 = add i32 %v0, %v1
+  %s1 = add i32 %v2, %v3
+  %s2 = add i32 %s0, %s1
+  ret i32 %s2
+}
+
+; The same aggregate under the C calling convention is still returned
+; indirectly: the four-register return is Swift-only.
+; CHECK-LABEL: gen4_ccc:
+; CHECK-DAG: sw {{.*}}, 0(a0)
+; CHECK-DAG: sw {{.*}}, 4(a0)
+; CHECK-DAG: sw {{.*}}, 8(a0)
+; CHECK-DAG: sw {{.*}}, 12(a0)
+; CHECK: ret
+define { i32, i32, i32, i32 } @gen4_ccc(i32 %key) {
+  %v0 = insertvalue { i32, i32, i32, i32 } undef, i32 %key, 0
+  %v1 = insertvalue { i32, i32, i32, i32 } %v0, i32 %key, 1
+  %v2 = insertvalue { i32, i32, i32, i32 } %v1, i32 %key, 2
+  %v3 = insertvalue { i32, i32, i32, i32 } %v2, i32 %key, 3
+  ret { i32, i32, i32, i32 } %v3
+}
+
+; A five-element aggregate exceeds the four-register budget and is demoted
+; to an indirect (sret) return.
+; CHECK-LABEL: gen5:
+; CHECK-DAG: sw {{.*}}, 0(a0)
+; CHECK-DAG: sw {{.*}}, 4(a0)
+; CHECK-DAG: sw {{.*}}, 8(a0)
+; CHECK-DAG: sw {{.*}}, 12(a0)
+; CHECK-DAG: sw {{.*}}, 16(a0)
+; CHECK: ret
+define swiftcc { i32, i32, i32, i32, i32 } @gen5(i32 %key) {
+  %v0 = insertvalue { i32, i32, i32, i32, i32 } undef, i32 %key, 0
+  %v1 = insertvalue { i32, i32, i32, i32, i32 } %v0, i32 %key, 1
+  %v2 = insertvalue { i32, i32, i32, i32, i32 } %v1, i32 %key, 2
+  %v3 = insertvalue { i32, i32, i32, i32, i32 } %v2, i32 %key, 3
+  %v4 = insertvalue { i32, i32, i32, i32, i32 } %v3, i32 %key, 4
+  ret { i32, i32, i32, i32, i32 } %v4
+}
+
+; A pair of i64s fits the budget on both rv32 (a0-a3 after splitting) and
+; rv64 (a0-a1).
+; CHECK-LABEL: gen2i64:
+; RV32-DAG: mv a2, a0
+; RV32-DAG: mv a3, a1
+; RV64: mv a1, a0
+; CHECK: ret
+define swiftcc { i64, i64 } @gen2i64(i64 %key) {
+  %v0 = insertvalue { i64, i64 } undef, i64 %key, 0
+  %v1 = insertvalue { i64, i64 } %v0, i64 %key, 1
+  ret { i64, i64 } %v1
+}
+
+; The mixed case from the swiftcall review: { i64, float, i64 } is returned
+; in a0/fa0/a1 under a hard-float ABI and a0-a2 under a soft-float ABI
+; (rv64).
+; RV64-LABEL: gen_mixed:
+; RV64-SOFT-DAG: mv a1, a0
+; RV64-SOFT-DAG: mv a2, a0
+; RV64D-DAG: fcvt.s.l fa0, a0
+; RV64D-DAG: mv a1, a0
+; RV64: ret
+define swiftcc { i64, float, i64 } @gen_mixed(i64 %key) {
+  %f = sitofp i64 %key to float
+  %v0 = insertvalue { i64, float, i64 } undef, i64 %key, 0
+  %v1 = insertvalue { i64, float, i64 } %v0, float %f, 1
+  %v2 = insertvalue { i64, float, i64 } %v1, i64 %key, 2
+  ret { i64, float, i64 } %v2
+}
+
+; Four doubles are returned in fa0-fa3 under lp64d.
+; RV64D-LABEL: gen4f64:
+; RV64D-DAG: fmv.d fa1, fa0
+; RV64D-DAG: fmv.d fa2, fa0
+; RV64D-DAG: fmv.d fa3, fa0
+; RV64D: ret
+define swiftcc { double, double, double, double } @gen4f64(double %key) {
+  %v0 = insertvalue { double, double, double, double } undef, double %key, 0
+  %v1 = insertvalue { double, double, double, double } %v0, double %key, 1
+  %v2 = insertvalue { double, double, double, double } %v1, double %key, 2
+  %v3 = insertvalue { double, double, double, double } %v2, double %key, 3
+  ret { double, double, double, double } %v3
+}
diff --git a/llvm/test/CodeGen/RISCV/swiftself.ll 
b/llvm/test/CodeGen/RISCV/swiftself.ll
new file mode 100644
index 0000000000000..1d3db689655e8
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/swiftself.ll
@@ -0,0 +1,83 @@
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s --check-prefixes=CHECK,SDAG
+; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s --check-prefixes=CHECK,SDAG
+; RUN: llc -mtriple=riscv64 -global-isel -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s
+
+; Parameter with swiftself should be allocated to x20 (s4).
+; CHECK-LABEL: swiftself_param:
+; CHECK: mv a0, s4
+; CHECK-NEXT: ret
+define ptr @swiftself_param(ptr swiftself %addr0) {
+  ret ptr %addr0
+}
+
+; Check that x20 is used to pass a swiftself argument.
+; CHECK-LABEL: call_swiftself:
+; CHECK: mv s4, a0
+; CHECK: call swiftself_param
+; CHECK: ret
+define ptr @call_swiftself(ptr %arg) {
+  %res = call ptr @swiftself_param(ptr swiftself %arg)
+  ret ptr %res
+}
+
+; x20 should be saved by the callee even if used for swiftself.
+; CHECK-LABEL: swiftself_clobber:
+; CHECK: {{sw|sd}} s4, {{[0-9]+}}(sp)
+; ...
+; CHECK: {{lw|ld}} s4, {{[0-9]+}}(sp)
+; CHECK: ret
+define ptr @swiftself_clobber(ptr swiftself %addr0) {
+  call void asm sideeffect "", "~{x20}"()
+  ret ptr %addr0
+}
+
+; Demonstrate that we do not need any moves when calling multiple functions
+; with the same swiftself argument.
+; CHECK-LABEL: swiftself_passthrough:
+; CHECK-NOT: mv s4,
+; CHECK: call swiftself_param
+; CHECK-NOT: mv s4,
+; CHECK-NEXT: call swiftself_param
+; CHECK: ret
+define void @swiftself_passthrough(ptr swiftself %addr0) {
+  call ptr @swiftself_param(ptr swiftself %addr0)
+  call ptr @swiftself_param(ptr swiftself %addr0)
+  ret void
+}
+
+; We can use a tail call if the callee swiftself is the same as the caller
+; one. GlobalISel does not implement tail calls on RISC-V yet and emits a
+; normal call.
+; CHECK-LABEL: swiftself_tail:
+; SDAG: tail swiftself_param
+; SDAG-NOT: ret
+define ptr @swiftself_tail(ptr swiftself %addr0) {
+  call void asm sideeffect "", "~{x20}"()
+  %res = tail call ptr @swiftself_param(ptr swiftself %addr0)
+  ret ptr %res
+}
+
+; We can not use a tail call if the callee swiftself is not the same as the
+; caller one: the epilogue restores s4 before the tail-call jump would
+; clobber the outgoing value.
+; CHECK-LABEL: swiftself_notail:
+; CHECK: mv s4, a0
+; CHECK: call swiftself_param
+; CHECK: ret
+define ptr @swiftself_notail(ptr swiftself %addr0, ptr %addr1) nounwind {
+  %res = tail call ptr @swiftself_param(ptr swiftself %addr1)
+  ret ptr %res
+}
+
+; swiftself does not steal any of the normal argument registers a0-a7.
+; CHECK-LABEL: swiftself_all_argregs:
+; CHECK: mv a0, s4
+; CHECK: ret
+define ptr @swiftself_all_argregs(i32 %a0, i32 %a1, i32 %a2, i32 %a3,
+                                  i32 %a4, i32 %a5, i32 %a6, i32 %a7,
+                                  ptr swiftself %addr0) {
+  ret ptr %addr0
+}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to