llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-sparc

Author: Folkert de Vries (folkertdev)

<details>
<summary>Changes</summary>

https://godbolt.org/z/o1nGYEM33

```c
extern void sink(int, ...);

void variadic_cld(_Complex float z) { sink(0, z); }
```

Current clang just uses float registers

```asm
variadic_cld:
        mov     %g0, %o0
        fmovs %f0, %f2
        fmovs %f1, %f3
        mov     %o7, %g1
        call sink
        mov     %g1, %o7
```

GCC packs a complex float into a single GPR

```asm
variadic_cld:
        save    %sp, -192, %sp
        st      %f0, [%fp+2043]
        lduw    [%fp+2043], %g1
        sllx    %g1, 32, %g1
        srl     %o1, 0, %o1
        or      %o1, %g1, %o1
        st      %f1, [%fp+2043]
        lduw    [%fp+2043], %g2
        mov     -1, %g1
        sllx    %g1, 32, %g1
        and     %o1, %g1, %o1
        or      %o1, %g2, %o1
        call    sink, 0
         mov    0, %o0
        return  %i7+8
         nop
```

---
Full diff: https://github.com/llvm/llvm-project/pull/216524.diff


2 Files Affected:

- (modified) clang/lib/CodeGen/Targets/Sparc.cpp (+17-8) 
- (modified) clang/test/CodeGen/Sparc/variadic-aggregate.c (+24-36) 


``````````diff
diff --git a/clang/lib/CodeGen/Targets/Sparc.cpp 
b/clang/lib/CodeGen/Targets/Sparc.cpp
index 25f0009fe7a09..9d8280ad25dd6 100644
--- a/clang/lib/CodeGen/Targets/Sparc.cpp
+++ b/clang/lib/CodeGen/Targets/Sparc.cpp
@@ -163,7 +163,7 @@ class SparcV9ABIInfo : public ABIInfo {
   bool IsComplexGnuABI;
 
   ABIArgInfo classifyType(QualType RetTy, unsigned SizeLimit,
-                          unsigned &RegOffset) const;
+                          unsigned &RegOffset, bool IsVarArg) const;
   void computeInfo(CGFunctionInfo &FI) const override;
   RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
                    AggValueSlot Slot) const override;
