diff options
author | Ulrich Weigand <ulrich.weigand@de.ibm.com> | 2012-11-05 19:13:42 +0000 |
---|---|---|
committer | Ulrich Weigand <ulrich.weigand@de.ibm.com> | 2012-11-05 19:13:42 +0000 |
commit | 71c0dcc129262e565069fbfc0b5239a05c94b86c (patch) | |
tree | 60a344ad8501a2a0da1f6fcdf277acedf077971a | |
parent | bd8fa30760754c902bde3e2210094833833452b9 (diff) |
On PowerPC64, integer arguments and return values need to be sign- or
zero-extended to 64 bits. This information is currently provided to
the back end by setting "signext" or "zeroext" attributes. However,
this is done only for integer types *smaller* than i32, not for i32
itself. This causes clang to generate code violating the ABI, which
results in a failure of the tramp3d-v4 test case (due to calling a
system library routine without ABI-required extension).
This patch implements custom versions of classifyArgumentType and
classifyReturnType for PPC64_SVR4_ABIInfo, which are the same as the
default versions except that they also classify "int" and "unsigned int"
as types needing extending. This fixed tramp3d-v4 on PowerPC64.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@167393 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/CodeGen/TargetInfo.cpp | 58 | ||||
-rw-r--r-- | test/CodeGen/ppc64-extend.c | 15 |
2 files changed, 73 insertions, 0 deletions
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 7aed35956f..f07e9548b1 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -2684,6 +2684,11 @@ class PPC64_SVR4_ABIInfo : public DefaultABIInfo { public: PPC64_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} + bool isPromotableTypeForABI(QualType Ty) const; + + ABIArgInfo classifyReturnType(QualType RetTy) const; + ABIArgInfo classifyArgumentType(QualType Ty) const; + // TODO: We can add more logic to computeInfo to improve performance. // Example: For aggregate arguments that fit in a register, we could // use getDirectInReg (as is done below for structs containing a single @@ -2744,6 +2749,59 @@ public: } +// Return true if the ABI requires Ty to be passed sign- or zero- +// extended to 64 bits. +bool +PPC64_SVR4_ABIInfo::isPromotableTypeForABI(QualType Ty) const { + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = Ty->getAs<EnumType>()) + Ty = EnumTy->getDecl()->getIntegerType(); + + // Promotable integer types are required to be promoted by the ABI. + if (Ty->isPromotableIntegerType()) + return true; + + // In addition to the usual promotable integer types, we also need to + // extend all 32-bit types, since the ABI requires promotion to 64 bits. + if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) + switch (BT->getKind()) { + case BuiltinType::Int: + case BuiltinType::UInt: + return true; + default: + break; + } + + return false; +} + +ABIArgInfo +PPC64_SVR4_ABIInfo::classifyArgumentType(QualType Ty) const { + if (isAggregateTypeForABI(Ty)) { + // Records with non trivial destructors/constructors should not be passed + // by value. + if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) + return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + + return ABIArgInfo::getIndirect(0); + } + + return (isPromotableTypeForABI(Ty) ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); +} + +ABIArgInfo +PPC64_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const { + if (RetTy->isVoidType()) + return ABIArgInfo::getIgnore(); + + if (isAggregateTypeForABI(RetTy)) + return ABIArgInfo::getIndirect(0); + + return (isPromotableTypeForABI(RetTy) ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); +} + // Based on ARMABIInfo::EmitVAArg, adjusted for 64-bit machine. llvm::Value *PPC64_SVR4_ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, diff --git a/test/CodeGen/ppc64-extend.c b/test/CodeGen/ppc64-extend.c new file mode 100644 index 0000000000..f4d6bf9c68 --- /dev/null +++ b/test/CodeGen/ppc64-extend.c @@ -0,0 +1,15 @@ +// REQUIRES: ppc64-registered-target +// RUN: %clang_cc1 -O0 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s + +void f1(int x) { return; } +// CHECK: define void @f1(i32 signext %x) nounwind + +void f2(unsigned int x) { return; } +// CHECK: define void @f2(i32 zeroext %x) nounwind + +int f3(void) { return 0; } +// CHECK: define signext i32 @f3() nounwind + +unsigned int f4(void) { return 0; } +// CHECK: define zeroext i32 @f4() nounwind + |