[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