aboutsummaryrefslogtreecommitdiff
path: root/include/clang/CodeGen/CGFunctionInfo.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/CodeGen/CGFunctionInfo.h')
-rw-r--r--include/clang/CodeGen/CGFunctionInfo.h237
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());