From e1e3ad3d11cb5d650b87c27d7b0af2f18e35d0eb Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Tue, 3 Jul 2012 19:24:06 +0000 Subject: [PATCH] Make the following changes in the way Mips handles vector arguments and return values: - Return integer vectors in integer registers. - Pass vector arguments in integer registers. - Set an upper bound for argument alignment. The largest alignment is 8-byte for O32 and 16-byte for N32/64. llvm-svn: 159676 --- clang/lib/CodeGen/TargetInfo.cpp | 63 ++++++++++++------------- clang/test/CodeGen/mips-vector-arg.c | 28 +++++++++++ clang/test/CodeGen/mips-vector-return.c | 10 ++++ 3 files changed, 69 insertions(+), 32 deletions(-) create mode 100644 clang/test/CodeGen/mips-vector-arg.c diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index c49fba339b7c..006cc4b65520 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -3166,14 +3166,16 @@ void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D, namespace { class MipsABIInfo : public ABIInfo { bool IsO32; - unsigned MinABIStackAlignInBytes; - llvm::Type* CoerceToIntArgs(uint64_t TySize) const; + unsigned MinABIStackAlignInBytes, StackAlignInBytes; + void CoerceToIntArgs(uint64_t TySize, + SmallVector &ArgList) const; llvm::Type* HandleAggregates(QualType Ty, uint64_t TySize) const; llvm::Type* returnAggregateInRegs(QualType RetTy, uint64_t Size) const; llvm::Type* getPaddingType(uint64_t Align, uint64_t Offset) const; public: MipsABIInfo(CodeGenTypes &CGT, bool _IsO32) : - ABIInfo(CGT), IsO32(_IsO32), MinABIStackAlignInBytes(IsO32 ? 4 : 8) {} + ABIInfo(CGT), IsO32(_IsO32), MinABIStackAlignInBytes(IsO32 ? 4 : 8), + StackAlignInBytes(IsO32 ? 8 : 16) {} ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType RetTy, uint64_t &Offset) const; @@ -3202,10 +3204,10 @@ public: }; } -llvm::Type* MipsABIInfo::CoerceToIntArgs(uint64_t TySize) const { - SmallVector ArgList; - llvm::IntegerType *IntTy = llvm::IntegerType::get(getVMContext(), - MinABIStackAlignInBytes * 8); +void MipsABIInfo::CoerceToIntArgs(uint64_t TySize, + SmallVector &ArgList) const { + llvm::IntegerType *IntTy = + llvm::IntegerType::get(getVMContext(), MinABIStackAlignInBytes * 8); // Add (TySize / MinABIStackAlignInBytes) args of IntTy. for (unsigned N = TySize / (MinABIStackAlignInBytes * 8); N; --N) @@ -3216,24 +3218,28 @@ llvm::Type* MipsABIInfo::CoerceToIntArgs(uint64_t TySize) const { if (R) ArgList.push_back(llvm::IntegerType::get(getVMContext(), R)); - - return llvm::StructType::get(getVMContext(), ArgList); } // In N32/64, an aligned double precision floating point field is passed in // a register. llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty, uint64_t TySize) const { - if (IsO32) - return CoerceToIntArgs(TySize); + SmallVector ArgList, IntArgList; + + if (IsO32) { + CoerceToIntArgs(TySize, ArgList); + return llvm::StructType::get(getVMContext(), ArgList); + } if (Ty->isComplexType()) return CGT.ConvertType(Ty); const RecordType *RT = Ty->getAs(); - // Unions are passed in integer registers. - if (!RT || !RT->isStructureOrClassType()) - return CoerceToIntArgs(TySize); + // Unions/vectors are passed in integer registers. + if (!RT || !RT->isStructureOrClassType()) { + CoerceToIntArgs(TySize, ArgList); + return llvm::StructType::get(getVMContext(), ArgList); + } const RecordDecl *RD = RT->getDecl(); const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); @@ -3242,7 +3248,6 @@ llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty, uint64_t TySize) const { uint64_t LastOffset = 0; unsigned idx = 0; llvm::IntegerType *I64 = llvm::IntegerType::get(getVMContext(), 64); - SmallVector ArgList; // Iterate over fields in the struct/class and check if there are any aligned // double fields. @@ -3267,15 +3272,8 @@ llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty, uint64_t TySize) const { LastOffset = Offset + 64; } - // Add ((TySize - LastOffset) / 64) args of type i64. - for (unsigned N = (TySize - LastOffset) / 64; N; --N) - ArgList.push_back(I64); - - // If the size of the remainder is not zero, add one more integer type to - // ArgList. - unsigned R = (TySize - LastOffset) % 64; - if (R) - ArgList.push_back(llvm::IntegerType::get(getVMContext(), R)); + CoerceToIntArgs(TySize - LastOffset, IntArgList); + ArgList.append(IntArgList.begin(), IntArgList.end()); return llvm::StructType::get(getVMContext(), ArgList); } @@ -3295,11 +3293,12 @@ MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const { uint64_t TySize = getContext().getTypeSize(Ty); uint64_t Align = getContext().getTypeAlign(Ty) / 8; - Align = std::max(Align, (uint64_t)MinABIStackAlignInBytes); + Align = std::min(std::max(Align, (uint64_t)MinABIStackAlignInBytes), + (uint64_t)StackAlignInBytes); Offset = llvm::RoundUpToAlignment(Offset, Align); Offset += llvm::RoundUpToAlignment(TySize, Align * 8) / 8; - if (isAggregateTypeForABI(Ty)) { + if (isAggregateTypeForABI(Ty) || Ty->isVectorType()) { // Ignore empty aggregates. if (TySize == 0) return ABIArgInfo::getIgnore(); @@ -3331,7 +3330,7 @@ MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const { llvm::Type* MipsABIInfo::returnAggregateInRegs(QualType RetTy, uint64_t Size) const { const RecordType *RT = RetTy->getAs(); - SmallVector RTList; + SmallVector RTList; if (RT && RT->isStructureOrClassType()) { const RecordDecl *RD = RT->getDecl(); @@ -3366,11 +3365,7 @@ MipsABIInfo::returnAggregateInRegs(QualType RetTy, uint64_t Size) const { } } - RTList.push_back(llvm::IntegerType::get(getVMContext(), - std::min(Size, (uint64_t)64))); - if (Size > 64) - RTList.push_back(llvm::IntegerType::get(getVMContext(), Size - 64)); - + CoerceToIntArgs(Size, RTList); return llvm::StructType::get(getVMContext(), RTList); } @@ -3385,6 +3380,10 @@ ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isAnyComplexType()) return ABIArgInfo::getDirect(); + // O32 returns integer vectors in registers. + if (IsO32 && RetTy->isVectorType() && !RetTy->hasFloatingRepresentation()) + return ABIArgInfo::getDirect(returnAggregateInRegs(RetTy, Size)); + if (!IsO32 && !isRecordWithNonTrivialDestructorOrCopyConstructor(RetTy)) return ABIArgInfo::getDirect(returnAggregateInRegs(RetTy, Size)); } diff --git a/clang/test/CodeGen/mips-vector-arg.c b/clang/test/CodeGen/mips-vector-arg.c new file mode 100644 index 000000000000..39998d91a64a --- /dev/null +++ b/clang/test/CodeGen/mips-vector-arg.c @@ -0,0 +1,28 @@ +// RUN: %clang -target mipsel-unknown-linux -ccc-clang-archs mipsel -O3 -S -o - -emit-llvm %s | FileCheck %s -check-prefix=O32 +// RUN: %clang -target mips64el-unknown-linux -ccc-clang-archs mips64el -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s -check-prefix=N64 + +// check that +// 1. vector arguments are passed in integer registers +// 2. argument alignment is no larger than 8-byte for O32 and 16-byte for N64. + +typedef float v4sf __attribute__ ((__vector_size__ (16))); +typedef int v4i32 __attribute__ ((__vector_size__ (16))); + +// O32: define void @test_v4sf(i32 %a1.coerce0, i32 %a1.coerce1, i32 %a1.coerce2, i32 %a1.coerce3, i32 %a2, i32, i32 %a3.coerce0, i32 %a3.coerce1, i32 %a3.coerce2, i32 %a3.coerce3) nounwind +// O32: declare i32 @test_v4sf_2(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32) +// N64: define void @test_v4sf(i64 %a1.coerce0, i64 %a1.coerce1, i32 %a2, i64, i64 %a3.coerce0, i64 %a3.coerce1) nounwind +// N64: declare i32 @test_v4sf_2(i64, i64, i32, i64, i64, i64) +extern test_v4sf_2(v4sf, int, v4sf); +void test_v4sf(v4sf a1, int a2, v4sf a3) { + test_v4sf_2(a3, a2, a1); +} + +// O32: define void @test_v4i32(i32 %a1.coerce0, i32 %a1.coerce1, i32 %a1.coerce2, i32 %a1.coerce3, i32 %a2, i32, i32 %a3.coerce0, i32 %a3.coerce1, i32 %a3.coerce2, i32 %a3.coerce3) nounwind +// O32: declare i32 @test_v4i32_2(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32) +// N64: define void @test_v4i32(i64 %a1.coerce0, i64 %a1.coerce1, i32 %a2, i64, i64 %a3.coerce0, i64 %a3.coerce1) nounwind +// N64: declare i32 @test_v4i32_2(i64, i64, i32, i64, i64, i64) +extern test_v4i32_2(v4i32, int, v4i32); +void test_v4i32(v4i32 a1, int a2, v4i32 a3) { + test_v4i32_2(a3, a2, a1); +} + diff --git a/clang/test/CodeGen/mips-vector-return.c b/clang/test/CodeGen/mips-vector-return.c index db6174874d26..12e71fadf87b 100644 --- a/clang/test/CodeGen/mips-vector-return.c +++ b/clang/test/CodeGen/mips-vector-return.c @@ -6,6 +6,7 @@ // integer registers. typedef float v4sf __attribute__ ((__vector_size__ (16))); typedef double v4df __attribute__ ((__vector_size__ (32))); +typedef int v4i32 __attribute__ ((__vector_size__ (16))); // O32: define void @test_v4sf(<4 x float>* noalias nocapture sret // N64: define { i64, i64 } @test_v4sf @@ -19,3 +20,12 @@ v4df test_v4df(double a) { return (v4df){0.0, a, 0.0, 0.0}; } +// O32 returns integer vectors whose size is equal to or smaller than 16-bytes +// in integer registers. +// +// O32: define { i32, i32, i32, i32 } @test_v4i32 +// N64: define { i64, i64 } @test_v4i32 +v4i32 test_v4i32(int a) { + return (v4i32){0, a, 0, 0}; +} +