[clang] [Sparc][clang] Match GCC's SPARC V8 vector return convention (PR #222264)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 9 01:25:30 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Daniel Cederman (doac)
<details>
<summary>Changes</summary>
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.
https://godbolt.org/z/sKzeoqb17
Assisted-by: Codex
---
Full diff: https://github.com/llvm/llvm-project/pull/222264.diff
2 Files Affected:
- (modified) clang/lib/CodeGen/Targets/Sparc.cpp (+11)
- (modified) clang/test/CodeGen/Sparc/sparcv8-abi.c (+75-1)
``````````diff
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);
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/222264
More information about the cfe-commits
mailing list