diff options
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r-- | clang/lib/CodeGen/CGCXXABI.h | 5 | ||||
-rw-r--r-- | clang/lib/CodeGen/ItaniumCXXABI.cpp | 21 | ||||
-rw-r--r-- | clang/lib/CodeGen/MicrosoftCXXABI.cpp | 26 | ||||
-rw-r--r-- | clang/lib/CodeGen/TargetInfo.cpp | 145 |
4 files changed, 84 insertions, 113 deletions
diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h index 868c1f90930..b6e85ca7e77 100644 --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/lib/CodeGen/CGCXXABI.h @@ -93,8 +93,9 @@ public: /// when called virtually, and code generation does not support the case. virtual bool HasThisReturn(GlobalDecl GD) const { return false; } - /// Returns true if the given record type should be returned indirectly. - virtual bool isReturnTypeIndirect(const CXXRecordDecl *RD) const = 0; + /// If the C++ ABI requires the given type be returned in a particular way, + /// this method sets RetAI and returns true. + virtual bool classifyReturnType(CGFunctionInfo &FI) const = 0; /// Specify how one should pass an argument of a record type. enum RecordArgABI { diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 8fdcaee31c9..201a7534776 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -52,11 +52,7 @@ public: CGCXXABI(CGM), UseARMMethodPtrABI(UseARMMethodPtrABI), UseARMGuardVarABI(UseARMGuardVarABI) { } - bool isReturnTypeIndirect(const CXXRecordDecl *RD) const override { - // Structures with either a non-trivial destructor or a non-trivial - // copy constructor are always indirect. - return !RD->hasTrivialDestructor() || RD->hasNonTrivialCopyConstructor(); - } + bool classifyReturnType(CGFunctionInfo &FI) const override; RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const override { // Structures with either a non-trivial destructor or a non-trivial @@ -761,6 +757,21 @@ ItaniumCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF, return Result; } +bool ItaniumCXXABI::classifyReturnType(CGFunctionInfo &FI) const { + const CXXRecordDecl *RD = FI.getReturnType()->getAsCXXRecordDecl(); + if (!RD) + return false; + + // Return indirectly if we have a non-trivial copy ctor or non-trivial dtor. + if (RD->hasNonTrivialDestructor() || RD->hasNonTrivialCopyConstructor()) { + FI.getReturnInfo() = ABIArgInfo::getIndirect(0, /*ByVal=*/false); + return true; + } + + // Otherwise, use the normal C ABI rules. + return false; +} + /// The Itanium ABI requires non-zero initialization only for data /// member pointers, for which '0' is a valid offset. bool ItaniumCXXABI::isZeroInitializable(const MemberPointerType *MPT) { diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index bd56b732ec4..1b05b93b076 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -39,10 +39,7 @@ public: bool HasThisReturn(GlobalDecl GD) const override; - bool isReturnTypeIndirect(const CXXRecordDecl *RD) const override { - // Structures that are not C++03 PODs are always indirect. - return !RD->isPOD(); - } + bool classifyReturnType(CGFunctionInfo &FI) const override; RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const override; @@ -459,6 +456,27 @@ bool MicrosoftCXXABI::HasThisReturn(GlobalDecl GD) const { return isa<CXXConstructorDecl>(GD.getDecl()); } +bool MicrosoftCXXABI::classifyReturnType(CGFunctionInfo &FI) const { + const CXXRecordDecl *RD = FI.getReturnType()->getAsCXXRecordDecl(); + if (!RD) + return false; + + if (FI.isInstanceMethod()) { + // If it's an instance method, aggregates are always returned indirectly via + // the second parameter. + FI.getReturnInfo() = ABIArgInfo::getIndirect(0, /*ByVal=*/false); + FI.getReturnInfo().setSRetAfterThis(FI.isInstanceMethod()); + return true; + } else if (!RD->isPOD()) { + // If it's a free function, non-POD types are returned indirectly. + FI.getReturnInfo() = ABIArgInfo::getIndirect(0, /*ByVal=*/false); + return true; + } + + // Otherwise, use the C ABI rules. + return false; +} + void MicrosoftCXXABI::BuildConstructorSignature( const CXXConstructorDecl *Ctor, CXXCtorType Type, CanQualType &ResTy, SmallVectorImpl<CanQualType> &ArgTys) { diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 6f0df6bda11..5dc1a913fb4 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -48,22 +48,6 @@ static bool isAggregateTypeForABI(QualType T) { ABIInfo::~ABIInfo() {} -static bool isRecordReturnIndirect(const RecordType *RT, - CGCXXABI &CXXABI) { - const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); - if (!RD) - return false; - return CXXABI.isReturnTypeIndirect(RD); -} - - -static bool isRecordReturnIndirect(QualType T, CGCXXABI &CXXABI) { - const RecordType *RT = T->getAs<RecordType>(); - if (!RT) - return false; - return isRecordReturnIndirect(RT, CXXABI); -} - static CGCXXABI::RecordArgABI getRecordArgABI(const RecordType *RT, CGCXXABI &CXXABI) { const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); @@ -370,7 +354,8 @@ public: ABIArgInfo classifyArgumentType(QualType RetTy) const; void computeInfo(CGFunctionInfo &FI) const override { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + if (!getCXXABI().classifyReturnType(FI)) + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &I : FI.arguments()) I.info = classifyArgumentType(I.type); } @@ -391,14 +376,8 @@ llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, } ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty) const { - if (isAggregateTypeForABI(Ty)) { - // Records with non-trivial destructors/constructors should not be passed - // by value. - if (isRecordReturnIndirect(Ty, getCXXABI())) - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); - + if (isAggregateTypeForABI(Ty)) return ABIArgInfo::getIndirect(0); - } // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs<EnumType>()) @@ -449,11 +428,12 @@ class PNaClTargetCodeGenInfo : public TargetCodeGenInfo { }; void PNaClABIInfo::computeInfo(CGFunctionInfo &FI) const { + if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); - for (auto &I : FI.arguments()) - I.info = classifyArgumentType(I.type); - } + for (auto &I : FI.arguments()) + I.info = classifyArgumentType(I.type); +} llvm::Value *PNaClABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, CodeGenFunction &CGF) const { @@ -550,8 +530,7 @@ class X86_32ABIInfo : public ABIInfo { return (Size == 8 || Size == 16 || Size == 32 || Size == 64); } - bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context, - bool IsInstanceMethod) const; + bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context) const; /// getIndirectResult - Give a source type \arg Ty, return a suitable result /// such that the argument will be passed in memory. @@ -563,8 +542,7 @@ class X86_32ABIInfo : public ABIInfo { unsigned getTypeStackAlignInBytes(QualType Ty, unsigned Align) const; Class classify(QualType Ty) const; - ABIArgInfo classifyReturnType(QualType RetTy, CCState &State, - bool IsInstanceMethod) const; + ABIArgInfo classifyReturnType(QualType RetTy, CCState &State) const; ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const; bool shouldUseInReg(QualType Ty, CCState &State, bool &NeedsPadding) const; @@ -630,8 +608,8 @@ public: /// shouldReturnTypeInRegister - Determine if the given type should be /// passed in a register (for the Darwin ABI). -bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, ASTContext &Context, - bool IsInstanceMethod) const { +bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, + ASTContext &Context) const { uint64_t Size = Context.getTypeSize(Ty); // Type must be register sized. @@ -656,8 +634,7 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, ASTContext &Context, // Arrays are treated like records. if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) - return shouldReturnTypeInRegister(AT->getElementType(), Context, - IsInstanceMethod); + return shouldReturnTypeInRegister(AT->getElementType(), Context); // Otherwise, it must be a record type. const RecordType *RT = Ty->getAs<RecordType>(); @@ -665,11 +642,6 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, ASTContext &Context, // FIXME: Traverse bases here too. - // For thiscall conventions, structures will never be returned in - // a register. This is for compatibility with the MSVC ABI - if (IsWin32StructABI && IsInstanceMethod && RT->isStructureType()) - return false; - // Structure types are passed in register if all fields would be // passed in a register. for (const auto *FD : RT->getDecl()->fields()) { @@ -678,7 +650,7 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, ASTContext &Context, continue; // Check fields recursively. - if (!shouldReturnTypeInRegister(FD->getType(), Context, IsInstanceMethod)) + if (!shouldReturnTypeInRegister(FD->getType(), Context)) return false; } return true; @@ -694,8 +666,7 @@ ABIArgInfo X86_32ABIInfo::getIndirectReturnResult(CCState &State) const { return ABIArgInfo::getIndirect(/*Align=*/0, /*ByVal=*/false); } -ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, CCState &State, - bool IsInstanceMethod) const { +ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, CCState &State) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); @@ -726,9 +697,6 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, CCState &State, if (isAggregateTypeForABI(RetTy)) { if (const RecordType *RT = RetTy->getAs<RecordType>()) { - if (isRecordReturnIndirect(RT, getCXXABI())) - return getIndirectReturnResult(State); - // Structures with flexible arrays are always indirect. if (RT->getDecl()->hasFlexibleArrayMember()) return getIndirectReturnResult(State); @@ -740,7 +708,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, CCState &State, // Small structures which are register sized are generally returned // in a register. - if (shouldReturnTypeInRegister(RetTy, getContext(), IsInstanceMethod)) { + if (shouldReturnTypeInRegister(RetTy, getContext())) { uint64_t Size = getContext().getTypeSize(RetTy); // As a special-case, if the struct is a "single-element" struct, and @@ -989,16 +957,8 @@ void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const { else State.FreeRegs = DefaultNumRegisterParameters; - FI.getReturnInfo() = - classifyReturnType(FI.getReturnType(), State, FI.isInstanceMethod()); - - // On win32, swap the order of the first two parameters for instance methods - // which are sret behind the scenes to match MSVC. - if (IsWin32StructABI && FI.isInstanceMethod() && - FI.getReturnInfo().isIndirect()) { - assert(FI.arg_size() >= 1 && "instance method should have this"); - FI.getReturnInfo().setSRetAfterThis(true); - } + if (!getCXXABI().classifyReturnType(FI)) + FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), State); bool UsedInAlloca = false; for (auto &I : FI.arguments()) { @@ -2451,7 +2411,8 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType( void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + if (!getCXXABI().classifyReturnType(FI)) + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); // Keep track of the number of assigned registers. unsigned freeIntRegs = 6, freeSSERegs = 8; @@ -2722,10 +2683,7 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, bool IsReturnType) const { const RecordType *RT = Ty->getAs<RecordType>(); if (RT) { - if (IsReturnType) { - if (isRecordReturnIndirect(RT, getCXXABI())) - return ABIArgInfo::getIndirect(0, false); - } else { + if (!IsReturnType) { if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI())) return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory); } @@ -2764,17 +2722,8 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, bool IsReturnType) const { } void WinX86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const { - - QualType RetTy = FI.getReturnType(); - FI.getReturnInfo() = classify(RetTy, true); - - // On win64, swap the order of the first two parameters for instance methods - // which are sret behind the scenes to match MSVC. - if (FI.getReturnInfo().isIndirect() && FI.isInstanceMethod() && - getCXXABI().isSRetParameterAfterThis()) { - assert(FI.arg_size() >= 1 && "instance method should have this"); - FI.getReturnInfo().setSRetAfterThis(true); - } + if (!getCXXABI().classifyReturnType(FI)) + FI.getReturnInfo() = classify(FI.getReturnType(), true); for (auto &I : FI.arguments()) I.info = classify(I.type, false); @@ -2919,7 +2868,8 @@ public: // entry. This would require changing the logic in PPCISelLowering // when lowering the parameters in the caller and args in the callee. void computeInfo(CGFunctionInfo &FI) const override { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + if (!getCXXABI().classifyReturnType(FI)) + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &I : FI.arguments()) { // We rely on the default argument classification for the most part. // One exception: An aggregate containing a single floating-point @@ -3203,7 +3153,8 @@ private: FI.getRequiredArgs().getNumRequiredArgs() : FI.arg_size()); - FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + if (!getCXXABI().classifyReturnType(FI)) + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) { unsigned PreAllocation = AllocatedVFP, PreGPR = AllocatedGPR; @@ -3340,9 +3291,10 @@ ABIArgInfo ARM64ABIInfo::classifyArgumentType(QualType Ty, // Structures with either a non-trivial destructor or a non-trivial // copy constructor are always indirect. - if (isRecordReturnIndirect(Ty, getCXXABI())) { + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) { AllocatedGPR++; - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + return ABIArgInfo::getIndirect(0, /*ByVal=*/RAA == + CGCXXABI::RAA_DirectInMemory); } // Empty records are always ignored on Darwin, but actually passed in C++ mode @@ -3412,11 +3364,6 @@ ABIArgInfo ARM64ABIInfo::classifyReturnType(QualType RetTy) const { : ABIArgInfo::getDirect()); } - // Structures with either a non-trivial destructor or a non-trivial - // copy constructor are always indirect. - if (isRecordReturnIndirect(RetTy, getCXXABI())) - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); - if (isEmptyRecord(getContext(), RetTy, true)) return ABIArgInfo::getIgnore(); @@ -3905,7 +3852,12 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const { // unallocated are marked as unavailable. resetAllocatedRegs(); - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), FI.isVariadic()); + if (getCXXABI().classifyReturnType(FI)) { + if (FI.getReturnInfo().isIndirect()) + markAllocatedGPRs(1, 1); + } else { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), FI.isVariadic()); + } for (auto &I : FI.arguments()) { unsigned PreAllocationVFPs = AllocatedVFPs; unsigned PreAllocationGPRs = AllocatedGPRs; @@ -4368,13 +4320,6 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } - // Structures with either a non-trivial destructor or a non-trivial - // copy constructor are always indirect. - if (isRecordReturnIndirect(RetTy, getCXXABI())) { - markAllocatedGPRs(1, 1); - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); - } - // Are we following APCS? if (getABIKind() == APCS) { if (isEmptyRecord(getContext(), RetTy, false)) @@ -4834,7 +4779,8 @@ ABIArgInfo NVPTXABIInfo::classifyArgumentType(QualType Ty) const { } void NVPTXABIInfo::computeInfo(CGFunctionInfo &FI) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + if (!getCXXABI().classifyReturnType(FI)) + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &I : FI.arguments()) I.info = classifyArgumentType(I.type); @@ -4931,7 +4877,8 @@ public: ABIArgInfo classifyArgumentType(QualType ArgTy) const; void computeInfo(CGFunctionInfo &FI) const override { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + if (!getCXXABI().classifyReturnType(FI)) + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &I : FI.arguments()) I.info = classifyArgumentType(I.type); } @@ -5500,9 +5447,6 @@ ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const { return ABIArgInfo::getIgnore(); if (isAggregateTypeForABI(RetTy) || RetTy->isVectorType()) { - if (isRecordReturnIndirect(RetTy, getCXXABI())) - return ABIArgInfo::getIndirect(0); - if (Size <= 128) { if (RetTy->isAnyComplexType()) return ABIArgInfo::getDirect(); @@ -5528,7 +5472,8 @@ ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const { void MipsABIInfo::computeInfo(CGFunctionInfo &FI) const { ABIArgInfo &RetInfo = FI.getReturnInfo(); - RetInfo = classifyReturnType(FI.getReturnType()); + if (!getCXXABI().classifyReturnType(FI)) + RetInfo = classifyReturnType(FI.getReturnType()); // Check if a pointer to an aggregate is passed as a hidden argument. uint64_t Offset = RetInfo.isIndirect() ? MinABIStackAlignInBytes : 0; @@ -5696,7 +5641,8 @@ public: } void HexagonABIInfo::computeInfo(CGFunctionInfo &FI) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + if (!getCXXABI().classifyReturnType(FI)) + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &I : FI.arguments()) I.info = classifyArgumentType(I.type); } @@ -5749,11 +5695,6 @@ ABIArgInfo HexagonABIInfo::classifyReturnType(QualType RetTy) const { ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } - // Structures with either a non-trivial destructor or a non-trivial - // copy constructor are always indirect. - if (isRecordReturnIndirect(RetTy, getCXXABI())) - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); - if (isEmptyRecord(getContext(), RetTy, true)) return ABIArgInfo::getIgnore(); |