llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-codegen 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
