aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen')
-rw-r--r--lib/CodeGen/CGCall.cpp13
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp186
-rw-r--r--lib/CodeGen/CodeGenTypes.h41
3 files changed, 172 insertions, 68 deletions
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 39a143feec..e770099058 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -265,9 +265,15 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
ArgTys.data(), ArgTys.size());
FunctionInfos.InsertNode(FI, InsertPos);
+ bool Inserted = FunctionsBeingProcessed.insert(FI); (void)Inserted;
+ assert(Inserted && "Recursively being processed?");
+
// Compute ABI information.
getABIInfo().computeInfo(*FI);
+ bool Erased = FunctionsBeingProcessed.erase(FI); (void)Erased;
+ assert(Erased && "Not in set?");
+
// Loop over all of the computed argument and return value info. If any of
// them are direct or extend without a specified coerce type, specify the
// default now.
@@ -604,6 +610,10 @@ llvm::FunctionType *CodeGenTypes::GetFunctionType(GlobalDecl GD) {
llvm::FunctionType *
CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic) {
+
+ bool Inserted = FunctionsBeingProcessed.insert(&FI); (void)Inserted;
+ assert(Inserted && "Recursively being processed?");
+
llvm::SmallVector<llvm::Type*, 8> argTypes;
const llvm::Type *resultType = 0;
@@ -669,6 +679,9 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic) {
}
}
+ bool Erased = FunctionsBeingProcessed.erase(&FI); (void)Erased;
+ assert(Erased && "Not in set?");
+
return llvm::FunctionType::get(resultType, argTypes, isVariadic);
}
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 8dae84e48f..764688fcb1 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -31,7 +31,6 @@ CodeGenTypes::CodeGenTypes(ASTContext &Ctx, llvm::Module& M,
CGCXXABI &CXXABI, const CodeGenOptions &CGO)
: Context(Ctx), Target(Ctx.Target), TheModule(M), TheTargetData(TD),
TheABIInfo(Info), TheCXXABI(CXXABI), CodeGenOpts(CGO) {
- RecursionState = RS_Normal;
SkippedLayout = false;
}
@@ -94,27 +93,114 @@ llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T){
(unsigned)Context.getTypeSize(T));
}
+
+/// isRecordLayoutComplete - Return true if the specified type is already
+/// completely laid out.
+bool CodeGenTypes::isRecordLayoutComplete(const Type *Ty) const {
+ llvm::DenseMap<const Type*, llvm::StructType *>::const_iterator I =
+ RecordDeclTypes.find(Ty);
+ return I != RecordDeclTypes.end() && !I->second->isOpaque();
+}
+
+static bool
+isSafeToConvert(QualType T, CodeGenTypes &CGT,
+ llvm::SmallPtrSet<const RecordDecl*, 16> &AlreadyChecked);
+
+
+/// isSafeToConvert - Return true if it is safe to convert the specified record
+/// decl to IR and lay it out, false if doing so would cause us to get into a
+/// recursive compilation mess.
+static bool
+isSafeToConvert(const RecordDecl *RD, CodeGenTypes &CGT,
+ llvm::SmallPtrSet<const RecordDecl*, 16> &AlreadyChecked) {
+ // If we have already checked this type (maybe the same type is used by-value
+ // multiple times in multiple structure fields, don't check again.
+ if (!AlreadyChecked.insert(RD)) return true;
+
+ const Type *Key = CGT.getContext().getTagDeclType(RD).getTypePtr();
+
+ // If this type is already laid out, converting it is a noop.
+ if (CGT.isRecordLayoutComplete(Key)) return true;
+
+ // If this type is currently being laid out, we can't recursively compile it.
+ if (CGT.isRecordBeingLaidOut(Key))
+ return false;
+
+ // If this type would require laying out bases that are currently being laid
+ // out, don't do it. This includes virtual base classes which get laid out
+ // when a class is translated, even though they aren't embedded by-value into
+ // the class.
+ if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
+ for (CXXRecordDecl::base_class_const_iterator I = CRD->bases_begin(),
+ E = CRD->bases_end(); I != E; ++I)
+ if (!isSafeToConvert(I->getType()->getAs<RecordType>()->getDecl(),
+ CGT, AlreadyChecked))
+ return false;
+ }
+
+ // If this type would require laying out members that are currently being laid
+ // out, don't do it.
+ for (RecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end(); I != E; ++I)
+ if (!isSafeToConvert(I->getType(), CGT, AlreadyChecked))
+ return false;
+
+ // If there are no problems, lets do it.
+ return true;
+}
+
+/// isSafeToConvert - Return true if it is safe to convert this field type,
+/// which requires the structure elements contained by-value to all be
+/// recursively safe to convert.
+static bool
+isSafeToConvert(QualType T, CodeGenTypes &CGT,
+ llvm::SmallPtrSet<const RecordDecl*, 16> &AlreadyChecked) {
+ T = T.getCanonicalType();
+
+ // If this is a record, check it.
+ if (const RecordType *RT = dyn_cast<RecordType>(T))
+ return isSafeToConvert(RT->getDecl(), CGT, AlreadyChecked);
+
+ // If this is an array, check the elements, which are embedded inline.
+ if (const ArrayType *AT = dyn_cast<ArrayType>(T))
+ return isSafeToConvert(AT->getElementType(), CGT, AlreadyChecked);
+
+ // Otherwise, there is no concern about transforming this. We only care about
+ // things that are contained by-value in a structure that can have another
+ // structure as a member.
+ return true;
+}
+
+
+/// isSafeToConvert - Return true if it is safe to convert the specified record
+/// decl to IR and lay it out, false if doing so would cause us to get into a
+/// recursive compilation mess.
+static bool isSafeToConvert(const RecordDecl *RD, CodeGenTypes &CGT) {
+ // If no structs are being laid out, we can certainly do this one.
+ if (CGT.noRecordsBeingLaidOut()) return true;
+
+ llvm::SmallPtrSet<const RecordDecl*, 16> AlreadyChecked;
+ return isSafeToConvert(RD, CGT, AlreadyChecked);
+}
+
+
/// isFuncTypeArgumentConvertible - Return true if the specified type in a
/// function argument or result position can be converted to an IR type at this
/// point. This boils down to being whether it is complete, as well as whether
/// we've temporarily deferred expanding the type because we're in a recursive
/// context.
-bool CodeGenTypes::isFuncTypeArgumentConvertible(QualType Ty){
+bool CodeGenTypes::isFuncTypeArgumentConvertible(QualType Ty) {
// If this isn't a tagged type, we can convert it!
const TagType *TT = Ty->getAs<TagType>();
if (TT == 0) return true;
- // If it's a tagged type, but is a forward decl, we can't convert it.
- if (!TT->getDecl()->isDefinition())
+ // If it's a tagged type used by-value, but is just a forward decl, we can't
+ // convert it. Note that getDefinition()==0 is not the same as !isDefinition.
+ if (TT->getDecl()->getDefinition() == 0)
return false;
- // If we're not under a pointer under a struct, then we can convert it if
- // needed.
- if (RecursionState != RS_StructPointer)
- return true;
-
- // If this is an enum, then it is safe to convert.
+ // If this is an enum, then it is always safe to convert.
const RecordType *RT = dyn_cast<RecordType>(TT);
if (RT == 0) return true;
@@ -125,7 +211,7 @@ bool CodeGenTypes::isFuncTypeArgumentConvertible(QualType Ty){
//
// We decide this by checking whether ConvertRecordDeclType returns us an
// opaque type for a struct that we know is defined.
- return !ConvertRecordDeclType(RT->getDecl())->isOpaque();
+ return isSafeToConvert(RT->getDecl(), *this);
}
@@ -289,7 +375,6 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
}
case Type::LValueReference:
case Type::RValueReference: {
- RecursionStatePointerRAII X(RecursionState);
const ReferenceType *RTy = cast<ReferenceType>(Ty);
QualType ETy = RTy->getPointeeType();
llvm::Type *PointeeType = ConvertTypeForMem(ETy);
@@ -298,7 +383,6 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
break;
}
case Type::Pointer: {
- RecursionStatePointerRAII X(RecursionState);
const PointerType *PTy = cast<PointerType>(Ty);
QualType ETy = PTy->getPointeeType();
llvm::Type *PointeeType = ConvertTypeForMem(ETy);
@@ -347,49 +431,62 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
}
case Type::FunctionNoProto:
case Type::FunctionProto: {
+ const FunctionType *FT = cast<FunctionType>(Ty);
// First, check whether we can build the full function type. If the
// function type depends on an incomplete type (e.g. a struct or enum), we
// cannot lower the function type.
- if (RecursionState == RS_StructPointer ||
- !isFuncTypeConvertible(cast<FunctionType>(Ty))) {
+ if (!isFuncTypeConvertible(FT)) {
// This function's type depends on an incomplete tag type.
// Return a placeholder type.
ResultType = llvm::StructType::get(getLLVMContext());
- SkippedLayout |= RecursionState == RS_StructPointer;
+ SkippedLayout = true;
break;
}
// While we're converting the argument types for a function, we don't want
// to recursively convert any pointed-to structs. Converting directly-used
// structs is ok though.
- RecursionStateTy SavedRecursionState = RecursionState;
- RecursionState = RS_Struct;
+ if (!RecordsBeingLaidOut.insert(Ty)) {
+ ResultType = llvm::StructType::get(getLLVMContext());
+
+ SkippedLayout = true;
+ break;
+ }
// The function type can be built; call the appropriate routines to
// build it.
const CGFunctionInfo *FI;
bool isVariadic;
- if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(Ty)) {
+ if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT)) {
FI = &getFunctionInfo(
CanQual<FunctionProtoType>::CreateUnsafe(QualType(FPT, 0)));
isVariadic = FPT->isVariadic();
} else {
- const FunctionNoProtoType *FNPT = cast<FunctionNoProtoType>(Ty);
+ const FunctionNoProtoType *FNPT = cast<FunctionNoProtoType>(FT);
FI = &getFunctionInfo(
CanQual<FunctionNoProtoType>::CreateUnsafe(QualType(FNPT, 0)));
isVariadic = true;
}
- ResultType = GetFunctionType(*FI, isVariadic);
-
- // Restore our recursion state.
- RecursionState = SavedRecursionState;
+ // If there is something higher level prodding our CGFunctionInfo, then
+ // don't recurse into it again.
+ if (FunctionsBeingProcessed.count(FI)) {
+
+ ResultType = llvm::StructType::get(getLLVMContext());
+ SkippedLayout = true;
+ } else {
+
+ // Otherwise, we're good to go, go ahead and convert it.
+ ResultType = GetFunctionType(*FI, isVariadic);
+ }
+
+ RecordsBeingLaidOut.erase(Ty);
if (SkippedLayout)
TypeCache.clear();
- if (RecursionState == RS_Normal)
+ if (RecordsBeingLaidOut.empty())
while (!DeferredRecords.empty())
ConvertRecordDeclType(DeferredRecords.pop_back_val());
break;
@@ -411,7 +508,6 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
}
case Type::ObjCObjectPointer: {
- RecursionStatePointerRAII X(RecursionState);
// Protocol qualifications do not influence the LLVM type, we just return a
// pointer to the underlying interface type. We don't need to worry about
// recursive conversion.
@@ -433,7 +529,6 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
}
case Type::BlockPointer: {
- RecursionStatePointerRAII X(RecursionState);
const QualType FTy = cast<BlockPointerType>(Ty)->getPointeeType();
llvm::Type *PointeeType = ConvertTypeForMem(FTy);
unsigned AS = Context.getTargetAddressSpace(FTy);
@@ -471,29 +566,27 @@ llvm::StructType *CodeGenTypes::ConvertRecordDeclType(const RecordDecl *RD) {
// If this is still a forward declaration, or the LLVM type is already
// complete, there's nothing more to do.
- if (!RD->isDefinition() || !Ty->isOpaque())
+ RD = RD->getDefinition();
+ if (RD == 0 || !Ty->isOpaque())
return Ty;
- // If we're recursively nested inside the conversion of a pointer inside the
- // struct, defer conversion.
- if (RecursionState == RS_StructPointer) {
+ // If converting this type would cause us to infinitely loop, don't do it!
+ if (!isSafeToConvert(RD, *this)) {
DeferredRecords.push_back(RD);
return Ty;
}
// Okay, this is a definition of a type. Compile the implementation now.
- RecursionStateTy SavedRecursionState = RecursionState;
- RecursionState = RS_Struct;
-
+ bool InsertResult = RecordsBeingLaidOut.insert(Key); (void)InsertResult;
+ assert(InsertResult && "Recursively compiling a struct?");
+
// Force conversion of non-virtual base classes recursively.
if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
for (CXXRecordDecl::base_class_const_iterator i = CRD->bases_begin(),
e = CRD->bases_end(); i != e; ++i) {
- if (!i->isVirtual()) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- ConvertRecordDeclType(Base);
- }
+ if (i->isVirtual()) continue;
+
+ ConvertRecordDeclType(i->getType()->getAs<RecordType>()->getDecl());
}
}
@@ -501,18 +594,19 @@ llvm::StructType *CodeGenTypes::ConvertRecordDeclType(const RecordDecl *RD) {
CGRecordLayout *Layout = ComputeRecordLayout(RD, Ty);
CGRecordLayouts[Key] = Layout;
+ // We're done laying out this struct.
+ bool EraseResult = RecordsBeingLaidOut.erase(Key); (void)EraseResult;
+ assert(EraseResult && "struct not in RecordsBeingLaidOut set?");
+
// If this struct blocked a FunctionType conversion, then recompute whatever
// was derived from that.
// FIXME: This is hugely overconservative.
if (SkippedLayout)
TypeCache.clear();
-
-
- // Restore our recursion state. If we're done converting the outer-most
- // record, then convert any deferred structs as well.
- RecursionState = SavedRecursionState;
-
- if (RecursionState == RS_Normal)
+
+ // If we're done converting the outer-most record, then convert any deferred
+ // structs as well.
+ if (RecordsBeingLaidOut.empty())
while (!DeferredRecords.empty())
ConvertRecordDeclType(DeferredRecords.pop_back_val());
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index 4229c59b83..7c0fb81643 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -81,32 +81,20 @@ class CodeGenTypes {
/// FunctionInfos - Hold memoized CGFunctionInfo results.
llvm::FoldingSet<CGFunctionInfo> FunctionInfos;
- enum RecursionStateTy {
- RS_Normal, // Normal type conversion.
- RS_Struct, // Recursively inside a struct conversion.
- RS_StructPointer // Recursively inside a pointer in a struct.
- } RecursionState;
-
- /// SkippedLayout - True if we didn't layout a function bit due to a
- /// RS_StructPointer RecursionState.
+ /// RecordsBeingLaidOut - This set keeps track of records that we're currently
+ /// converting to an IR type. For example, when converting:
+ /// struct A { struct B { int x; } } when processing 'x', the 'A' and 'B'
+ /// types will be in this set.
+ llvm::SmallPtrSet<const Type*, 4> RecordsBeingLaidOut;
+
+ llvm::SmallPtrSet<const CGFunctionInfo*, 4> FunctionsBeingProcessed;
+
+ /// SkippedLayout - True if we didn't layout a function due to a being inside
+ /// a recursive struct conversion, set this to true.
bool SkippedLayout;
llvm::SmallVector<const RecordDecl *, 8> DeferredRecords;
- struct RecursionStatePointerRAII {
- RecursionStateTy &Val;
- RecursionStateTy Saved;
-
- RecursionStatePointerRAII(RecursionStateTy &V) : Val(V), Saved(V) {
- if (Val == RS_Struct)
- Val = RS_StructPointer;
- }
-
- ~RecursionStatePointerRAII() {
- Val = Saved;
- }
- };
-
private:
/// TypeCache - This map keeps cache of llvm::Types
/// and maps llvm::Types to corresponding clang::Type.
@@ -232,6 +220,15 @@ public: // These are internal details of CGT that shouldn't be used externally.
/// IsZeroInitializable - Return whether a record type can be
/// zero-initialized (in the C++ sense) with an LLVM zeroinitializer.
bool isZeroInitializable(const CXXRecordDecl *RD);
+
+ bool isRecordLayoutComplete(const Type *Ty) const;
+ bool noRecordsBeingLaidOut() const {
+ return RecordsBeingLaidOut.empty();
+ }
+ bool isRecordBeingLaidOut(const Type *Ty) const {
+ return RecordsBeingLaidOut.count(Ty);
+ }
+
};
} // end namespace CodeGen