[clang] [RISCV] make `_Complex {integer}` consistent with GCC (PR #216404)

Folkert de Vries via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 14 15:02:21 PDT 2026


https://github.com/folkertdev updated https://github.com/llvm/llvm-project/pull/216404

>From 77105ec5c27e155a36aabcdb999079516d5de48f Mon Sep 17 00:00:00 2001
From: Folkert de Vries <folkert at folkertdev.nl>
Date: Fri, 14 Aug 2026 21:08:52 +0200
Subject: [PATCH 1/2] [RISCV] make `_Complex {integer}` consistent with GCC

Complex integers should not be passed via FPRs.
---
 clang/lib/CodeGen/Targets/RISCV.cpp    |  6 ++++++
 clang/test/CodeGen/RISCV/riscv32-abi.c | 23 +++++++++--------------
 clang/test/CodeGen/RISCV/riscv64-abi.c | 23 +++++++++--------------
 3 files changed, 24 insertions(+), 28 deletions(-)

diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp
index ce2352ca76284..4bac5711a2dd6 100644
--- a/clang/lib/CodeGen/Targets/RISCV.cpp
+++ b/clang/lib/CodeGen/Targets/RISCV.cpp
@@ -225,6 +225,12 @@ bool RISCVABIInfo::detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff,
     if (Field1Ty)
       return false;
     QualType EltTy = CTy->getElementType();
+    // Only floating-point complex types (e.g. _Complex float/double) are
+    // eligible to be passed in floating-point argument registers. Complex
+    // integer types (a GNU extension) should be treated like a normal
+    // aggregate and packed into GPRs instead.
+    if (!EltTy->isRealFloatingType())
+      return false;
     if (getContext().getTypeSize(EltTy) > FLen)
       return false;
     Field1Ty = CGT.ConvertType(EltTy);
diff --git a/clang/test/CodeGen/RISCV/riscv32-abi.c b/clang/test/CodeGen/RISCV/riscv32-abi.c
index e9f7e6c26a0dc..9fa34a9a75cf2 100644
--- a/clang/test/CodeGen/RISCV/riscv32-abi.c
+++ b/clang/test/CodeGen/RISCV/riscv32-abi.c
@@ -1888,6 +1888,9 @@ struct float16complex_s f_ret_float16complex_s(void) {
   return (struct float16complex_s){1.0};
 }
 
+// Complex integer values or structs containing a single complex
+// integer value should be passed as if it were an int+int struct.
+
 // CHECK-LABEL: define{{.*}} i64 @f_ucharcomplex(i64 %x.coerce)
 // ILP32-ILP32F-ILP32D-LABEL: define dso_local i16 @f_ucharcomplex
 // ILP32-ILP32F-ILP32D-SAME: (i16 noundef [[X_COERCE:%.*]]) #[[ATTR0]] {
@@ -1906,13 +1909,9 @@ struct ucharcomplex_s {
   unsigned char __complex__ c;
 };
 // CHECK-LABEL: define{{.*}} i64 @f_ucharcomplex_s(i64 %x.coerce)
-// ILP32-LABEL: define dso_local i16 @f_ucharcomplex_s
-// ILP32-SAME: (i16 [[X_COERCE:%.*]]) #[[ATTR0]] {
-// ILP32:  entry:
-//
-// ILP32F-ILP32D-LABEL: define dso_local { i8, i8 } @f_ucharcomplex_s
-// ILP32F-ILP32D-SAME: (i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) #[[ATTR0]] {
-// ILP32F-ILP32D:  entry:
+// ILP32-ILP32F-ILP32D-LABEL: define dso_local i16 @f_ucharcomplex_s
+// ILP32-ILP32F-ILP32D-SAME: (i16 [[X_COERCE:%.*]]) #[[ATTR0]] {
+// ILP32-ILP32F-ILP32D:  entry:
 //
 struct ucharcomplex_s f_ucharcomplex_s(struct ucharcomplex_s x) {
   return x;
@@ -1922,13 +1921,9 @@ struct ushortcomplex_s {
   unsigned short __complex__ c;
 };
 // CHECK-LABEL: define{{.*}} i64 @f_ushortcomplex_s(i64 %x.coerce)
-// ILP32-LABEL: define dso_local i32 @f_ushortcomplex_s
-// ILP32-SAME: (i32 [[X_COERCE:%.*]]) #[[ATTR0]] {
-// ILP32:  entry:
-//
-// ILP32F-ILP32D-LABEL: define dso_local { i16, i16 } @f_ushortcomplex_s
-// ILP32F-ILP32D-SAME: (i16 [[TMP0:%.*]], i16 [[TMP1:%.*]]) #[[ATTR0]] {
-// ILP32F-ILP32D:  entry:
+// ILP32-ILP32F-ILP32D-LABEL: define dso_local i32 @f_ushortcomplex_s
+// ILP32-ILP32F-ILP32D-SAME: (i32 [[X_COERCE:%.*]]) #[[ATTR0]] {
+// ILP32-ILP32F-ILP32D:  entry:
 //
 struct ushortcomplex_s f_ushortcomplex_s(struct ushortcomplex_s x) {
   return x;
diff --git a/clang/test/CodeGen/RISCV/riscv64-abi.c b/clang/test/CodeGen/RISCV/riscv64-abi.c
index ac5524720ee31..4a2f89e9ec6b1 100644
--- a/clang/test/CodeGen/RISCV/riscv64-abi.c
+++ b/clang/test/CodeGen/RISCV/riscv64-abi.c
@@ -709,6 +709,9 @@ struct floatcomplex_s f_ret_floatcomplex_s(void) {
   return (struct floatcomplex_s){1.0};
 }
 
+// Complex integer values or structs containing a single complex
+// integer value should be passed as if it were an int+int struct.
+
 // CHECK-LABEL: define{{.*}} i64 @f_ucharcomplex(i64 %x.coerce)
 // LP64-LP64F-LP64D-LABEL: define dso_local i16 @f_ucharcomplex
 // LP64-LP64F-LP64D-SAME: (i16 noundef [[X_COERCE:%.*]]) #[[ATTR0]] {
@@ -727,13 +730,9 @@ struct ucharcomplex_s {
   unsigned char __complex__ c;
 };
 // CHECK-LABEL: define{{.*}} i64 @f_ucharcomplex_s(i64 %x.coerce)
-// LP64-LABEL: define dso_local i16 @f_ucharcomplex_s
-// LP64-SAME: (i16 [[X_COERCE:%.*]]) #[[ATTR0]] {
-// LP64:  entry:
-//
-// LP64F-LP64D-LABEL: define dso_local { i8, i8 } @f_ucharcomplex_s
-// LP64F-LP64D-SAME: (i8 [[TMP0:%.*]], i8 [[TMP1:%.*]]) #[[ATTR0]] {
-// LP64F-LP64D:  entry:
+// LP64-LP64F-LP64D-LABEL: define dso_local i16 @f_ucharcomplex_s
+// LP64-LP64F-LP64D-SAME: (i16 [[X_COERCE:%.*]]) #[[ATTR0]] {
+// LP64-LP64F-LP64D:  entry:
 //
 struct ucharcomplex_s f_ucharcomplex_s(struct ucharcomplex_s x) {
   return x;
@@ -743,13 +742,9 @@ struct ushortcomplex_s {
   unsigned short __complex__ c;
 };
 // CHECK-LABEL: define{{.*}} i64 @f_ushortcomplex_s(i64 %x.coerce)
-// LP64-LABEL: define dso_local i32 @f_ushortcomplex_s
-// LP64-SAME: (i32 [[X_COERCE:%.*]]) #[[ATTR0]] {
-// LP64:  entry:
-//
-// LP64F-LP64D-LABEL: define dso_local { i16, i16 } @f_ushortcomplex_s
-// LP64F-LP64D-SAME: (i16 [[TMP0:%.*]], i16 [[TMP1:%.*]]) #[[ATTR0]] {
-// LP64F-LP64D:  entry:
+// LP64-LP64F-LP64D-LABEL: define dso_local i32 @f_ushortcomplex_s
+// LP64-LP64F-LP64D-SAME: (i32 [[X_COERCE:%.*]]) #[[ATTR0]] {
+// LP64-LP64F-LP64D:  entry:
 //
 struct ushortcomplex_s f_ushortcomplex_s(struct ushortcomplex_s x) {
   return x;

>From 6fc1907c1d893f8f5303a09a01ee8626c5247446 Mon Sep 17 00:00:00 2001
From: Folkert de Vries <folkert at folkertdev.nl>
Date: Sat, 15 Aug 2026 00:01:57 +0200
Subject: [PATCH 2/2] remove ignored check lines

---
 clang/test/CodeGen/RISCV/riscv32-abi.c | 4 ----
 clang/test/CodeGen/RISCV/riscv64-abi.c | 4 ----
 2 files changed, 8 deletions(-)

diff --git a/clang/test/CodeGen/RISCV/riscv32-abi.c b/clang/test/CodeGen/RISCV/riscv32-abi.c
index 9fa34a9a75cf2..fe4cb21146ee8 100644
--- a/clang/test/CodeGen/RISCV/riscv32-abi.c
+++ b/clang/test/CodeGen/RISCV/riscv32-abi.c
@@ -1891,14 +1891,12 @@ struct float16complex_s f_ret_float16complex_s(void) {
 // Complex integer values or structs containing a single complex
 // integer value should be passed as if it were an int+int struct.
 
-// CHECK-LABEL: define{{.*}} i64 @f_ucharcomplex(i64 %x.coerce)
 // ILP32-ILP32F-ILP32D-LABEL: define dso_local i16 @f_ucharcomplex
 // ILP32-ILP32F-ILP32D-SAME: (i16 noundef [[X_COERCE:%.*]]) #[[ATTR0]] {
 // ILP32-ILP32F-ILP32D:  entry:
 //
 unsigned char __complex__ f_ucharcomplex(unsigned char __complex__ x) { return x; }
 
-// CHECK-LABEL: define{{.*}} i64 @f_ushortcomplex(i64 %x.coerce)
 // ILP32-ILP32F-ILP32D-LABEL: define dso_local i32 @f_ushortcomplex
 // ILP32-ILP32F-ILP32D-SAME: (i32 noundef [[X_COERCE:%.*]]) #[[ATTR0]] {
 // ILP32-ILP32F-ILP32D:  entry:
@@ -1908,7 +1906,6 @@ unsigned short __complex__ f_ushortcomplex(unsigned short __complex__ x) { retur
 struct ucharcomplex_s {
   unsigned char __complex__ c;
 };
-// CHECK-LABEL: define{{.*}} i64 @f_ucharcomplex_s(i64 %x.coerce)
 // ILP32-ILP32F-ILP32D-LABEL: define dso_local i16 @f_ucharcomplex_s
 // ILP32-ILP32F-ILP32D-SAME: (i16 [[X_COERCE:%.*]]) #[[ATTR0]] {
 // ILP32-ILP32F-ILP32D:  entry:
@@ -1920,7 +1917,6 @@ struct ucharcomplex_s f_ucharcomplex_s(struct ucharcomplex_s x) {
 struct ushortcomplex_s {
   unsigned short __complex__ c;
 };
-// CHECK-LABEL: define{{.*}} i64 @f_ushortcomplex_s(i64 %x.coerce)
 // ILP32-ILP32F-ILP32D-LABEL: define dso_local i32 @f_ushortcomplex_s
 // ILP32-ILP32F-ILP32D-SAME: (i32 [[X_COERCE:%.*]]) #[[ATTR0]] {
 // ILP32-ILP32F-ILP32D:  entry:
diff --git a/clang/test/CodeGen/RISCV/riscv64-abi.c b/clang/test/CodeGen/RISCV/riscv64-abi.c
index 4a2f89e9ec6b1..88a64f41f71b9 100644
--- a/clang/test/CodeGen/RISCV/riscv64-abi.c
+++ b/clang/test/CodeGen/RISCV/riscv64-abi.c
@@ -712,14 +712,12 @@ struct floatcomplex_s f_ret_floatcomplex_s(void) {
 // Complex integer values or structs containing a single complex
 // integer value should be passed as if it were an int+int struct.
 
-// CHECK-LABEL: define{{.*}} i64 @f_ucharcomplex(i64 %x.coerce)
 // LP64-LP64F-LP64D-LABEL: define dso_local i16 @f_ucharcomplex
 // LP64-LP64F-LP64D-SAME: (i16 noundef [[X_COERCE:%.*]]) #[[ATTR0]] {
 // LP64-LP64F-LP64D:  entry:
 //
 unsigned char __complex__ f_ucharcomplex(unsigned char __complex__ x) { return x; }
 
-// CHECK-LABEL: define{{.*}} i64 @f_ushortcomplex(i64 %x.coerce)
 // LP64-LP64F-LP64D-LABEL: define dso_local i32 @f_ushortcomplex
 // LP64-LP64F-LP64D-SAME: (i32 noundef [[X_COERCE:%.*]]) #[[ATTR0]] {
 // LP64-LP64F-LP64D:  entry:
@@ -729,7 +727,6 @@ unsigned short __complex__ f_ushortcomplex(unsigned short __complex__ x) { retur
 struct ucharcomplex_s {
   unsigned char __complex__ c;
 };
-// CHECK-LABEL: define{{.*}} i64 @f_ucharcomplex_s(i64 %x.coerce)
 // LP64-LP64F-LP64D-LABEL: define dso_local i16 @f_ucharcomplex_s
 // LP64-LP64F-LP64D-SAME: (i16 [[X_COERCE:%.*]]) #[[ATTR0]] {
 // LP64-LP64F-LP64D:  entry:
@@ -741,7 +738,6 @@ struct ucharcomplex_s f_ucharcomplex_s(struct ucharcomplex_s x) {
 struct ushortcomplex_s {
   unsigned short __complex__ c;
 };
-// CHECK-LABEL: define{{.*}} i64 @f_ushortcomplex_s(i64 %x.coerce)
 // LP64-LP64F-LP64D-LABEL: define dso_local i32 @f_ushortcomplex_s
 // LP64-LP64F-LP64D-SAME: (i32 [[X_COERCE:%.*]]) #[[ATTR0]] {
 // LP64-LP64F-LP64D:  entry:



More information about the cfe-commits mailing list