[PowerPC] ABI support for non-Altivec vector types

This patch adds support for passing arguments of non-Altivec vector type
(i.e. defined via attribute ((vector_size (...)))) on powerpc64-linux.

While such types are not mentioned in the formal ABI document, this
patch implements a calling convention compatible with GCC:

- Vectors of size < 16 bytes are passed in a GPR
- Vectors of size > 16 bytes are passed via reference

Note that vector types with a number of elements that is not a power
of 2 are not supported by GCC, so there is no pre-existing ABI to
follow.  We choose to pass those (of size < 16) as if widened to the
next power of two, so they might end up in a vector register or
in a GPR.  (Sizes > 16 are always passed via reference as well.)

Reviewed by Hal Finkel.

llvm-svn: 212734
This commit is contained in:
Ulrich Weigand 2014-07-10 16:39:01 +00:00
parent 57417d0d97
commit f4eba98853
2 changed files with 78 additions and 1 deletions

View File

@ -2923,7 +2923,8 @@ public:
const Type *T = isSingleElementStruct(I.type, getContext());
if (T) {
const BuiltinType *BT = T->getAs<BuiltinType>();
if (T->isVectorType() || (BT && BT->isFloatingPoint())) {
if ((T->isVectorType() && getContext().getTypeSize(T) == 128) ||
(BT && BT->isFloatingPoint())) {
QualType QT(T, 0);
I.info = ABIArgInfo::getDirectInReg(CGT.ConvertType(QT));
continue;
@ -2997,6 +2998,18 @@ PPC64_SVR4_ABIInfo::classifyArgumentType(QualType Ty) const {
if (Ty->isAnyComplexType())
return ABIArgInfo::getDirect();
// Non-Altivec vector types are passed in GPRs (smaller than 16 bytes)
// or via reference (larger than 16 bytes).
if (Ty->isVectorType()) {
uint64_t Size = getContext().getTypeSize(Ty);
if (Size > 128)
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
else if (Size < 128) {
llvm::Type *CoerceTy = llvm::IntegerType::get(getVMContext(), Size);
return ABIArgInfo::getDirect(CoerceTy);
}
}
if (isAggregateTypeForABI(Ty)) {
if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
@ -3016,6 +3029,18 @@ PPC64_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const {
if (RetTy->isAnyComplexType())
return ABIArgInfo::getDirect();
// Non-Altivec vector types are returned in GPRs (smaller than 16 bytes)
// or via reference (larger than 16 bytes).
if (RetTy->isVectorType()) {
uint64_t Size = getContext().getTypeSize(RetTy);
if (Size > 128)
return ABIArgInfo::getIndirect(0);
else if (Size < 128) {
llvm::Type *CoerceTy = llvm::IntegerType::get(getVMContext(), Size);
return ABIArgInfo::getDirect(CoerceTy);
}
}
if (isAggregateTypeForABI(RetTy))
return ABIArgInfo::getIndirect(0);

View File

@ -0,0 +1,52 @@
// RUN: %clang_cc1 -faltivec -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
typedef short v2i16 __attribute__((vector_size (4)));
typedef short v3i16 __attribute__((vector_size (6)));
typedef short v4i16 __attribute__((vector_size (8)));
typedef short v6i16 __attribute__((vector_size (12)));
typedef short v8i16 __attribute__((vector_size (16)));
typedef short v16i16 __attribute__((vector_size (32)));
struct v16i16 { v16i16 x; };
// CHECK: define i32 @test_v2i16(i32 %x.coerce)
v2i16 test_v2i16(v2i16 x)
{
return x;
}
// CHECK: define i64 @test_v3i16(i64 %x.coerce)
v3i16 test_v3i16(v3i16 x)
{
return x;
}
// CHECK: define i64 @test_v4i16(i64 %x.coerce)
v4i16 test_v4i16(v4i16 x)
{
return x;
}
// CHECK: define <6 x i16> @test_v6i16(<6 x i16> %x)
v6i16 test_v6i16(v6i16 x)
{
return x;
}
// CHECK: define <8 x i16> @test_v8i16(<8 x i16> %x)
v8i16 test_v8i16(v8i16 x)
{
return x;
}
// CHECK: define void @test_v16i16(<16 x i16>* noalias sret %agg.result, <16 x i16>*)
v16i16 test_v16i16(v16i16 x)
{
return x;
}
// CHECK: define void @test_struct_v16i16(%struct.v16i16* noalias sret %agg.result, %struct.v16i16* byval %x)
struct v16i16 test_struct_v16i16(struct v16i16 x)
{
return x;
}