summaryrefslogtreecommitdiff
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.h217
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) {