diff options
Diffstat (limited to 'include/clang/CodeGen/CGFunctionInfo.h')
| -rw-r--r-- | include/clang/CodeGen/CGFunctionInfo.h | 217 |
1 files changed, 186 insertions, 31 deletions
diff --git a/include/clang/CodeGen/CGFunctionInfo.h b/include/clang/CodeGen/CGFunctionInfo.h index bb6ceb43514eb..8dd6ad1c21ee8 100644 --- a/include/clang/CodeGen/CGFunctionInfo.h +++ b/include/clang/CodeGen/CGFunctionInfo.h @@ -16,20 +16,17 @@ #ifndef LLVM_CLANG_CODEGEN_CGFUNCTIONINFO_H #define LLVM_CLANG_CODEGEN_CGFUNCTIONINFO_H +#include "clang/AST/Attr.h" #include "clang/AST/CanonicalType.h" #include "clang/AST/CharUnits.h" +#include "clang/AST/Decl.h" #include "clang/AST/Type.h" +#include "llvm/IR/DerivedTypes.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/TrailingObjects.h" #include <cassert> -namespace llvm { - class Type; - class StructType; -} - namespace clang { -class Decl; - namespace CodeGen { /// ABIArgInfo - Helper class to encapsulate information about how a @@ -63,6 +60,12 @@ public: /// are all scalar types or are themselves expandable types. Expand, + /// CoerceAndExpand - Only valid for aggregate argument types. The + /// structure should be expanded into consecutive arguments corresponding + /// to the non-array elements of the type stored in CoerceToType. + /// Array elements in the type are assumed to be padding and skipped. + CoerceAndExpand, + /// InAlloca - Pass the argument directly using the LLVM inalloca attribute. /// This is similar to indirect with byval, except it only applies to /// arguments stored in memory and forbids any implicit copies. When @@ -74,8 +77,11 @@ public: }; private: - llvm::Type *TypeData; // isDirect() || isExtend() - llvm::Type *PaddingType; + llvm::Type *TypeData; // canHaveCoerceToType() + union { + llvm::Type *PaddingType; // canHavePaddingType() + llvm::Type *UnpaddedCoerceAndExpandType; // isCoerceAndExpand() + }; union { unsigned DirectOffset; // isDirect() || isExtend() unsigned IndirectAlign; // isIndirect() @@ -90,8 +96,22 @@ private: bool InReg : 1; // isDirect() || isExtend() || isIndirect() bool CanBeFlattened: 1; // isDirect() + bool canHavePaddingType() const { + return isDirect() || isExtend() || isIndirect() || isExpand(); + } + void setPaddingType(llvm::Type *T) { + assert(canHavePaddingType()); + PaddingType = T; + } + + void setUnpaddedCoerceToType(llvm::Type *T) { + assert(isCoerceAndExpand()); + UnpaddedCoerceAndExpandType = T; + } + ABIArgInfo(Kind K) - : PaddingType(nullptr), TheKind(K), PaddingInReg(false), InReg(false) {} + : TheKind(K), PaddingInReg(false), InReg(false) { + } public: ABIArgInfo() @@ -103,8 +123,8 @@ public: bool CanBeFlattened = true) { auto AI = ABIArgInfo(Direct); AI.setCoerceToType(T); - AI.setDirectOffset(Offset); AI.setPaddingType(Padding); + AI.setDirectOffset(Offset); AI.setCanBeFlattened(CanBeFlattened); return AI; } @@ -116,6 +136,7 @@ public: static ABIArgInfo getExtend(llvm::Type *T = nullptr) { auto AI = ABIArgInfo(Extend); AI.setCoerceToType(T); + AI.setPaddingType(nullptr); AI.setDirectOffset(0); return AI; } @@ -150,7 +171,9 @@ public: return AI; } static ABIArgInfo getExpand() { - return ABIArgInfo(Expand); + auto AI = ABIArgInfo(Expand); + AI.setPaddingType(nullptr); + return AI; } static ABIArgInfo getExpandWithPadding(bool PaddingInReg, llvm::Type *Padding) { @@ -160,6 +183,54 @@ public: return AI; } + /// \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) { +#ifndef NDEBUG + // Sanity checks on unpaddedCoerceToType. + + // Assert that we only have a struct type if there are multiple elements. + auto unpaddedStruct = dyn_cast<llvm::StructType>(unpaddedCoerceToType); + assert(!unpaddedStruct || unpaddedStruct->getNumElements() != 1); + + // Assert that all the non-padding elements have a corresponding element + // in the unpadded type. + unsigned unpaddedIndex = 0; + for (auto eltType : coerceToType->elements()) { + if (isPaddingForCoerceAndExpand(eltType)) continue; + if (unpaddedStruct) { + assert(unpaddedStruct->getElementType(unpaddedIndex) == eltType); + } else { + assert(unpaddedIndex == 0 && unpaddedCoerceToType == eltType); + } + unpaddedIndex++; + } + + // Assert that there aren't extra elements in the unpadded type. + if (unpaddedStruct) { + assert(unpaddedStruct->getNumElements() == unpaddedIndex); + } else { + assert(unpaddedIndex == 1); + } +#endif + + auto AI = ABIArgInfo(CoerceAndExpand); + AI.setCoerceToType(coerceToType); + AI.setUnpaddedCoerceToType(unpaddedCoerceToType); + return AI; + } + + static bool isPaddingForCoerceAndExpand(llvm::Type *eltType) { + if (eltType->isArrayTy()) { + assert(eltType->getArrayElementType()->isIntegerTy(8)); + return true; + } else { + return false; + } + } + Kind getKind() const { return TheKind; } bool isDirect() const { return TheKind == Direct; } bool isInAlloca() const { return TheKind == InAlloca; } @@ -167,8 +238,11 @@ public: bool isIgnore() const { return TheKind == Ignore; } bool isIndirect() const { return TheKind == Indirect; } bool isExpand() const { return TheKind == Expand; } + bool isCoerceAndExpand() const { return TheKind == CoerceAndExpand; } - bool canHaveCoerceToType() const { return isDirect() || isExtend(); } + bool canHaveCoerceToType() const { + return isDirect() || isExtend() || isCoerceAndExpand(); + } // Direct/Extend accessors unsigned getDirectOffset() const { @@ -180,9 +254,9 @@ public: DirectOffset = Offset; } - llvm::Type *getPaddingType() const { return PaddingType; } - - void setPaddingType(llvm::Type *T) { PaddingType = T; } + llvm::Type *getPaddingType() const { + return (canHavePaddingType() ? PaddingType : nullptr); + } bool getPaddingInReg() const { return PaddingInReg; @@ -201,6 +275,26 @@ public: TypeData = T; } + llvm::StructType *getCoerceAndExpandType() const { + assert(isCoerceAndExpand()); + return cast<llvm::StructType>(TypeData); + } + + llvm::Type *getUnpaddedCoerceAndExpandType() const { + assert(isCoerceAndExpand()); + return UnpaddedCoerceAndExpandType; + } + + ArrayRef<llvm::Type *>getCoerceAndExpandTypeSequence() const { + assert(isCoerceAndExpand()); + if (auto structTy = + dyn_cast<llvm::StructType>(UnpaddedCoerceAndExpandType)) { + return structTy->elements(); + } else { + return llvm::makeArrayRef(&UnpaddedCoerceAndExpandType, 1); + } + } + bool getInReg() const { assert((isDirect() || isExtend() || isIndirect()) && "Invalid kind!"); return InReg; @@ -299,23 +393,34 @@ public: /// Compute the arguments required by the given formal prototype, /// given that there may be some additional, non-formal arguments /// in play. + /// + /// If FD is not null, this will consider pass_object_size params in FD. static RequiredArgs forPrototypePlus(const FunctionProtoType *prototype, - unsigned additional) { + unsigned additional, + const FunctionDecl *FD) { if (!prototype->isVariadic()) return All; + if (FD) + additional += + llvm::count_if(FD->parameters(), [](const ParmVarDecl *PVD) { + return PVD->hasAttr<PassObjectSizeAttr>(); + }); return RequiredArgs(prototype->getNumParams() + additional); } - static RequiredArgs forPrototype(const FunctionProtoType *prototype) { - return forPrototypePlus(prototype, 0); + static RequiredArgs forPrototype(const FunctionProtoType *prototype, + const FunctionDecl *FD) { + return forPrototypePlus(prototype, 0, FD); } - static RequiredArgs forPrototype(CanQual<FunctionProtoType> prototype) { - return forPrototype(prototype.getTypePtr()); + static RequiredArgs forPrototype(CanQual<FunctionProtoType> prototype, + const FunctionDecl *FD) { + return forPrototype(prototype.getTypePtr(), FD); } static RequiredArgs forPrototypePlus(CanQual<FunctionProtoType> prototype, - unsigned additional) { - return forPrototypePlus(prototype.getTypePtr(), additional); + unsigned additional, + const FunctionDecl *FD) { + return forPrototypePlus(prototype.getTypePtr(), additional, FD); } bool allowsOptionalArgs() const { return NumRequired != ~0U; } @@ -331,13 +436,21 @@ public: } }; +// Implementation detail of CGFunctionInfo, factored out so it can be named +// in the TrailingObjects base class of CGFunctionInfo. +struct CGFunctionInfoArgInfo { + CanQualType type; + ABIArgInfo info; +}; + /// CGFunctionInfo - Class to encapsulate the information about a /// function definition. -class CGFunctionInfo : public llvm::FoldingSetNode { - struct ArgInfo { - CanQualType type; - ABIArgInfo info; - }; +class CGFunctionInfo final + : public llvm::FoldingSetNode, + private llvm::TrailingObjects<CGFunctionInfo, CGFunctionInfoArgInfo, + FunctionProtoType::ExtParameterInfo> { + typedef CGFunctionInfoArgInfo ArgInfo; + typedef FunctionProtoType::ExtParameterInfo ExtParameterInfo; /// The LLVM::CallingConv to use for this function (as specified by the /// user). @@ -371,14 +484,23 @@ class CGFunctionInfo : public llvm::FoldingSetNode { /// The struct representing all arguments passed in memory. Only used when /// passing non-trivial types with inalloca. Not part of the profile. llvm::StructType *ArgStruct; - unsigned ArgStructAlign; + unsigned ArgStructAlign : 31; + unsigned HasExtParameterInfos : 1; unsigned NumArgs; + ArgInfo *getArgsBuffer() { - return reinterpret_cast<ArgInfo*>(this+1); + return getTrailingObjects<ArgInfo>(); } const ArgInfo *getArgsBuffer() const { - return reinterpret_cast<const ArgInfo*>(this + 1); + return getTrailingObjects<ArgInfo>(); + } + + ExtParameterInfo *getExtParameterInfosBuffer() { + return getTrailingObjects<ExtParameterInfo>(); + } + const ExtParameterInfo *getExtParameterInfosBuffer() const{ + return getTrailingObjects<ExtParameterInfo>(); } CGFunctionInfo() : Required(RequiredArgs::All) {} @@ -388,9 +510,21 @@ public: bool instanceMethod, bool chainCall, const FunctionType::ExtInfo &extInfo, + ArrayRef<ExtParameterInfo> paramInfos, CanQualType resultType, ArrayRef<CanQualType> argTypes, RequiredArgs required); + void operator delete(void *p) { ::operator delete(p); } + + // Friending class TrailingObjects is apparently not good enough for MSVC, + // so these have to be public. + friend class TrailingObjects; + size_t numTrailingObjects(OverloadToken<ArgInfo>) const { + return NumArgs + 1; + } + size_t numTrailingObjects(OverloadToken<ExtParameterInfo>) const { + return (HasExtParameterInfos ? NumArgs : 0); + } typedef const ArgInfo *const_arg_iterator; typedef ArgInfo *arg_iterator; @@ -460,6 +594,16 @@ public: ABIArgInfo &getReturnInfo() { return getArgsBuffer()[0].info; } const ABIArgInfo &getReturnInfo() const { return getArgsBuffer()[0].info; } + ArrayRef<ExtParameterInfo> getExtParameterInfos() const { + if (!HasExtParameterInfos) return {}; + return llvm::makeArrayRef(getExtParameterInfosBuffer(), NumArgs); + } + ExtParameterInfo getExtParameterInfo(unsigned argIndex) const { + assert(argIndex <= NumArgs); + if (!HasExtParameterInfos) return ExtParameterInfo(); + return getExtParameterInfos()[argIndex]; + } + /// \brief Return true if this function uses inalloca arguments. bool usesInAlloca() const { return ArgStruct; } @@ -482,6 +626,11 @@ public: ID.AddBoolean(HasRegParm); ID.AddInteger(RegParm); ID.AddInteger(Required.getOpaqueData()); + ID.AddBoolean(HasExtParameterInfos); + if (HasExtParameterInfos) { + for (auto paramInfo : getExtParameterInfos()) + ID.AddInteger(paramInfo.getOpaqueValue()); + } getReturnType().Profile(ID); for (const auto &I : arguments()) I.type.Profile(ID); @@ -490,6 +639,7 @@ public: bool InstanceMethod, bool ChainCall, const FunctionType::ExtInfo &info, + ArrayRef<ExtParameterInfo> paramInfos, RequiredArgs required, CanQualType resultType, ArrayRef<CanQualType> argTypes) { @@ -501,6 +651,11 @@ public: ID.AddBoolean(info.getHasRegParm()); ID.AddInteger(info.getRegParm()); ID.AddInteger(required.getOpaqueData()); + ID.AddBoolean(!paramInfos.empty()); + if (!paramInfos.empty()) { + for (auto paramInfo : paramInfos) + ID.AddInteger(paramInfo.getOpaqueValue()); + } resultType.Profile(ID); for (ArrayRef<CanQualType>::iterator i = argTypes.begin(), e = argTypes.end(); i != e; ++i) { |
