https://github.com/doac updated https://github.com/llvm/llvm-project/pull/222264
>From 40bfa1c590f7a08a85f9a968d9a556f32f58e1e4 Mon Sep 17 00:00:00 2001 From: Daniel Cederman <[email protected]> Date: Mon, 17 Aug 2026 07:11:06 +0200 Subject: [PATCH 1/2] [Sparc][clang] Match GCC's SPARC V8 vector return convention Match GCC's SPARC V8 calling convention for vector return values. Return floating-point vectors and vectors larger than 64 bits indirectly. Return smaller integer vectors in floating-point registers. Assisted-by: Codex --- clang/lib/CodeGen/Targets/Sparc.cpp | 11 ++++ clang/test/CodeGen/Sparc/sparcv8-abi.c | 76 +++++++++++++++++++++++++- 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/clang/lib/CodeGen/Targets/Sparc.cpp b/clang/lib/CodeGen/Targets/Sparc.cpp index f5a17aa51184a..09663661bacce 100644 --- a/clang/lib/CodeGen/Targets/Sparc.cpp +++ b/clang/lib/CodeGen/Targets/Sparc.cpp @@ -71,6 +71,17 @@ ABIArgInfo SparcV8ABIInfo::classifyReturnType(QualType Ty) const { if (const auto *CT = Ty->getAs<ComplexType>()) return classifyComplexType(CT, /*IsRet=*/true); + if (const auto *VT = Ty->getAs<VectorType>()) { + uint64_t Size = getContext().getTypeSize(Ty); + if (VT->getElementType()->isRealFloatingType() || Size > 64) + return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace()); + + llvm::Type *FloatTy = llvm::Type::getFloatTy(getVMContext()); + llvm::Type *CoerceTy = + Size <= 32 ? FloatTy : llvm::StructType::get(FloatTy, FloatTy); + return ABIArgInfo::getDirect(CoerceTy); + } + if (const auto *BT = Ty->getAs<BuiltinType>(); BT && BT->getKind() == BuiltinType::LongDouble) return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(), diff --git a/clang/test/CodeGen/Sparc/sparcv8-abi.c b/clang/test/CodeGen/Sparc/sparcv8-abi.c index 7beddd20e5e4d..1aa2687f14f39 100644 --- a/clang/test/CodeGen/Sparc/sparcv8-abi.c +++ b/clang/test/CodeGen/Sparc/sparcv8-abi.c @@ -1,4 +1,4 @@ -// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --filter "^define |^entry:" --version 6 +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --filter "^define |^entry:|call .*@return_" --version 6 // RUN: %clang_cc1 -triple sparc-unknown-unknown -emit-llvm %s -o - | FileCheck %s float __complex__ @@ -50,3 +50,77 @@ t(long double _Complex a) { return 0; } + +typedef char v4i8 __attribute__((vector_size(4))); +typedef char v8i8 __attribute__((vector_size(8))); +typedef char v16i8 __attribute__((vector_size(16))); +typedef float v1f32 __attribute__((vector_size(4))); +typedef double v1f64 __attribute__((vector_size(8))); + +// Integer vectors of at most eight bytes are returned in floating-point +// registers. Larger integer vectors and all floating-point vectors are +// returned indirectly. +// CHECK-LABEL: define dso_local float @return_v4i8( +// CHECK-SAME: i32 noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK: [[ENTRY:.*:]] +// +v4i8 return_v4i8(int x) { return (v4i8){x, x, x, x}; } +// CHECK-LABEL: define dso_local { float, float } @return_v8i8( +// CHECK-SAME: i32 noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK: [[ENTRY:.*:]] +// +v8i8 return_v8i8(int x) { return (v8i8){x, x, x, x, x, x, x, x}; } +// CHECK-LABEL: define dso_local void @return_v16i8( +// CHECK-SAME: ptr dead_on_unwind noalias writable sret(<16 x i8>) align 16 [[AGG_RESULT:%.*]], i32 noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK: [[ENTRY:.*:]] +// +v16i8 return_v16i8(int x) { + return (v16i8){x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x}; +} +// CHECK-LABEL: define dso_local void @return_v1f32( +// CHECK-SAME: ptr dead_on_unwind noalias writable sret(<1 x float>) align 4 [[AGG_RESULT:%.*]], float noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK: [[ENTRY:.*:]] +// +v1f32 return_v1f32(float x) { return (v1f32){x}; } +// CHECK-LABEL: define dso_local void @return_v1f64( +// CHECK-SAME: ptr dead_on_unwind noalias writable sret(<1 x double>) align 8 [[AGG_RESULT:%.*]], double noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK: [[ENTRY:.*:]] +// +v1f64 return_v1f64(double x) { return (v1f64){x}; } + +volatile v4i8 v4i8_result; +volatile v8i8 v8i8_result; +volatile v16i8 v16i8_result; +volatile v1f32 v1f32_result; +volatile v1f64 v1f64_result; + +// CHECK-LABEL: define dso_local void @call_integer_vector_returns( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK: [[ENTRY:.*:]] +// CHECK: [[CALL:%.*]] = call float @return_v4i8(i32 noundef 1) +// CHECK: [[CALL1:%.*]] = call { float, float } @return_v8i8(i32 noundef 1) +// CHECK: call void @return_v16i8(ptr dead_on_unwind writable sret(<16 x i8>) align 16 [[TMP:%.*]], i32 noundef 1) +// +void call_integer_vector_returns(void) { + v4i8_result = return_v4i8(1); + v8i8_result = return_v8i8(1); + v16i8_result = return_v16i8(1); +} + +// CHECK-LABEL: define dso_local void @call_f32_vector_return( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK: [[ENTRY:.*:]] +// CHECK: call void @return_v1f32(ptr dead_on_unwind writable sret(<1 x float>) align 4 [[TMP:%.*]], float noundef 1.000000e+00) +// +void call_f32_vector_return(void) { + v1f32_result = return_v1f32(1.0f); +} + +// CHECK-LABEL: define dso_local void @call_f64_vector_return( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK: [[ENTRY:.*:]] +// CHECK: call void @return_v1f64(ptr dead_on_unwind writable sret(<1 x double>) align 8 [[TMP:%.*]], double noundef 1.000000e+00) +// +void call_f64_vector_return(void) { + v1f64_result = return_v1f64(1.0); +} >From c34ee51571c92aae564f1078a0a6004425443c49 Mon Sep 17 00:00:00 2001 From: Daniel Cederman <[email protected]> Date: Mon, 14 Sep 2026 08:22:04 +0200 Subject: [PATCH 2/2] [Sparc][clang] Match GCC's SPARC V8 vector return convention v2 Use double to return 64-bit integer vectors. Add tests for v1i32, v2i32, and v4i16 variants. --- clang/lib/CodeGen/Targets/Sparc.cpp | 5 +++-- clang/test/CodeGen/Sparc/sparcv8-abi.c | 31 ++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/clang/lib/CodeGen/Targets/Sparc.cpp b/clang/lib/CodeGen/Targets/Sparc.cpp index 09663661bacce..ee49f2a1f864f 100644 --- a/clang/lib/CodeGen/Targets/Sparc.cpp +++ b/clang/lib/CodeGen/Targets/Sparc.cpp @@ -76,9 +76,10 @@ ABIArgInfo SparcV8ABIInfo::classifyReturnType(QualType Ty) const { if (VT->getElementType()->isRealFloatingType() || Size > 64) return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace()); + // Return smaller integer vectors via float registers. llvm::Type *FloatTy = llvm::Type::getFloatTy(getVMContext()); - llvm::Type *CoerceTy = - Size <= 32 ? FloatTy : llvm::StructType::get(FloatTy, FloatTy); + llvm::Type *DoubleTy = llvm::Type::getDoubleTy(getVMContext()); + llvm::Type *CoerceTy = Size <= 32 ? FloatTy : DoubleTy; return ABIArgInfo::getDirect(CoerceTy); } diff --git a/clang/test/CodeGen/Sparc/sparcv8-abi.c b/clang/test/CodeGen/Sparc/sparcv8-abi.c index 1aa2687f14f39..d2ba172377786 100644 --- a/clang/test/CodeGen/Sparc/sparcv8-abi.c +++ b/clang/test/CodeGen/Sparc/sparcv8-abi.c @@ -54,6 +54,9 @@ t(long double _Complex a) typedef char v4i8 __attribute__((vector_size(4))); typedef char v8i8 __attribute__((vector_size(8))); typedef char v16i8 __attribute__((vector_size(16))); +typedef int v1i32 __attribute__((vector_size(4))); +typedef int v2i32 __attribute__((vector_size(8))); +typedef short v4i16 __attribute__((vector_size(8))); typedef float v1f32 __attribute__((vector_size(4))); typedef double v1f64 __attribute__((vector_size(8))); @@ -65,11 +68,26 @@ typedef double v1f64 __attribute__((vector_size(8))); // CHECK: [[ENTRY:.*:]] // v4i8 return_v4i8(int x) { return (v4i8){x, x, x, x}; } -// CHECK-LABEL: define dso_local { float, float } @return_v8i8( +// CHECK-LABEL: define dso_local double @return_v8i8( // CHECK-SAME: i32 noundef [[X:%.*]]) #[[ATTR0]] { // CHECK: [[ENTRY:.*:]] // v8i8 return_v8i8(int x) { return (v8i8){x, x, x, x, x, x, x, x}; } +// CHECK-LABEL: define dso_local float @return_v1i32( +// CHECK-SAME: i32 noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK: [[ENTRY:.*:]] +// +v1i32 return_v1i32(int x) { return (v1i32){x}; } +// CHECK-LABEL: define dso_local double @return_v2i32( +// CHECK-SAME: i32 noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK: [[ENTRY:.*:]] +// +v2i32 return_v2i32(int x) { return (v2i32){x, x}; } +// CHECK-LABEL: define dso_local double @return_v4i16( +// CHECK-SAME: i32 noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK: [[ENTRY:.*:]] +// +v4i16 return_v4i16(int x) { return (v4i16){x, x, x, x}; } // CHECK-LABEL: define dso_local void @return_v16i8( // CHECK-SAME: ptr dead_on_unwind noalias writable sret(<16 x i8>) align 16 [[AGG_RESULT:%.*]], i32 noundef [[X:%.*]]) #[[ATTR0]] { // CHECK: [[ENTRY:.*:]] @@ -91,6 +109,9 @@ v1f64 return_v1f64(double x) { return (v1f64){x}; } volatile v4i8 v4i8_result; volatile v8i8 v8i8_result; volatile v16i8 v16i8_result; +volatile v1i32 v1i32_result; +volatile v2i32 v2i32_result; +volatile v4i16 v4i16_result; volatile v1f32 v1f32_result; volatile v1f64 v1f64_result; @@ -98,12 +119,18 @@ volatile v1f64 v1f64_result; // CHECK-SAME: ) #[[ATTR0]] { // CHECK: [[ENTRY:.*:]] // CHECK: [[CALL:%.*]] = call float @return_v4i8(i32 noundef 1) -// CHECK: [[CALL1:%.*]] = call { float, float } @return_v8i8(i32 noundef 1) +// CHECK: [[CALL1:%.*]] = call double @return_v8i8(i32 noundef 1) +// CHECK: [[CALL3:%.*]] = call float @return_v1i32(i32 noundef 1) +// CHECK: [[CALL5:%.*]] = call double @return_v2i32(i32 noundef 1) +// CHECK: [[CALL7:%.*]] = call double @return_v4i16(i32 noundef 1) // CHECK: call void @return_v16i8(ptr dead_on_unwind writable sret(<16 x i8>) align 16 [[TMP:%.*]], i32 noundef 1) // void call_integer_vector_returns(void) { v4i8_result = return_v4i8(1); v8i8_result = return_v8i8(1); + v1i32_result = return_v1i32(1); + v2i32_result = return_v2i32(1); + v4i16_result = return_v4i16(1); v16i8_result = return_v16i8(1); } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
