[clang] [clang][LoongArch] Match GCC ABI handling of integer complex types (PR #215222)

via cfe-commits cfe-commits at lists.llvm.org
Mon Aug 10 02:12:01 PDT 2026


https://github.com/heiher created https://github.com/llvm/llvm-project/pull/215222

GNU integer complex types such as `_Complex unsigned char` and `_Complex unsigned short` were incorrectly recognized as eligible floating-point ABI aggregates by `detectFARsEligibleStructHelper`. When used as a member of a structure, this caused the real and imaginary parts to be expanded into separate general-purpose argument registers.

Integer complex types are not floating-point complex types and should be handled as ordinary aggregates. Restrict the complex-type expansion path to elements with real floating-point types, allowing small integer complex aggregates to be packed into a single general-purpose register, consistent with GCC.

Fixes #214810

>From 1264c1b524d017baf5039d3c67a4142a12883c69 Mon Sep 17 00:00:00 2001
From: WANG Rui <wangrui at loongson.cn>
Date: Mon, 10 Aug 2026 17:08:27 +0800
Subject: [PATCH] [clang][LoongArch] Match GCC ABI handling of integer complex
 types

GNU integer complex types such as `_Complex unsigned char` and
`_Complex unsigned short` were incorrectly recognized as eligible
floating-point ABI aggregates by `detectFARsEligibleStructHelper`.
When used as a member of a structure, this caused the real and
imaginary parts to be expanded into separate general-purpose argument
registers.

Integer complex types are not floating-point complex types and should
be handled as ordinary aggregates. Restrict the complex-type expansion
path to elements with real floating-point types, allowing small integer
complex aggregates to be packed into a single general-purpose register,
consistent with GCC.
---
 clang/lib/CodeGen/Targets/LoongArch.cpp  |  6 +++++
 clang/test/CodeGen/LoongArch/abi-lp64d.c | 28 ++++++++++++++++++++++++
 2 files changed, 34 insertions(+)

diff --git a/clang/lib/CodeGen/Targets/LoongArch.cpp b/clang/lib/CodeGen/Targets/LoongArch.cpp
index 878723d67f081..ca080b22fcabd 100644
--- a/clang/lib/CodeGen/Targets/LoongArch.cpp
+++ b/clang/lib/CodeGen/Targets/LoongArch.cpp
@@ -135,6 +135,12 @@ bool LoongArchABIInfo::detectFARsEligibleStructHelper(
     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 GARs instead.
+    if (!EltTy->isRealFloatingType())
+      return false;
     if (getContext().getTypeSize(EltTy) > FRLen)
       return false;
     Field1Ty = CGT.ConvertType(EltTy);
diff --git a/clang/test/CodeGen/LoongArch/abi-lp64d.c b/clang/test/CodeGen/LoongArch/abi-lp64d.c
index 9f64cfd662e5f..6bee262f30fa2 100644
--- a/clang/test/CodeGen/LoongArch/abi-lp64d.c
+++ b/clang/test/CodeGen/LoongArch/abi-lp64d.c
@@ -501,6 +501,34 @@ struct doublecomplex_s f_doublecomplex_s(struct doublecomplex_s x) {
   return x;
 }
 
+/// A complex integer, or a structure containing just one complex integer
+/// (a GNU extension), is not eligible to be passed in floating-point
+/// registers; it is passed as though it were an aggregate of the same
+/// size, i.e. packed into a single GAR when its size does not exceed
+/// GRLen.
+
+// CHECK-LABEL: define{{.*}} i64 @f_ucharcomplex(i64 %x.coerce)
+unsigned char __complex__ f_ucharcomplex(unsigned char __complex__ x) { return x; }
+
+// CHECK-LABEL: define{{.*}} i64 @f_ushortcomplex(i64 %x.coerce)
+unsigned short __complex__ f_ushortcomplex(unsigned short __complex__ x) { return x; }
+
+struct ucharcomplex_s {
+  unsigned char __complex__ c;
+};
+// CHECK-LABEL: define{{.*}} i64 @f_ucharcomplex_s(i64 %x.coerce)
+struct ucharcomplex_s f_ucharcomplex_s(struct ucharcomplex_s x) {
+  return x;
+}
+
+struct ushortcomplex_s {
+  unsigned short __complex__ c;
+};
+// CHECK-LABEL: define{{.*}} i64 @f_ushortcomplex_s(i64 %x.coerce)
+struct ushortcomplex_s f_ushortcomplex_s(struct ushortcomplex_s x) {
+  return x;
+}
+
 /// Part 5: Variadic arguments.
 
 /// Variadic arguments are passed in GARs in the same manner as named arguments.



More information about the cfe-commits mailing list