Index: include/clang/CodeGen/CGFunctionInfo.h =================================================================== --- include/clang/CodeGen/CGFunctionInfo.h +++ include/clang/CodeGen/CGFunctionInfo.h @@ -22,8 +22,10 @@ #include "clang/AST/Decl.h" #include "clang/AST/Type.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Constants.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/Support/TrailingObjects.h" +#include "llvm/Support/type_traits.h" #include namespace clang { @@ -76,16 +78,20 @@ KindLast = InAlloca }; + enum class ExtendKind : unsigned { None = 1, SignExt = 2, ZeroExt = 3 }; + private: + llvm::Type *TypeData; // canHaveCoerceToType() union { llvm::Type *PaddingType; // canHavePaddingType() llvm::Type *UnpaddedCoerceAndExpandType; // isCoerceAndExpand() }; union { - unsigned DirectOffset; // isDirect() || isExtend() - unsigned IndirectAlign; // isIndirect() - unsigned AllocaFieldIndex; // isInAlloca() + llvm::ConstantDataArray *ExtendSeq; // isCoerceAndExpand() + unsigned DirectOffset; // isDirect() || isExtend() + unsigned IndirectAlign; // isIndirect() + unsigned AllocaFieldIndex; // isInAlloca() }; Kind TheKind; bool PaddingInReg : 1; @@ -110,13 +116,16 @@ UnpaddedCoerceAndExpandType = T; } - ABIArgInfo(Kind K) - : TheKind(K), PaddingInReg(false), InReg(false) { + void setExtendSet(llvm::ConstantDataArray *ES) { + assert(isCoerceAndExpand()); + ExtendSeq = ES; } + ABIArgInfo(Kind K) : TheKind(K), PaddingInReg(false), InReg(false) {} + public: ABIArgInfo() - : TypeData(nullptr), PaddingType(nullptr), DirectOffset(0), + : TypeData(nullptr), PaddingType(nullptr), ExtendSeq(nullptr), TheKind(Direct), PaddingInReg(false), InReg(false) {} static ABIArgInfo getDirect(llvm::Type *T = nullptr, unsigned Offset = 0, @@ -210,8 +219,15 @@ /// \param unpaddedCoerceToType The coerce-to type with padding elements /// removed, canonicalized to a single element if it would otherwise /// have exactly one element. - static ABIArgInfo getCoerceAndExpand(llvm::StructType *coerceToType, - llvm::Type *unpaddedCoerceToType) { + /// \param extendSet The extension to be applied to the expanded type. It is + // represented by a constant data array of integers where each integer + // is a value of ExtendKind. If null no extension is applied. If not null + // it has as many elements as unpaddedCoerceToType. Only integral-types can + // have an extension other than None. + static ABIArgInfo + getCoerceAndExpand(llvm::StructType *coerceToType, + llvm::Type *unpaddedCoerceToType, + llvm::ConstantDataArray *extendSet = nullptr) { #ifndef NDEBUG // Sanity checks on unpaddedCoerceToType. @@ -238,11 +254,38 @@ } else { assert(unpaddedIndex == 1); } + + if (extendSet) { + // Assert that the size of the extend struct agrees with the unpadded + // struct and it only attempts to extend integral types. + if (unpaddedStruct) { + assert(extendSet->getNumElements() == unpaddedStruct->getNumElements()); + unsigned Idx = 0; + for (auto EltType : unpaddedStruct->elements()) { + uint64_t ExtendType = extendSet->getElementAsInteger(Idx); + assert(ExtendType == static_cast(ExtendKind::None) || + (ExtendType == static_cast(ExtendKind::ZeroExt) || + ExtendType == static_cast(ExtendKind::SignExt)) && + EltType->isIntegerTy() && + "Invalid extend applied to non-integral type"); + Idx++; + } + } else { + assert(extendSet->getNumElements() == 1); + uint64_t ExtendType = extendSet->getElementAsInteger(0); + assert(ExtendType == static_cast(ExtendKind::None) || + (ExtendType == static_cast(ExtendKind::ZeroExt) || + ExtendType == static_cast(ExtendKind::SignExt)) && + unpaddedCoerceToType->isIntegerTy() && + "Invalid extend applied to non-integral type"); + } + } #endif auto AI = ABIArgInfo(CoerceAndExpand); AI.setCoerceToType(coerceToType); AI.setUnpaddedCoerceToType(unpaddedCoerceToType); + AI.setExtendSet(extendSet); return AI; } @@ -255,6 +298,15 @@ } } + static ExtendKind getExtendKind(uint64_t I) { + ExtendKind EK = static_cast(I); + if (EK == ExtendKind::None || EK == ExtendKind::SignExt || + EK == ExtendKind::ZeroExt) { + return EK; + } + llvm_unreachable("Unexpected integer kind"); + } + Kind getKind() const { return TheKind; } bool isDirect() const { return TheKind == Direct; } bool isInAlloca() const { return TheKind == InAlloca; } @@ -318,6 +370,11 @@ return UnpaddedCoerceAndExpandType; } + llvm::ConstantDataArray *getExtendSeq() const { + assert(isCoerceAndExpand()); + return ExtendSeq; + } + ArrayRefgetCoerceAndExpandTypeSequence() const { assert(isCoerceAndExpand()); if (auto structTy = @@ -409,6 +466,13 @@ void dump() const; }; +#if defined(LLVM_IS_TRIVIALLY_COPYABLE) +static_assert( + LLVM_IS_TRIVIALLY_COPYABLE(ABIArgInfo), + "ABIArgInfo must be trivially copyable as it is embedded as trailing " + "data of CGFunctionInfo"); +#endif + /// A class for recording the number of arguments that a function /// signature requires. class RequiredArgs { Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -1951,7 +1951,6 @@ case ABIArgInfo::CoerceAndExpand: break; - case ABIArgInfo::Expand: llvm_unreachable("Invalid ABI kind for return argument"); } @@ -1987,6 +1986,8 @@ llvm::AttributeSet::get(getLLVMContext(), Attrs); } + SmallVector CoerceAndExpandAttrs(IRFunctionArgs.totalIRArgs()); + bool CoerceAndExpandHasAttributes = false; unsigned ArgNo = 0; for (CGFunctionInfo::const_arg_iterator I = FI.arg_begin(), E = FI.arg_end(); @@ -2055,9 +2056,39 @@ } case ABIArgInfo::Ignore: case ABIArgInfo::Expand: - case ABIArgInfo::CoerceAndExpand: break; + case ABIArgInfo::CoerceAndExpand: + if (AI.getExtendSeq()) { + // Handle extends in expanded items + unsigned FirstIRArg, NumIRArgs; + std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo); + llvm::StructType *CoercionType = AI.getCoerceAndExpandType(); + for (unsigned I = 0, Ext = 0; I < NumIRArgs; I++) { + llvm::Type *EltType = CoercionType->getElementType(I); + if (ABIArgInfo::isPaddingForCoerceAndExpand(EltType)) + continue; + uint64_t ExtendKind = AI.getExtendSeq()->getElementAsInteger(Ext++); + switch (ABIArgInfo::getExtendKind(ExtendKind)) { + case ABIArgInfo::ExtendKind::None: + break; + case ABIArgInfo::ExtendKind::SignExt: { + CoerceAndExpandHasAttributes = true; + CoerceAndExpandAttrs[FirstIRArg + I].addAttribute( + llvm::Attribute::SExt); + break; + } + case ABIArgInfo::ExtendKind::ZeroExt: { + CoerceAndExpandHasAttributes = true; + CoerceAndExpandAttrs[FirstIRArg + I].addAttribute( + llvm::Attribute::ZExt); + break; + } + } + } + } + + break; case ABIArgInfo::InAlloca: // inalloca disables readnone and readonly. FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly) @@ -2112,12 +2143,16 @@ if (FI.getExtParameterInfo(ArgNo).isNoEscape()) Attrs.addAttribute(llvm::Attribute::NoCapture); - if (Attrs.hasAttributes()) { + if (Attrs.hasAttributes() || CoerceAndExpandHasAttributes) { unsigned FirstIRArg, NumIRArgs; std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo); for (unsigned i = 0; i < NumIRArgs; i++) + { + llvm::AttrBuilder CoerceAndExpandMergedAttrs(Attrs); + CoerceAndExpandMergedAttrs.merge(CoerceAndExpandAttrs[FirstIRArg + i]); ArgAttrs[FirstIRArg + i] = - llvm::AttributeSet::get(getLLVMContext(), Attrs); + llvm::AttributeSet::get(getLLVMContext(), CoerceAndExpandMergedAttrs); + } } } assert(ArgNo == FI.arg_size());