@@ -185,9 +185,11 @@ class SparcV9ABIInfo : public ABIInfo {
     SmallVector<llvm::Type*, 8> Elems;
     uint64_t Size;
     bool InReg;
+    bool IsVarArg;
 
-    CoerceBuilder(llvm::LLVMContext &c, const llvm::DataLayout &dl)
-      : Context(c), DL(dl), Size(0), InReg(false) {}
+    CoerceBuilder(llvm::LLVMContext &c, const llvm::DataLayout &dl,
+                  bool IsVarArg)
+        : Context(c), DL(dl), Size(0), InReg(false), IsVarArg(IsVarArg) {}
 
     // Pad Elems with integers until Size is ToSize.
     void pad(uint64_t ToSize) {
@@ -217,6 +219,9 @@ class SparcV9ABIInfo : public ABIInfo {
 
     // Add a floating point element at Offset.
     void addFloat(uint64_t Offset, llvm::Type *Ty, unsigned Bits) {
+      // Varargs are treated as integers.
+      if (IsVarArg)
+        return;
       // Unaligned floats are treated as integers.
       if (Offset % Bits)
         return;
@@ -277,7 +282,8 @@ class SparcV9ABIInfo : public ABIInfo {
 } // end anonymous namespace
 
 ABIArgInfo SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit,
-                                        unsigned &RegOffset) const {
+                                        unsigned &RegOffset,
+                                        bool IsVarArg) const {
   if (Ty->isVoidType())
     return ABIArgInfo::getIgnore();
 
@@ -369,7 +375,7 @@ ABIArgInfo SparcV9ABIInfo::classifyType(QualType Ty, 
unsigned SizeLimit,
     return ABIArgInfo::getDirect(/*T=*/nullptr, /*Offset=*/0, Padding);
   }
 
-  CoerceBuilder CB(VMContext, getDataLayout());
+  CoerceBuilder CB(VMContext, getDataLayout(), IsVarArg);
   CB.addStruct(0, StrTy);
   // All structs, even empty ones, should take up a register argument slot,
   // so pin the minimum struct size to one bit.
@@ -406,13 +412,16 @@ RValue SparcV9ABIInfo::EmitVAArg(CodeGenFunction &CGF, 
Address VAListAddr,
 
 void SparcV9ABIInfo::computeInfo(CGFunctionInfo &FI) const {
   unsigned RetOffset = 0;
-  ABIArgInfo RetType = classifyType(FI.getReturnType(), 32 * 8, RetOffset);
+  ABIArgInfo RetType =
+      classifyType(FI.getReturnType(), 32 * 8, RetOffset, /*IsVarArg=*/false);
   FI.getReturnInfo() = RetType;
 
   // Indirect returns will have its pointer passed as an argument.
   unsigned ArgOffset = RetType.isIndirect() ? RetOffset : 0;
-  for (auto &I : FI.arguments())
-    I.info = classifyType(I.type, 16 * 8, ArgOffset);
+  for (auto [ArgNo, I] : llvm::enumerate(FI.arguments())) {
+    bool IsVarArg = ArgNo >= FI.getNumRequiredArgs();
+    I.info = classifyType(I.type, 16 * 8, ArgOffset, IsVarArg);
+  }
 }
 
 namespace {
diff --git a/clang/test/CodeGen/Sparc/variadic-aggregate.c 
b/clang/test/CodeGen/Sparc/variadic-aggregate.c
index 92093e1133b8a..fb7524b887980 100644
--- a/clang/test/CodeGen/Sparc/variadic-aggregate.c
+++ b/clang/test/CodeGen/Sparc/variadic-aggregate.c
@@ -615,11 +615,8 @@ void test_long_long_long_long(va_list *ap) {
 // SPARC64-NEXT:    [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { float, 
float }, ptr [[COERCE]], i32 0, i32 1
 // SPARC64-NEXT:    store float [[X_REAL]], ptr [[COERCE_REALP]], align 4
 // SPARC64-NEXT:    store float [[X_IMAG]], ptr [[COERCE_IMAGP]], align 4
-// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw { float, float 
}, ptr [[COERCE]], i32 0, i32 0
-// SPARC64-NEXT:    [[TMP2:%.*]] = load float, ptr [[TMP1]], align 4
-// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw { float, float 
}, ptr [[COERCE]], i32 0, i32 1
-// SPARC64-NEXT:    [[TMP4:%.*]] = load float, ptr [[TMP3]], align 4
-// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, float 
inreg noundef [[TMP2]], float inreg noundef [[TMP4]])
+// SPARC64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[COERCE]], align 4
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
noundef [[TMP1]])
 // SPARC64-NEXT:    ret void
 //
 void test_complex_float(va_list *ap) {
@@ -650,11 +647,8 @@ void test_complex_float(va_list *ap) {
 // SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 8
 // SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
 // SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[X]], ptr 
align 8 [[ARGP_CUR]], i64 8, i1 false)
-// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw 
[[STRUCT_FLOAT_FLOAT]], ptr [[X]], i32 0, i32 0
-// SPARC64-NEXT:    [[TMP2:%.*]] = load float, ptr [[TMP1]], align 4
-// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw 
[[STRUCT_FLOAT_FLOAT]], ptr [[X]], i32 0, i32 1
-// SPARC64-NEXT:    [[TMP4:%.*]] = load float, ptr [[TMP3]], align 4
-// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, float 
inreg [[TMP2]], float inreg [[TMP4]])
+// SPARC64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[X]], align 4
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
[[TMP1]])
 // SPARC64-NEXT:    ret void
 //
 void test_float_float(va_list *ap) {
@@ -717,11 +711,11 @@ void test_float_float(va_list *ap) {
 // SPARC64-NEXT:    [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { 
double, double }, ptr [[COERCE]], i32 0, i32 1
 // SPARC64-NEXT:    store double [[X_REAL]], ptr [[COERCE_REALP]], align 8
 // SPARC64-NEXT:    store double [[X_IMAG]], ptr [[COERCE_IMAGP]], align 8
-// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw { double, double 
}, ptr [[COERCE]], i32 0, i32 0
-// SPARC64-NEXT:    [[TMP2:%.*]] = load double, ptr [[TMP1]], align 8
-// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw { double, double 
}, ptr [[COERCE]], i32 0, i32 1
-// SPARC64-NEXT:    [[TMP4:%.*]] = load double, ptr [[TMP3]], align 8
-// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, double 
noundef [[TMP2]], double noundef [[TMP4]])
+// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[COERCE]], i32 0, i32 0
+// SPARC64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 8
+// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[COERCE]], i32 0, i32 1
+// SPARC64-NEXT:    [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
noundef [[TMP2]], i64 noundef [[TMP4]])
 // SPARC64-NEXT:    ret void
 //
 void test_complex_double(va_list *ap) {
@@ -752,11 +746,11 @@ void test_complex_double(va_list *ap) {
 // SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 16
 // SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
 // SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[X]], ptr 
align 8 [[ARGP_CUR]], i64 16, i1 false)
-// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw 
[[STRUCT_DOUBLE_DOUBLE]], ptr [[X]], i32 0, i32 0
-// SPARC64-NEXT:    [[TMP2:%.*]] = load double, ptr [[TMP1]], align 8
-// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw 
[[STRUCT_DOUBLE_DOUBLE]], ptr [[X]], i32 0, i32 1
-// SPARC64-NEXT:    [[TMP4:%.*]] = load double, ptr [[TMP3]], align 8
-// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, double 
[[TMP2]], double [[TMP4]])
+// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 8
+// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
[[TMP2]], i64 [[TMP4]])
 // SPARC64-NEXT:    ret void
 //
 void test_double_double(va_list *ap) {
@@ -925,13 +919,11 @@ void test_aligned_int(va_list *ap) {
 // SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR_ALIGNED]], i64 16
 // SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
 // SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 16 [[X]], ptr 
align 16 [[ARGP_CUR_ALIGNED]], i64 16, i1 false)
-// SPARC64-NEXT:    [[TMP2:%.*]] = getelementptr inbounds nuw { float, i32, 
i64 }, ptr [[X]], i32 0, i32 0
-// SPARC64-NEXT:    [[TMP3:%.*]] = load float, ptr [[TMP2]], align 16
-// SPARC64-NEXT:    [[TMP4:%.*]] = getelementptr inbounds nuw { float, i32, 
i64 }, ptr [[X]], i32 0, i32 1
-// SPARC64-NEXT:    [[TMP5:%.*]] = load i32, ptr [[TMP4]], align 4
-// SPARC64-NEXT:    [[TMP6:%.*]] = getelementptr inbounds nuw { float, i32, 
i64 }, ptr [[X]], i32 0, i32 2
-// SPARC64-NEXT:    [[TMP7:%.*]] = load i64, ptr [[TMP6]], align 8
-// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
undef, float inreg [[TMP3]], i32 inreg [[TMP5]], i64 inreg [[TMP7]])
+// SPARC64-NEXT:    [[TMP2:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[TMP3:%.*]] = load i64, ptr [[TMP2]], align 16
+// SPARC64-NEXT:    [[TMP4:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[TMP5:%.*]] = load i64, ptr [[TMP4]], align 8
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
undef, i64 [[TMP3]], i64 [[TMP5]])
 // SPARC64-NEXT:    ret void
 //
 void test_aligned_float(va_list *ap) {
@@ -997,15 +989,11 @@ void test_int_int_int_int(va_list *ap) {
 // SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 16
 // SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
 // SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[X]], ptr 
align 8 [[ARGP_CUR]], i64 16, i1 false)
-// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw 
[[STRUCT_FLOAT_FLOAT_FLOAT_FLOAT]], ptr [[X]], i32 0, i32 0
-// SPARC64-NEXT:    [[TMP2:%.*]] = load float, ptr [[TMP1]], align 4
-// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw 
[[STRUCT_FLOAT_FLOAT_FLOAT_FLOAT]], ptr [[X]], i32 0, i32 1
-// SPARC64-NEXT:    [[TMP4:%.*]] = load float, ptr [[TMP3]], align 4
-// SPARC64-NEXT:    [[TMP5:%.*]] = getelementptr inbounds nuw 
[[STRUCT_FLOAT_FLOAT_FLOAT_FLOAT]], ptr [[X]], i32 0, i32 2
-// SPARC64-NEXT:    [[TMP6:%.*]] = load float, ptr [[TMP5]], align 4
-// SPARC64-NEXT:    [[TMP7:%.*]] = getelementptr inbounds nuw 
[[STRUCT_FLOAT_FLOAT_FLOAT_FLOAT]], ptr [[X]], i32 0, i32 3
-// SPARC64-NEXT:    [[TMP8:%.*]] = load float, ptr [[TMP7]], align 4
-// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, float 
inreg [[TMP2]], float inreg [[TMP4]], float inreg [[TMP6]], float inreg 
[[TMP8]])
+// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 4
+// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 4
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
[[TMP2]], i64 [[TMP4]])
 // SPARC64-NEXT:    ret void
 //
 void test_float_float_float_float(va_list *ap) {

``````````

</details>


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

Reply via email to