diff options
Diffstat (limited to 'include/clang/CodeGen/CGFunctionInfo.h')
-rw-r--r-- | include/clang/CodeGen/CGFunctionInfo.h | 237 |
1 files changed, 179 insertions, 58 deletions
diff --git a/include/clang/CodeGen/CGFunctionInfo.h b/include/clang/CodeGen/CGFunctionInfo.h index 96da0e9de1ad..449827e02891 100644 --- a/include/clang/CodeGen/CGFunctionInfo.h +++ b/include/clang/CodeGen/CGFunctionInfo.h @@ -19,21 +19,23 @@ #include "clang/AST/CanonicalType.h" #include "clang/AST/Type.h" #include "llvm/ADT/FoldingSet.h" - #include <cassert> namespace llvm { class Type; + class StructType; } namespace clang { +class Decl; + namespace CodeGen { /// ABIArgInfo - Helper class to encapsulate information about how a /// specific C type should be passed to or returned from a function. class ABIArgInfo { public: - enum Kind { + enum Kind : uint8_t { /// Direct - Pass the argument directly using the normal converted LLVM /// type, or by coercing to another specified type stored in /// 'CoerceToType'). If an offset is specified (in UIntData), then the @@ -60,86 +62,130 @@ public: /// are all scalar types or are themselves expandable types. Expand, - KindFirst=Direct, KindLast=Expand + /// InAlloca - Pass the argument directly using the LLVM inalloca attribute. + /// This is similar to 'direct', except it only applies to arguments stored + /// in memory and forbids any implicit copies. When applied to a return + /// type, it means the value is returned indirectly via an implicit sret + /// parameter stored in the argument struct. + InAlloca, + KindFirst = Direct, + KindLast = InAlloca }; private: - Kind TheKind; - llvm::Type *TypeData; + llvm::Type *TypeData; // isDirect() || isExtend() llvm::Type *PaddingType; - unsigned UIntData; - bool BoolData0; - bool BoolData1; - bool InReg; - bool PaddingInReg; + union { + unsigned DirectOffset; // isDirect() || isExtend() + unsigned IndirectAlign; // isIndirect() + unsigned AllocaFieldIndex; // isInAlloca() + }; + Kind TheKind; + bool PaddingInReg : 1; + bool InAllocaSRet : 1; // isInAlloca() + bool IndirectByVal : 1; // isIndirect() + bool IndirectRealign : 1; // isIndirect() + bool SRetAfterThis : 1; // isIndirect() + bool InReg : 1; // isDirect() || isExtend() || isIndirect() - ABIArgInfo(Kind K, llvm::Type *TD, unsigned UI, bool B0, bool B1, bool IR, - bool PIR, llvm::Type* P) - : TheKind(K), TypeData(TD), PaddingType(P), UIntData(UI), BoolData0(B0), - BoolData1(B1), InReg(IR), PaddingInReg(PIR) {} + ABIArgInfo(Kind K) + : PaddingType(nullptr), TheKind(K), PaddingInReg(false), InReg(false) {} public: - ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {} - - static ABIArgInfo getDirect(llvm::Type *T = 0, unsigned Offset = 0, - llvm::Type *Padding = 0) { - return ABIArgInfo(Direct, T, Offset, false, false, false, false, Padding); - } - static ABIArgInfo getDirectInReg(llvm::Type *T = 0) { - return ABIArgInfo(Direct, T, 0, false, false, true, false, 0); - } - static ABIArgInfo getExtend(llvm::Type *T = 0) { - return ABIArgInfo(Extend, T, 0, false, false, false, false, 0); - } - static ABIArgInfo getExtendInReg(llvm::Type *T = 0) { - return ABIArgInfo(Extend, T, 0, false, false, true, false, 0); + ABIArgInfo() + : TypeData(nullptr), PaddingType(nullptr), DirectOffset(0), + TheKind(Direct), PaddingInReg(false), InReg(false) {} + + static ABIArgInfo getDirect(llvm::Type *T = nullptr, unsigned Offset = 0, + llvm::Type *Padding = nullptr) { + auto AI = ABIArgInfo(Direct); + AI.setCoerceToType(T); + AI.setDirectOffset(Offset); + AI.setPaddingType(Padding); + return AI; + } + static ABIArgInfo getDirectInReg(llvm::Type *T = nullptr) { + auto AI = getDirect(T); + AI.setInReg(true); + return AI; + } + static ABIArgInfo getExtend(llvm::Type *T = nullptr) { + auto AI = ABIArgInfo(Extend); + AI.setCoerceToType(T); + AI.setDirectOffset(0); + return AI; + } + static ABIArgInfo getExtendInReg(llvm::Type *T = nullptr) { + auto AI = getExtend(T); + AI.setInReg(true); + return AI; } static ABIArgInfo getIgnore() { - return ABIArgInfo(Ignore, 0, 0, false, false, false, false, 0); - } - static ABIArgInfo getIndirect(unsigned Alignment, bool ByVal = true - , bool Realign = false - , llvm::Type *Padding = 0) { - return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, false, false, - Padding); - } - static ABIArgInfo getIndirectInReg(unsigned Alignment, bool ByVal = true - , bool Realign = false) { - return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, true, false, 0); + return ABIArgInfo(Ignore); + } + static ABIArgInfo getIndirect(unsigned Alignment, bool ByVal = true, + bool Realign = false, + llvm::Type *Padding = nullptr) { + auto AI = ABIArgInfo(Indirect); + AI.setIndirectAlign(Alignment); + AI.setIndirectByVal(ByVal); + AI.setIndirectRealign(Realign); + AI.setSRetAfterThis(false); + AI.setPaddingType(Padding); + return AI; + } + static ABIArgInfo getIndirectInReg(unsigned Alignment, bool ByVal = true, + bool Realign = false) { + auto AI = getIndirect(Alignment, ByVal, Realign); + AI.setInReg(true); + return AI; + } + static ABIArgInfo getInAlloca(unsigned FieldIndex) { + auto AI = ABIArgInfo(InAlloca); + AI.setInAllocaFieldIndex(FieldIndex); + return AI; } static ABIArgInfo getExpand() { - return ABIArgInfo(Expand, 0, 0, false, false, false, false, 0); + return ABIArgInfo(Expand); } static ABIArgInfo getExpandWithPadding(bool PaddingInReg, llvm::Type *Padding) { - return ABIArgInfo(Expand, 0, 0, false, false, false, PaddingInReg, - Padding); + auto AI = getExpand(); + AI.setPaddingInReg(PaddingInReg); + AI.setPaddingType(Padding); + return AI; } Kind getKind() const { return TheKind; } bool isDirect() const { return TheKind == Direct; } + bool isInAlloca() const { return TheKind == InAlloca; } bool isExtend() const { return TheKind == Extend; } bool isIgnore() const { return TheKind == Ignore; } bool isIndirect() const { return TheKind == Indirect; } bool isExpand() const { return TheKind == Expand; } - bool canHaveCoerceToType() const { - return TheKind == Direct || TheKind == Extend; - } + bool canHaveCoerceToType() const { return isDirect() || isExtend(); } // Direct/Extend accessors unsigned getDirectOffset() const { assert((isDirect() || isExtend()) && "Not a direct or extend kind"); - return UIntData; + return DirectOffset; } - - llvm::Type *getPaddingType() const { - return PaddingType; + void setDirectOffset(unsigned Offset) { + assert((isDirect() || isExtend()) && "Not a direct or extend kind"); + DirectOffset = Offset; } + llvm::Type *getPaddingType() const { return PaddingType; } + + void setPaddingType(llvm::Type *T) { PaddingType = T; } + bool getPaddingInReg() const { return PaddingInReg; } + void setPaddingInReg(bool PIR) { + PaddingInReg = PIR; + } llvm::Type *getCoerceToType() const { assert(canHaveCoerceToType() && "Invalid kind!"); @@ -156,20 +202,67 @@ public: return InReg; } + void setInReg(bool IR) { + assert((isDirect() || isExtend() || isIndirect()) && "Invalid kind!"); + InReg = IR; + } + // Indirect accessors unsigned getIndirectAlign() const { - assert(TheKind == Indirect && "Invalid kind!"); - return UIntData; + assert(isIndirect() && "Invalid kind!"); + return IndirectAlign; + } + void setIndirectAlign(unsigned IA) { + assert(isIndirect() && "Invalid kind!"); + IndirectAlign = IA; } bool getIndirectByVal() const { - assert(TheKind == Indirect && "Invalid kind!"); - return BoolData0; + assert(isIndirect() && "Invalid kind!"); + return IndirectByVal; + } + void setIndirectByVal(unsigned IBV) { + assert(isIndirect() && "Invalid kind!"); + IndirectByVal = IBV; } bool getIndirectRealign() const { - assert(TheKind == Indirect && "Invalid kind!"); - return BoolData1; + assert(isIndirect() && "Invalid kind!"); + return IndirectRealign; + } + void setIndirectRealign(bool IR) { + assert(isIndirect() && "Invalid kind!"); + IndirectRealign = IR; + } + + bool isSRetAfterThis() const { + assert(isIndirect() && "Invalid kind!"); + return SRetAfterThis; + } + void setSRetAfterThis(bool AfterThis) { + assert(isIndirect() && "Invalid kind!"); + SRetAfterThis = AfterThis; + } + + unsigned getInAllocaFieldIndex() const { + assert(isInAlloca() && "Invalid kind!"); + return AllocaFieldIndex; + } + void setInAllocaFieldIndex(unsigned FieldIndex) { + assert(isInAlloca() && "Invalid kind!"); + AllocaFieldIndex = FieldIndex; + } + + /// \brief Return true if this field of an inalloca struct should be returned + /// to implement a struct return calling convention. + bool getInAllocaSRet() const { + assert(isInAlloca() && "Invalid kind!"); + return InAllocaSRet; + } + + void setInAllocaSRet(bool SRet) { + assert(isInAlloca() && "Invalid kind!"); + InAllocaSRet = SRet; } void dump() const; @@ -195,7 +288,7 @@ public: static RequiredArgs forPrototypePlus(const FunctionProtoType *prototype, unsigned additional) { if (!prototype->isVariadic()) return All; - return RequiredArgs(prototype->getNumArgs() + additional); + return RequiredArgs(prototype->getNumParams() + additional); } static RequiredArgs forPrototype(const FunctionProtoType *prototype) { @@ -243,6 +336,9 @@ class CGFunctionInfo : public llvm::FoldingSetNode { /// The clang::CallingConv that this was originally created with. unsigned ASTCallingConvention : 8; + /// Whether this is an instance method. + unsigned InstanceMethod : 1; + /// Whether this function is noreturn. unsigned NoReturn : 1; @@ -255,6 +351,10 @@ class CGFunctionInfo : public llvm::FoldingSetNode { RequiredArgs Required; + /// 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 NumArgs; ArgInfo *getArgsBuffer() { return reinterpret_cast<ArgInfo*>(this+1); @@ -267,6 +367,7 @@ class CGFunctionInfo : public llvm::FoldingSetNode { public: static CGFunctionInfo *create(unsigned llvmCC, + bool InstanceMethod, const FunctionType::ExtInfo &extInfo, CanQualType resultType, ArrayRef<CanQualType> argTypes, @@ -275,6 +376,14 @@ public: typedef const ArgInfo *const_arg_iterator; typedef ArgInfo *arg_iterator; + typedef llvm::iterator_range<arg_iterator> arg_range; + typedef llvm::iterator_range<const_arg_iterator> arg_const_range; + + arg_range arguments() { return arg_range(arg_begin(), arg_end()); } + arg_const_range arguments() const { + return arg_const_range(arg_begin(), arg_end()); + } + const_arg_iterator arg_begin() const { return getArgsBuffer() + 1; } const_arg_iterator arg_end() const { return getArgsBuffer() + 1 + NumArgs; } arg_iterator arg_begin() { return getArgsBuffer() + 1; } @@ -285,6 +394,8 @@ public: bool isVariadic() const { return Required.allowsOptionalArgs(); } RequiredArgs getRequiredArgs() const { return Required; } + bool isInstanceMethod() const { return InstanceMethod; } + bool isNoReturn() const { return NoReturn; } /// In ARC, whether this function retains its return value. This @@ -325,23 +436,33 @@ public: ABIArgInfo &getReturnInfo() { return getArgsBuffer()[0].info; } const ABIArgInfo &getReturnInfo() const { return getArgsBuffer()[0].info; } + /// \brief Return true if this function uses inalloca arguments. + bool usesInAlloca() const { return ArgStruct; } + + /// \brief Get the struct type used to represent all the arguments in memory. + llvm::StructType *getArgStruct() const { return ArgStruct; } + void setArgStruct(llvm::StructType *Ty) { ArgStruct = Ty; } + void Profile(llvm::FoldingSetNodeID &ID) { ID.AddInteger(getASTCallingConvention()); + ID.AddBoolean(InstanceMethod); ID.AddBoolean(NoReturn); ID.AddBoolean(ReturnsRetained); ID.AddBoolean(HasRegParm); ID.AddInteger(RegParm); ID.AddInteger(Required.getOpaqueData()); getReturnType().Profile(ID); - for (arg_iterator it = arg_begin(), ie = arg_end(); it != ie; ++it) - it->type.Profile(ID); + for (const auto &I : arguments()) + I.type.Profile(ID); } static void Profile(llvm::FoldingSetNodeID &ID, + bool InstanceMethod, const FunctionType::ExtInfo &info, RequiredArgs required, CanQualType resultType, ArrayRef<CanQualType> argTypes) { ID.AddInteger(info.getCC()); + ID.AddBoolean(InstanceMethod); ID.AddBoolean(info.getNoReturn()); ID.AddBoolean(info.getProducesResult()); ID.AddBoolean(info.getHasRegParm()); |