Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Revived metadata support and gc2stack. #206

Merged
merged 8 commits into from

1 participant

@klickverbot
Owner

No description provided.

@klickverbot
Owner

Found the culprit of the test suite failures (the promoted value is arg to a LLVM tail call function), will cook up a fix tomorrow.

@klickverbot
Owner

Darn, the DtoType call added in the typeinfo building function breaks funclit on x86 (32 bit) builds – somehow, this messes up the type system to the point where the inreg attribute for the context pointer is instead applied to the additional lambda parameter.

klickverbot added some commits
@klickverbot klickverbot Renamed IrType::get/IrType::getD, treat classes as the special case t…
…hey are.
464c695
@klickverbot klickverbot Refactored IrType construction to use static get() method.
This also allows us to enable the assert in IrType::IrType.

Unfortunately, this is mostly a "peace of mind" commit, there
doesn't seem to have been a bug actually caused by the transitory
duplicate IrTypePointer/IrTypeStruct instances.

The remaining xyz2llvm static methods are not exactly pretty,
they should probably just be folded into get.
a3a511c
@klickverbot klickverbot Metadata/gc2stack compile fixes to accomodate LLVM API changes. ebbbfdd
@klickverbot klickverbot Added D2/druntime support to gc2stack. bc541a4
@klickverbot klickverbot Enable USE_METADATA by default. 4da1427
@klickverbot klickverbot dgc2stack: Demote LLVM "tail" calls when promoting an allocation.
Referencing alloca'd memory in tail calls is invalid IR. This was
not caught by the verifier, but produced misoptimizations due to
wrong alias analysis results.
8913898
@klickverbot klickverbot dgc2stack: LLVM 3.2 compatibility. 7be9c5c
@klickverbot klickverbot Set irtype for underlying function type when building delegate types.
This fixes the problem of arg_nest disappearing when DtoType
is called on such types, e.g. as part of metadata generation.
9d9f827
@klickverbot klickverbot merged commit 9d9f827 into ldc-developers:master

1 check was pending

Details default The Travis build is in progress
@klickverbot klickverbot deleted the klickverbot:metadata branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 20, 2012
  1. @klickverbot
  2. @klickverbot

    Refactored IrType construction to use static get() method.

    klickverbot authored
    This also allows us to enable the assert in IrType::IrType.
    
    Unfortunately, this is mostly a "peace of mind" commit, there
    doesn't seem to have been a bug actually caused by the transitory
    duplicate IrTypePointer/IrTypeStruct instances.
    
    The remaining xyz2llvm static methods are not exactly pretty,
    they should probably just be folded into get.
  3. @klickverbot
  4. @klickverbot
  5. @klickverbot
  6. @klickverbot

    dgc2stack: Demote LLVM "tail" calls when promoting an allocation.

    klickverbot authored
    Referencing alloca'd memory in tail calls is invalid IR. This was
    not caught by the verifier, but produced misoptimizations due to
    wrong alias analysis results.
  7. @klickverbot
  8. @klickverbot

    Set irtype for underlying function type when building delegate types.

    klickverbot authored
    This fixes the problem of arg_nest disappearing when DtoType
    is called on such types, e.g. as part of metadata generation.
This page is out of date. Refresh to see the latest.
View
6 CMakeLists.txt
@@ -42,7 +42,11 @@ set(CONF_INST_DIR ${SYSCONF_INSTALL_DIR} CACHE PATH "Directory ldc.conf is insta
# The following flags are currently not well tested, expect the build to fail.
option(USE_BOEHM_GC "use the Boehm garbage collector internally")
option(GENERATE_OFFTI "generate complete ClassInfo.offTi arrays")
-option(USE_METADATA "use metadata and related custom optimization passes")
+
+# Enabled by default now, will be removed entirely soon if no problems pop up
+# with the added functionality.
+option(USE_METADATA "use metadata and related custom optimization passes" ON)
+
mark_as_advanced(USE_BOEHM_GC GENERATE_OFFTI USE_METADATA)
if(D_VERSION EQUAL 1)
View
2  gen/classes.cpp
@@ -722,7 +722,7 @@ LLConstant* DtoDefineClassInfo(ClassDeclaration* cd)
}
else
{
- LLType* cd_type = stripModifiers(cdty)->irtype->getType();
+ LLType* cd_type = cdty->irtype->isClass()->getMemoryLLType();
size_t initsz = getTypePaddedSize(cd_type);
b.push_void_array(initsz, ir->getInitSymbol());
}
View
9 gen/metadata.h
@@ -20,15 +20,6 @@
#include "llvm/Metadata.h"
typedef llvm::Value MDNodeField;
-// Use getNumElements() and getElement() to access elements.
-inline unsigned MD_GetNumElements(llvm::MDNode* N) {
- return N->getNumElements();
-}
-
-inline MDNodeField* MD_GetElement(llvm::MDNode* N, unsigned i) {
- return N->getElement(i);
-}
-
#define METADATA_LINKAGE_TYPE llvm::GlobalValue::WeakODRLinkage
// *** Metadata for TypeInfo instances ***
View
16 gen/module.cpp
@@ -50,6 +50,10 @@
#include "ir/irmodule.h"
#include "ir/irtype.h"
+#if !MODULEINFO_IS_STRUCT
+#include "ir/irtypeclass.h"
+#endif
+
#if DMDV2
#define NEW_MODULEINFO_LAYOUT 1
#endif
@@ -379,8 +383,12 @@ void Module::genmoduleinfo()
RTTIBuilder b(moduleinfo);
// some types
- LLType* moduleinfoTy = moduleinfo->type->irtype->getType();
- LLType* classinfoTy = ClassDeclaration::classinfo->type->irtype->getType();
+#if MODULEINFO_IS_STRUCT
+ LLType* moduleinfoTy = moduleinfo->type->irtype->getLLType();
+#else
+ LLType* moduleinfoTy = moduleinfo->type->irtype->isClass()->getMemoryLLType();
+#endif
+ LLType* classinfoTy = ClassDeclaration::classinfo->type->irtype->getLLType();
// importedModules[]
std::vector<LLConstant*> importInits;
@@ -438,13 +446,13 @@ void Module::genmoduleinfo()
continue;
}
Logger::println("class: %s", cd->toPrettyChars());
- LLConstant *c = DtoBitCast(cd->ir.irStruct->getClassInfoSymbol(), getPtrToType(classinfoTy));
+ LLConstant *c = DtoBitCast(cd->ir.irStruct->getClassInfoSymbol(), classinfoTy);
classInits.push_back(c);
}
// has class array?
if (!classInits.empty())
{
- localClassesTy = llvm::ArrayType::get(getPtrToType(classinfoTy), classInits.size());
+ localClassesTy = llvm::ArrayType::get(classinfoTy, classInits.size());
localClasses = LLConstantArray::get(localClassesTy, classInits);
}
View
2  gen/optimizer.cpp
@@ -190,7 +190,7 @@ static void addOptimizationPasses(PassManagerBase &mpm, FunctionPassManager &fpm
#if USE_METADATA
if (!disableGCToStack)
- Builder.addExtension(PassManagerBuilder::EP_LoopOptimizerEnd, addGarbageCollect2StackPass);
+ builder.addExtension(PassManagerBuilder::EP_LoopOptimizerEnd, addGarbageCollect2StackPass);
#endif // USE_METADATA
}
View
220 gen/passes/GarbageCollect2Stack.cpp
@@ -14,6 +14,7 @@
//
//===----------------------------------------------------------------------===//
+#include "gen/runtime.h"
#include "gen/metadata.h"
#define DEBUG_TYPE "dgc2stack"
@@ -30,7 +31,11 @@
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/ValueTracking.h"
+#if LDC_LLVM_VER >= 302
+#include "llvm/DataLayout.h"
+#else
#include "llvm/Target/TargetData.h"
+#endif
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
@@ -48,12 +53,16 @@ STATISTIC(NumDeleted, "Number of GC calls deleted because the return value was u
namespace {
struct Analysis {
+#if LDC_LLVM_VER >= 302
+ DataLayout& TD;
+#else
TargetData& TD;
+#endif
const Module& M;
CallGraph* CG;
CallGraphNode* CGNode;
- const Type* getTypeFor(Value* typeinfo) const;
+ Type* getTypeFor(Value* typeinfo) const;
};
}
@@ -66,10 +75,11 @@ void EmitMemSet(IRBuilder<>& B, Value* Dst, Value* Val, Value* Len,
Dst = B.CreateBitCast(Dst, PointerType::getUnqual(B.getInt8Ty()));
Module *M = B.GetInsertBlock()->getParent()->getParent();
- const Type* intTy = Len->getType();
- const Type *VoidPtrTy = PointerType::getUnqual(B.getInt8Ty());
- const Type *Tys[2] ={VoidPtrTy, intTy};
- Function *MemSet = Intrinsic::getDeclaration(M, Intrinsic::memset, Tys, 2);
+ Type* intTy = Len->getType();
+ Type *VoidPtrTy = PointerType::getUnqual(B.getInt8Ty());
+ Type *Tys[2] = {VoidPtrTy, intTy};
+ Function *MemSet = Intrinsic::getDeclaration(M, Intrinsic::memset,
+ llvm::makeArrayRef(Tys, 2));
Value *Align = ConstantInt::get(B.getInt32Ty(), 1);
CallSite CS = B.CreateCall5(MemSet, Dst, Val, Len, Align, B.getFalse());
@@ -90,12 +100,16 @@ static void EmitMemZero(IRBuilder<>& B, Value* Dst, Value* Len,
namespace {
class FunctionInfo {
protected:
- const Type* Ty;
+ Type* Ty;
public:
unsigned TypeInfoArgNr;
bool SafeToDelete;
+ /// Whether the allocated memory is returned as a D array instead of
+ /// just a plain pointer.
+ bool ReturnsArray;
+
// Analyze the current call, filling in some fields. Returns true if
// this is an allocation we can stack-allocate.
virtual bool analyze(CallSite CS, const Analysis& A) {
@@ -106,15 +120,17 @@ namespace {
// Returns the alloca to replace this call.
// It will always be inserted before the call.
- virtual AllocaInst* promote(CallSite CS, IRBuilder<>& B, const Analysis& A) {
+ virtual Value* promote(CallSite CS, IRBuilder<>& B, const Analysis& A) {
NumGcToStack++;
Instruction* Begin = CS.getCaller()->getEntryBlock().begin();
return new AllocaInst(Ty, ".nongc_mem", Begin); // FIXME: align?
}
- FunctionInfo(unsigned typeInfoArgNr, bool safeToDelete)
- : TypeInfoArgNr(typeInfoArgNr), SafeToDelete(safeToDelete) {}
+ FunctionInfo(unsigned typeInfoArgNr, bool safeToDelete, bool returnsArray)
+ : TypeInfoArgNr(typeInfoArgNr),
+ SafeToDelete(safeToDelete),
+ ReturnsArray(returnsArray) {}
};
class ArrayFI : public FunctionInfo {
@@ -123,9 +139,9 @@ namespace {
bool Initialized;
public:
- ArrayFI(unsigned tiArgNr, bool safeToDelete, bool initialized,
- unsigned arrSizeArgNr)
- : FunctionInfo(tiArgNr, safeToDelete),
+ ArrayFI(unsigned tiArgNr, bool safeToDelete, bool returnsArray,
+ bool initialized, unsigned arrSizeArgNr)
+ : FunctionInfo(tiArgNr, safeToDelete, returnsArray),
ArrSizeArgNr(arrSizeArgNr),
Initialized(initialized)
{}
@@ -145,7 +161,11 @@ namespace {
// the conversion is safe.
APInt Mask = APInt::getHighBitsSet(bits, bits - 32);
APInt KnownZero(bits, 0), KnownOne(bits, 0);
+#if LDC_LLVM_VER >= 301
+ ComputeMaskedBits(arrSize, KnownZero, KnownOne, &A.TD);
+#else
ComputeMaskedBits(arrSize, Mask, KnownZero, KnownOne, &A.TD);
+#endif
if ((KnownZero & Mask) != Mask)
return false;
}
@@ -159,7 +179,7 @@ namespace {
return true;
}
- virtual AllocaInst* promote(CallSite CS, IRBuilder<>& B, const Analysis& A) {
+ virtual Value* promote(CallSite CS, IRBuilder<>& B, const Analysis& A) {
IRBuilder<> Builder = B;
// If the allocation is of constant size it's best to put it in the
// entry block, so do so if we're not already there.
@@ -189,6 +209,15 @@ namespace {
EmitMemZero(B, alloca, Size, A);
}
+ if (ReturnsArray) {
+ Value* arrStruct = llvm::UndefValue::get(CS.getType());
+ arrStruct = Builder.CreateInsertValue(arrStruct, arrSize, 0);
+ Value* memPtr = Builder.CreateBitCast(alloca,
+ PointerType::getUnqual(B.getInt8Ty()));
+ arrStruct = Builder.CreateInsertValue(arrStruct, memPtr, 1);
+ return arrStruct;
+ }
+
return alloca;
}
};
@@ -213,17 +242,17 @@ namespace {
if (!meta)
return false;
- MDNode* node = static_cast<MDNode*>(meta->getElement(0));
- if (!node || MD_GetNumElements(node) != CD_NumFields)
+ MDNode* node = static_cast<MDNode*>(meta->getOperand(0));
+ if (!node || node->getNumOperands() != CD_NumFields)
return false;
// Inserting destructor calls is not implemented yet, so classes
// with destructors are ignored for now.
- Constant* hasDestructor = dyn_cast<Constant>(MD_GetElement(node, CD_Finalize));
+ Constant* hasDestructor = dyn_cast<Constant>(node->getOperand(CD_Finalize));
// We can't stack-allocate if the class has a custom deallocator
// (Custom allocators don't get turned into this runtime call, so
// those can be ignored)
- Constant* hasCustomDelete = dyn_cast<Constant>(MD_GetElement(node, CD_CustomDelete));
+ Constant* hasCustomDelete = dyn_cast<Constant>(node->getOperand(CD_CustomDelete));
if (hasDestructor == NULL || hasCustomDelete == NULL)
return false;
@@ -231,13 +260,13 @@ namespace {
!= ConstantInt::getFalse(A.M.getContext()))
return false;
- Ty = MD_GetElement(node, CD_BodyType)->getType();
+ Ty =node->getOperand(CD_BodyType)->getType();
return true;
}
// The default promote() should be fine.
- AllocClassFI() : FunctionInfo(~0u, true) {}
+ AllocClassFI() : FunctionInfo(~0u, true, false) {}
};
}
@@ -270,7 +299,11 @@ namespace {
bool runOnFunction(Function &F);
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
+#if LDC_LLVM_VER >= 302
+ AU.addRequired<DataLayout>();
+#else
AU.addRequired<TargetData>();
+#endif
AU.addRequired<DominatorTree>();
AU.addPreserved<CallGraph>();
@@ -289,10 +322,15 @@ FunctionPass *createGarbageCollect2Stack() {
}
GarbageCollect2Stack::GarbageCollect2Stack()
-: FunctionPass(&ID),
- AllocMemoryT(0, true),
- NewArrayVT(0, true, false, 1),
- NewArrayT(0, true, true, 1)
+: FunctionPass(ID),
+ AllocMemoryT(0, true, false),
+ NewArrayVT(0, true, false, false, 1),
+#ifdef DMDV1
+ // _d_newarrayT returns just the void* ptr in the LDC D1 runtime.
+ NewArrayT(0, true, false, true, 1)
+#else
+ NewArrayT(0, true, true, true, 1)
+#endif
{
KnownFunctions["_d_allocmemoryT"] = &AllocMemoryT;
KnownFunctions["_d_newarrayvT"] = &NewArrayVT;
@@ -317,14 +355,23 @@ static void RemoveCall(CallSite CS, const Analysis& A) {
CS.getInstruction()->eraseFromParent();
}
-static bool isSafeToStackAllocate(Instruction* Alloc, DominatorTree& DT);
+static bool isSafeToStackAllocateArray(Instruction* Alloc, DominatorTree& DT,
+ SmallVector<CallInst*, 4>& RemoveTailCallInsts
+);
+static bool isSafeToStackAllocate(Instruction* Alloc, Value* V, DominatorTree& DT,
+ SmallVector<CallInst*, 4>& RemoveTailCallInsts
+);
/// runOnFunction - Top level algorithm.
///
bool GarbageCollect2Stack::runOnFunction(Function &F) {
DEBUG(errs() << "\nRunning -dgc2stack on function " << F.getName() << '\n');
+#if LDC_LLVM_VER >= 302
+ DataLayout& TD = getAnalysis<DataLayout>();
+#else
TargetData& TD = getAnalysis<TargetData>();
+#endif
DominatorTree& DT = getAnalysis<DominatorTree>();
CallGraph* CG = getAnalysisIfAvailable<CallGraph>();
CallGraphNode* CGNode = CG ? (*CG)[&F] : NULL;
@@ -340,7 +387,7 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) {
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) {
// Ignore non-calls.
Instruction* Inst = I++;
- CallSite CS = CallSite::get(Inst);
+ CallSite CS(Inst);
if (!CS.getInstruction())
continue;
@@ -355,9 +402,6 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) {
KnownFunctions.find(Callee->getName());
if (OMI == KnownFunctions.end()) continue;
- assert(isa<PointerType>(Inst->getType())
- && "GC function doesn't return a pointer?");
-
FunctionInfo* info = OMI->getValue();
if (Inst->use_empty() && info->SafeToDelete) {
@@ -369,12 +413,26 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) {
DEBUG(errs() << "GarbageCollect2Stack inspecting: " << *Inst);
- if (!info->analyze(CS, A) || !isSafeToStackAllocate(Inst, DT))
+ if (!info->analyze(CS, A))
continue;
+ SmallVector<CallInst*, 4> RemoveTailCallInsts;
+ if (info->ReturnsArray) {
+ if (!isSafeToStackAllocateArray(Inst, DT, RemoveTailCallInsts)) continue;
+ } else {
+ if (!isSafeToStackAllocate(Inst, Inst, DT, RemoveTailCallInsts)) continue;
+ }
+
// Let's alloca this!
Changed = true;
+ // First demote tail calls which use the value so there IR is never
+ // in an invalid state.
+ SmallVector<CallInst*, 4>::iterator it, end = RemoveTailCallInsts.end();
+ for (it = RemoveTailCallInsts.begin(); it != end; ++it) {
+ (*it)->setTailCall(false);
+ }
+
IRBuilder<> Builder(BB, Inst);
Value* newVal = info->promote(CS, Builder, A);
@@ -393,7 +451,7 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) {
return Changed;
}
-const Type* Analysis::getTypeFor(Value* typeinfo) const {
+Type* Analysis::getTypeFor(Value* typeinfo) const {
GlobalVariable* ti_global = dyn_cast<GlobalVariable>(typeinfo->stripPointerCasts());
if (!ti_global)
return NULL;
@@ -405,17 +463,17 @@ const Type* Analysis::getTypeFor(Value* typeinfo) const {
if (!meta)
return NULL;
- MDNode* node = static_cast<MDNode*>(meta->getElement(0));
+ MDNode* node = static_cast<MDNode*>(meta->getOperand(0));
if (!node)
return NULL;
- if (MD_GetNumElements(node) != TD_NumFields)
+ if (node->getNumOperands() != TD_NumFields)
return NULL;
- if (TD_Confirm >= 0 && (!MD_GetElement(node, TD_Confirm) ||
- MD_GetElement(node, TD_Confirm)->stripPointerCasts() != ti_global))
+ if (TD_Confirm >= 0 && (!node->getOperand(TD_Confirm) ||
+ node->getOperand(TD_Confirm)->stripPointerCasts() != ti_global))
return NULL;
- return MD_GetElement(node, TD_Type)->getType();
+ return node->getOperand(TD_Type)->getType();
}
/// Returns whether Def is used by any instruction that is reachable from Alloc
@@ -549,12 +607,57 @@ static bool mayBeUsedAfterRealloc(Instruction* Def, Instruction* Alloc, Dominato
return false;
}
+/// Returns true if the GC call passed in is safe to turn into a stack
+/// allocation.
+///
+/// This handles GC calls returning a D array instead of a raw pointer,
+/// see isSafeToStackAllocate() for details.
+bool isSafeToStackAllocateArray(Instruction* Alloc, DominatorTree& DT,
+ SmallVector<CallInst*, 4>& RemoveTailCallInsts
+) {
+ assert(Alloc->getType()->isStructTy() && "Allocated array is not a struct?");
+ Value* V = Alloc;
+
+ for (Value::use_iterator UI = V->use_begin(), UE = V->use_end();
+ UI != UE; ++UI) {
+ Instruction *User = cast<Instruction>(*UI);
+
+ switch (User->getOpcode()) {
+ case Instruction::ExtractValue: {
+ ExtractValueInst *EVI = cast<ExtractValueInst>(User);
-/// isSafeToStackAllocate - Return true if the GC call passed in is safe to turn
+ assert(EVI->getAggregateOperand() == V);
+ assert(EVI->getNumIndices() == 1);
+
+ unsigned idx = EVI->getIndices()[0];
+ if (idx == 0) {
+ // This extract the length argument, irrelevant for our analysis.
+ assert(EVI->getType()->isIntegerTy() && "First array field not length?");
+ } else {
+ assert(idx == 1 && "Invalid array struct access.");
+ if (!isSafeToStackAllocate(Alloc, EVI, DT, RemoveTailCallInsts))
+ return false;
+ }
+ break;
+ }
+ default:
+ // We are super conservative here, the only thing we want to be able to
+ // handle at this point is extracting len/ptr. More extensive analysis
+ // could be added later.
+ return false;
+ }
+ }
+
+ // All uses examined - memory not captured.
+ return true;
+}
+
+
+/// Returns true if the GC call passed in is safe to turn
/// into a stack allocation. This requires that the return value does not
/// escape from the function and no derived pointers are live at the call site
/// (i.e. if it's in a loop then the function can't use any pointer returned
-/// from an earlier call after a new call has been made)
+/// from an earlier call after a new call has been made).
///
/// This is currently conservative where loops are involved: it can handle
/// simple loops, but returns false if any derived pointer is used in a
@@ -562,9 +665,19 @@ static bool mayBeUsedAfterRealloc(Instruction* Def, Instruction* Alloc, Dominato
///
/// Based on LLVM's PointerMayBeCaptured(), which only does escape analysis but
/// doesn't care about loops.
-bool isSafeToStackAllocate(Instruction* Alloc, DominatorTree& DT) {
- assert(isa<PointerType>(Alloc->getType()) && "Allocation is not a pointer?");
- Value* V = Alloc;
+///
+/// Alloc is the actual call to the runtime function, and V is the pointer to
+/// the memory it returns (which might not be equal to Alloc in case of
+/// functions returning D arrays).
+///
+/// If the value is used in a call instruction with the tail attribute set,
+/// the attribute has to be removed before promoting the memory to the
+/// stack. The affected instructions are added to RemoveTailCallInsts. If
+/// the function returns false, these entries are meaningless.
+bool isSafeToStackAllocate(Instruction* Alloc, Value* V, DominatorTree& DT,
+ SmallVector<CallInst*, 4>& RemoveTailCallInsts
+) {
+ assert(isa<PointerType>(V->getType()) && "Allocated value is not a pointer?");
SmallVector<Use*, 16> Worklist;
SmallSet<Use*, 16> Visited;
@@ -584,7 +697,7 @@ bool isSafeToStackAllocate(Instruction* Alloc, DominatorTree& DT) {
switch (I->getOpcode()) {
case Instruction::Call:
case Instruction::Invoke: {
- CallSite CS = CallSite::get(I);
+ CallSite CS(I);
// Not captured if the callee is readonly, doesn't return a copy through
// its return value and doesn't unwind (a readonly function can leak bits
// by throwing an exception or not depending on the input value).
@@ -601,16 +714,29 @@ bool isSafeToStackAllocate(Instruction* Alloc, DominatorTree& DT) {
// (think of self-referential objects).
CallSite::arg_iterator B = CS.arg_begin(), E = CS.arg_end();
for (CallSite::arg_iterator A = B; A != E; ++A)
- if (A->get() == V && !CS.paramHasAttr(A - B + 1, Attribute::NoCapture))
- // The parameter is not marked 'nocapture' - captured.
- return false;
+ if (A->get() == V) {
+ if (!CS.paramHasAttr(A - B + 1,
+#if LDC_LLVM_VER >= 302
+ Attributes::NoCapture
+#else
+ Attribute::NoCapture
+#endif
+ )) {
+ // The parameter is not marked 'nocapture' - captured.
+ return false;
+ }
+
+ if (CS.isCall()) {
+ CallInst* CI = cast<CallInst>(I);
+ if (CI->isTailCall()) {
+ RemoveTailCallInsts.push_back(CI);
+ }
+ }
+ }
// Only passed via 'nocapture' arguments, or is the called function - not
// captured.
break;
}
- case Instruction::Free:
- // Freeing a pointer does not cause it to be captured.
- break;
case Instruction::Load:
// Loading from a pointer does not cause it to be captured.
break;
View
7 gen/runtime.h
@@ -14,6 +14,13 @@
#ifndef LDC_GEN_RUNTIME_H_
#define LDC_GEN_RUNTIME_H_
+namespace llvm
+{
+ class Function;
+ class GlobalVariable;
+ class Module;
+}
+
// D runtime support helpers
bool LLVM_D_InitRuntime();
View
51 gen/tollvm.cpp
@@ -79,7 +79,7 @@ LLType* DtoType(Type* t)
if (t->irtype)
{
- return t->irtype->get();
+ return t->irtype->getLLType();
}
IF_LOG Logger::println("Building type: %s", t->toChars());
@@ -113,55 +113,65 @@ LLType* DtoType(Type* t)
case Twchar:
case Tdchar:
{
- t->irtype = new IrTypeBasic(t);
- return t->irtype->buildType();
+ return IrTypeBasic::get(t)->getLLType();
}
// pointers
case Tnull:
case Tpointer:
{
- t->irtype = new IrTypePointer(t);
- return t->irtype->buildType();
+ return IrTypePointer::get(t)->getLLType();
}
// arrays
case Tarray:
{
- t->irtype = new IrTypeArray(t);
- return t->irtype->buildType();
+ return IrTypeArray::get(t)->getLLType();
}
case Tsarray:
{
- t->irtype = new IrTypeSArray(t);
- return t->irtype->buildType();
+ return IrTypeSArray::get(t)->getLLType();
}
// aggregates
- case Tstruct: {
+ case Tstruct:
+ {
TypeStruct* ts = static_cast<TypeStruct*>(t);
- t->irtype = new IrTypeStruct(ts->sym);
- return t->irtype->buildType();
+ if (ts->sym->type->irtype)
+ {
+ // This should not happen, but the frontend seems to be buggy. Not
+ // sure if this is the best way to handle the situation, but we
+ // certainly don't want to override ts->sym->type->irtype.
+ IF_LOG Logger::cout() << "Struct with multiple Types detected: " <<
+ ts->toChars() << " (" << ts->sym->locToChars() << ")" << std::endl;
+ return ts->sym->type->irtype->getLLType();
+ }
+ return IrTypeStruct::get(ts->sym)->getLLType();
}
- case Tclass: {
+ case Tclass:
+ {
TypeClass* tc = static_cast<TypeClass*>(t);
- t->irtype = new IrTypeClass(tc->sym);
- return t->irtype->buildType();
+ if (tc->sym->type->irtype)
+ {
+ // See Tstruct case.
+ IF_LOG Logger::cout() << "Class with multiple Types detected: " <<
+ tc->toChars() << " (" << tc->sym->locToChars() << ")" << std::endl;
+ return tc->sym->type->irtype->getLLType();
+ }
+ return IrTypeClass::get(tc->sym)->getLLType();
}
// functions
case Tfunction:
{
- t->irtype = new IrTypeFunction(t);
- return t->irtype->buildType();
+ return IrTypeFunction::get(t)->getLLType();
}
// delegates
case Tdelegate:
{
- t->irtype = new IrTypeDelegate(t);
- return t->irtype->buildType();
+ return IrTypeDelegate::get(t)->getLLType();
}
// typedefs
@@ -183,8 +193,7 @@ LLType* DtoType(Type* t)
#if DMDV2
case Tvector:
{
- t->irtype = new IrTypeVector(t);
- return t->irtype->buildType();
+ return IrTypeVector::get(t)->getLLType();
}
#endif
View
13 gen/typinf.cpp
@@ -53,6 +53,7 @@
#include "ir/irvar.h"
#include "ir/irtype.h"
+#include <ir/irtypeclass.h>
/*******************************************
* Get a canonicalized form of the TypeInfo for use with the internal
@@ -323,7 +324,7 @@ void DtoResolveTypeInfo(TypeInfoDeclaration* tid)
if (!irg->value) {
if (tid->tinfo->builtinTypeInfo()) // this is a declaration of a builtin __initZ var
- irg->type = Type::typeinfo->type->irtype->getType();
+ irg->type = Type::typeinfo->type->irtype->isClass()->getMemoryLLType();
else
irg->type = LLStructType::create(gIR->context(), tid->toPrettyChars());
irg->value = new llvm::GlobalVariable(*gIR->module, irg->type, true,
@@ -348,10 +349,10 @@ void DtoResolveTypeInfo(TypeInfoDeclaration* tid)
if (TD_Confirm >= 0)
mdVals[TD_Confirm] = llvm::cast<MDNodeField>(irg->value);
mdVals[TD_Type] = llvm::UndefValue::get(DtoType(tid->tinfo));
- // Construct the metadata
- llvm::MetadataBase* metadata = llvm::MDNode::get(gIR->context(), mdVals, TD_NumFields);
- // Insert it into the module
- llvm::NamedMDNode::Create(gIR->context(), metaname, &metadata, 1, gIR->module);
+ // Construct the metadata and insert it into the module.
+ llvm::NamedMDNode* node = gIR->module->getOrInsertNamedMetadata(metaname);
+ node->addOperand(llvm::MDNode::get(gIR->context(),
+ llvm::makeArrayRef(mdVals, TD_NumFields)));
}
}
#endif // USE_METADATA
@@ -638,7 +639,7 @@ void TypeInfoStructDeclaration::llvmDefine()
// void[] init
// never emit a null array, even for zero initialized typeinfo
// the size() method uses this array!
- size_t init_size = getTypeStoreSize(tc->irtype->getType());
+ size_t init_size = getTypeStoreSize(tc->irtype->getLLType());
b.push_void_array(init_size, irstruct->getInitSymbol());
// toX functions ground work
View
16 ir/irclass.cpp
@@ -9,6 +9,7 @@
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
+#include "llvm/ADT/SmallString.h"
#include "aggregate.h"
#include "declaration.h"
@@ -78,9 +79,9 @@ LLGlobalVariable * IrStruct::getClassInfoSymbol()
IrTypeClass* tc = stripModifiers(cinfo->type)->irtype->isClass();
assert(tc && "invalid ClassInfo type");
- // classinfos cannot be constants since they're used a locks for synchronized
+ // classinfos cannot be constants since they're used as locks for synchronized
classInfo = new llvm::GlobalVariable(
- *gIR->module, tc->getType(), false, _linkage, NULL, initname);
+ *gIR->module, tc->getMemoryLLType(), false, _linkage, NULL, initname);
#if USE_METADATA
// Generate some metadata on this ClassInfo if it's for a class.
@@ -96,11 +97,12 @@ LLGlobalVariable * IrStruct::getClassInfoSymbol()
mdVals[CD_BodyType] = llvm::UndefValue::get(bodyType);
mdVals[CD_Finalize] = LLConstantInt::get(LLType::getInt1Ty(gIR->context()), hasDestructor);
mdVals[CD_CustomDelete] = LLConstantInt::get(LLType::getInt1Ty(gIR->context()), hasCustomDelete);
- // Construct the metadata
- llvm::MetadataBase* metadata = llvm::MDNode::get(gIR->context(), mdVals, CD_NumFields);
- // Insert it into the module
- std::string metaname = CD_PREFIX + initname;
- llvm::NamedMDNode::Create(gIR->context(), metaname, &metadata, 1, gIR->module);
+ // Construct the metadata and insert it into the module.
+ llvm::SmallString<64> name;
+ llvm::NamedMDNode* node = gIR->module->getOrInsertNamedMetadata(
+ llvm::Twine(CD_PREFIX, initname).toStringRef(name));
+ node->addOperand(llvm::MDNode::get(gIR->context(),
+ llvm::makeArrayRef(mdVals, CD_NumFields)));
}
#endif // USE_METADATA
View
80 ir/irtype.cpp
@@ -13,6 +13,7 @@
#include "mtype.h"
#include "gen/irstate.h"
#include "gen/logger.h"
+#include "gen/tollvm.h"
#include "ir/irtype.h"
// This code uses llvm::getGlobalContext() as these functions are invoked before gIR is set.
@@ -20,21 +21,13 @@
//////////////////////////////////////////////////////////////////////////////
-extern LLType* DtoType(Type* dt);
-extern LLIntegerType* DtoSize_t();
-
-//////////////////////////////////////////////////////////////////////////////
-
IrType::IrType(Type* dt, LLType* lt)
: dtype(dt),
type(lt)
{
assert(dt && "null D Type");
assert(lt && "null LLVM Type");
-#if 0
- // FIXME: For some reason the assert fails
- assert(dt->irtype == NULL && "already has IrType");
-#endif
+ assert(!dt->irtype && "already has IrType");
}
//////////////////////////////////////////////////////////////////////////////
@@ -48,9 +41,11 @@ IrTypeBasic::IrTypeBasic(Type * dt)
//////////////////////////////////////////////////////////////////////////////
-llvm::Type * IrTypeBasic::buildType()
+IrTypeBasic* IrTypeBasic::get(Type* dt)
{
- return type;
+ IrTypeBasic* t = new IrTypeBasic(dt);
+ dt->irtype = t;
+ return t;
}
//////////////////////////////////////////////////////////////////////////////
@@ -145,35 +140,36 @@ llvm::Type * IrTypeBasic::basic2llvm(Type* t)
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
-IrTypePointer::IrTypePointer(Type * dt)
-: IrType(dt, dt->ty == Tnull ? null2llvm(dt) : pointer2llvm(dt))
-{
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-llvm::Type * IrTypePointer::buildType()
+IrTypePointer::IrTypePointer(Type* dt, LLType* lt)
+: IrType(dt, lt)
{
- return type;
}
//////////////////////////////////////////////////////////////////////////////
-llvm::Type * IrTypePointer::pointer2llvm(Type * dt)
+IrTypePointer* IrTypePointer::get(Type* dt)
{
- assert(dt->ty == Tpointer && "not pointer type");
+ assert(!dt->irtype);
+ assert((dt->ty == Tpointer || dt->ty == Tnull) && "not pointer/null type");
- LLType* elemType = DtoType(dt->nextOf());
- if (elemType == llvm::Type::getVoidTy(llvm::getGlobalContext()))
+ LLType* elemType;
+ if (dt->ty == Tnull)
+ {
elemType = llvm::Type::getInt8Ty(llvm::getGlobalContext());
- return llvm::PointerType::get(elemType, 0);
-}
+ }
+ else
+ {
+ elemType = DtoTypeNotVoid(dt->nextOf());
-llvm::Type* IrTypePointer::null2llvm(Type* dt)
-{
- assert(dt->ty == Tnull && "not null type");
- LLType* elemType = llvm::Type::getInt8Ty(llvm::getGlobalContext());
- return llvm::PointerType::get(elemType, 0);
+ // DtoTypeNotVoid could have already created the same type, e.g. for
+ // dt == Node* in struct Node { Node* n; }.
+ if (dt->irtype)
+ return dt->irtype->isPointer();
+ }
+
+ IrTypePointer* t = new IrTypePointer(dt, llvm::PointerType::get(elemType, 0));
+ dt->irtype = t;
+ return t;
}
//////////////////////////////////////////////////////////////////////////////
@@ -187,9 +183,11 @@ IrTypeSArray::IrTypeSArray(Type * dt)
//////////////////////////////////////////////////////////////////////////////
-llvm::Type * IrTypeSArray::buildType()
+IrTypeSArray* IrTypeSArray::get(Type* dt)
{
- return type;
+ IrTypeSArray* t = new IrTypeSArray(dt);
+ dt->irtype = t;
+ return t;
}
//////////////////////////////////////////////////////////////////////////////
@@ -198,7 +196,7 @@ llvm::Type * IrTypeSArray::sarray2llvm(Type * t)
{
assert(t->ty == Tsarray && "not static array type");
TypeSArray* tsa = static_cast<TypeSArray*>(t);
- dim = static_cast<uint64_t>(tsa->dim->toUInteger());
+ uint64_t dim = static_cast<uint64_t>(tsa->dim->toUInteger());
LLType* elemType = DtoType(t->nextOf());
if (elemType == llvm::Type::getVoidTy(llvm::getGlobalContext()))
elemType = llvm::Type::getInt8Ty(llvm::getGlobalContext());
@@ -216,9 +214,11 @@ IrTypeArray::IrTypeArray(Type * dt)
//////////////////////////////////////////////////////////////////////////////
-llvm::Type * IrTypeArray::buildType()
+IrTypeArray* IrTypeArray::get(Type* dt)
{
- return type;
+ IrTypeArray* t = new IrTypeArray(dt);
+ dt->irtype = t;
+ return t;
}
//////////////////////////////////////////////////////////////////////////////
@@ -255,9 +255,11 @@ IrTypeVector::IrTypeVector(Type* dt)
//////////////////////////////////////////////////////////////////////////////
-llvm::Type* IrTypeVector::buildType()
+IrTypeVector* IrTypeVector::get(Type* dt)
{
- return type;
+ IrTypeVector* t = new IrTypeVector(dt);
+ dt->irtype = t;
+ return t;
}
//////////////////////////////////////////////////////////////////////////////
@@ -268,7 +270,7 @@ llvm::Type* IrTypeVector::vector2llvm(Type* dt)
TypeVector* tv = static_cast<TypeVector*>(dt);
assert(tv->basetype->ty == Tsarray);
TypeSArray* tsa = static_cast<TypeSArray*>(tv->basetype);
- dim = static_cast<uint64_t>(tsa->dim->toUInteger());
+ uint64_t dim = static_cast<uint64_t>(tsa->dim->toUInteger());
LLType* elemType = DtoType(tsa->next);
if (elemType == llvm::Type::getVoidTy(llvm::getGlobalContext()))
elemType = llvm::Type::getInt8Ty(llvm::getGlobalContext());
View
76 ir/irtype.h
@@ -8,8 +8,7 @@
//===----------------------------------------------------------------------===//
//
// The types derived from IrType are used to attach LLVM type information and
-// other codegen metadata (e.g. for vtbl resolution) to frontend Types. There
-// is an 1:1 correspondence between Type and IrType instances.
+// other codegen metadata (e.g. for vtbl resolution) to frontend Types.
//
//===----------------------------------------------------------------------===//
@@ -40,14 +39,18 @@ class IrTypeVector;
//////////////////////////////////////////////////////////////////////////////
-/// Base class for IrTypeS.
+/// Code generation state/metadata for D types. The mapping from IrType to
+/// Type is injective but not surjective.
+///
+/// Derived classes should be created using their static get() methods, which
+/// makes sure that uniqueness is preserved in the face of forward references.
+/// Note that the get() methods expect the IrType of the passed type/symbol to
+/// be not yet set. This could be altered to just return the existing IrType
+/// in order to bring the API entirely in line with the LLVM type get() methods.
class IrType
{
public:
///
- IrType(Type* dt, llvm::Type* lt);
-
- ///
virtual IrTypeAggr* isAggr() { return NULL; }
///
virtual IrTypeArray* isArray() { return NULL; }
@@ -71,16 +74,14 @@ class IrType
#endif
///
- Type* getD() { return dtype; }
- ///
- virtual llvm::Type* get() { return type; }
+ Type* getDType() { return dtype; }
///
- llvm::Type* getType() { return type; }
+ virtual llvm::Type* getLLType() { return type; }
+protected:
///
- virtual llvm::Type* buildType() = 0;
+ IrType(Type* dt, llvm::Type* lt);
-protected:
///
Type* dtype;
@@ -95,19 +96,18 @@ class IrTypeBasic : public IrType
{
public:
///
- IrTypeBasic(Type* dt);
+ static IrTypeBasic* get(Type* dt);
///
IrTypeBasic* isBasic() { return this; }
- ///
- llvm::Type* buildType();
-
protected:
///
- LLType* getComplexType(llvm::LLVMContext& ctx, LLType* type);
+ IrTypeBasic(Type* dt);
+ ///
+ static LLType* getComplexType(llvm::LLVMContext& ctx, LLType* type);
///
- llvm::Type* basic2llvm(Type* t);
+ static llvm::Type* basic2llvm(Type* t);
};
//////////////////////////////////////////////////////////////////////////////
@@ -117,19 +117,14 @@ class IrTypePointer : public IrType
{
public:
///
- IrTypePointer(Type* dt);
+ static IrTypePointer* get(Type* dt);
///
IrTypePointer* isPointer() { return this; }
- ///
- llvm::Type* buildType();
-
protected:
///
- llvm::Type* pointer2llvm(Type* t);
- ///
- llvm::Type* null2llvm(Type* t);
+ IrTypePointer(Type* dt, LLType *lt);
};
//////////////////////////////////////////////////////////////////////////////
@@ -139,20 +134,17 @@ class IrTypeSArray : public IrType
{
public:
///
- IrTypeSArray(Type* dt);
+ static IrTypeSArray* get(Type* dt);
///
IrTypeSArray* isSArray() { return this; }
- ///
- llvm::Type* buildType();
-
protected:
///
- llvm::Type* sarray2llvm(Type* t);
+ IrTypeSArray(Type* dt);
- /// Dimension.
- uint64_t dim;
+ ///
+ static llvm::Type* sarray2llvm(Type* t);
};
//////////////////////////////////////////////////////////////////////////////
@@ -162,17 +154,16 @@ class IrTypeArray : public IrType
{
public:
///
- IrTypeArray(Type* dt);
+ static IrTypeArray* get(Type* dt);
///
IrTypeArray* isArray() { return this; }
- ///
- llvm::Type* buildType();
-
protected:
///
- llvm::Type* array2llvm(Type* t);
+ IrTypeArray(Type* dt);
+ ///
+ static llvm::Type* array2llvm(Type* t);
};
//////////////////////////////////////////////////////////////////////////////
@@ -183,17 +174,16 @@ class IrTypeVector : public IrType
{
public:
///
- IrTypeVector(Type* dt);
+ static IrTypeVector* get(Type* dt);
///
IrTypeVector* isVector() { return this; }
- ///
- llvm::Type* buildType();
protected:
- llvm::Type* vector2llvm(Type* dt);
- /// Dimension.
- uint64_t dim;
+ ///
+ IrTypeVector(Type* dt);
+
+ static llvm::Type* vector2llvm(Type* dt);
};
#endif
View
28 ir/irtypeclass.cpp
@@ -222,8 +222,11 @@ void IrTypeClass::addBaseClassData(
//////////////////////////////////////////////////////////////////////////////
-llvm::Type* IrTypeClass::buildType()
+IrTypeClass* IrTypeClass::get(ClassDeclaration* cd)
{
+ IrTypeClass* t = new IrTypeClass(cd);
+ cd->type->irtype = t;
+
IF_LOG Logger::println("Building class type %s @ %s", cd->toPrettyChars(), cd->loc.toChars());
LOG_SCOPE;
IF_LOG Logger::println("Instance size: %u", cd->structsize);
@@ -235,12 +238,12 @@ llvm::Type* IrTypeClass::buildType()
defaultTypes.reserve(32);
// add vtbl
- defaultTypes.push_back(llvm::PointerType::get(vtbl_type, 0));
+ defaultTypes.push_back(llvm::PointerType::get(t->vtbl_type, 0));
// interfaces are just a vtable
if (cd->isInterfaceDeclaration())
{
- num_interface_vtbls = cd->vtblInterfaces ? cd->vtblInterfaces->dim : 0;
+ t->num_interface_vtbls = cd->vtblInterfaces ? cd->vtblInterfaces->dim : 0;
}
// classes have monitor and fields
else
@@ -253,7 +256,7 @@ llvm::Type* IrTypeClass::buildType()
size_t field_index = 2;
// add data members recursively
- addBaseClassData(defaultTypes, cd, offset, field_index);
+ t->addBaseClassData(defaultTypes, cd, offset, field_index);
#if 1
// tail padding?
@@ -270,16 +273,16 @@ llvm::Type* IrTypeClass::buildType()
fatal();
// set struct body
- isaStruct(type)->setBody(defaultTypes, false);
+ isaStruct(t->type)->setBody(defaultTypes, false);
// VTBL
// set vtbl type body
- vtbl_type->setBody(buildVtblType(ClassDeclaration::classinfo->type, &cd->vtbl));
+ t->vtbl_type->setBody(t->buildVtblType(ClassDeclaration::classinfo->type, &cd->vtbl));
- IF_LOG Logger::cout() << "class type: " << *type << std::endl;
+ IF_LOG Logger::cout() << "class type: " << *t->type << std::endl;
- return get();
+ return t;
}
//////////////////////////////////////////////////////////////////////////////
@@ -349,13 +352,20 @@ std::vector<llvm::Type*> IrTypeClass::buildVtblType(Type* first, Array* vtbl_arr
//////////////////////////////////////////////////////////////////////////////
-llvm::Type * IrTypeClass::get()
+llvm::Type * IrTypeClass::getLLType()
{
return llvm::PointerType::get(type, 0);
}
//////////////////////////////////////////////////////////////////////////////
+llvm::Type * IrTypeClass::getMemoryLLType()
+{
+ return type;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
size_t IrTypeClass::getInterfaceIndex(ClassDeclaration * inter)
{
ClassIndexMap::iterator it = interfaceMap.find(inter);
View
12 ir/irtypeclass.h
@@ -22,16 +22,17 @@ class IrTypeClass : public IrTypeAggr
{
public:
///
- IrTypeClass(ClassDeclaration* cd);
+ static IrTypeClass* get(ClassDeclaration* cd);
///
virtual IrTypeClass* isClass() { return this; }
///
- llvm::Type* buildType();
+ llvm::Type* getLLType();
- ///
- llvm::Type* get();
+ /// Returns the actual storage type, i.e. without the indirection
+ /// for the class reference.
+ llvm::Type* getMemoryLLType();
/// Returns the vtable type for this class.
llvm::Type* getVtbl() { return vtbl_type; }
@@ -50,6 +51,9 @@ class IrTypeClass : public IrTypeAggr
protected:
///
+ IrTypeClass(ClassDeclaration* cd);
+
+ ///
ClassDeclaration* cd;
///
TypeClass* tc;
View
69 ir/irtypefunction.cpp
@@ -16,47 +16,64 @@
#include "ir/irtypefunction.h"
-IrTypeFunction::IrTypeFunction(Type* dt)
-: IrType(dt, func2llvm(dt))
+IrTypeFunction::IrTypeFunction(Type* dt, LLType* lt)
+: IrType(dt, lt)
{
- irfty = NULL;
}
-llvm::Type * IrTypeFunction::buildType()
+IrTypeFunction* IrTypeFunction::get(Type* dt, Type* nestedContextOverride)
{
- return type;
-}
+ assert(!dt->irtype);
+ assert(dt->ty == Tfunction);
-llvm::Type* IrTypeFunction::func2llvm(Type* dt)
-{
- llvm::Type* T;
+ // We can't get cycles here, but we can end up building the type as part of
+ // a class vtbl, ...
+ llvm::Type* lt;
TypeFunction* tf = static_cast<TypeFunction*>(dt);
if (tf->funcdecl)
- T = DtoFunctionType(tf->funcdecl);
+ lt = DtoFunctionType(tf->funcdecl);
else
- T = DtoFunctionType(tf,NULL,NULL);
- return T;
+ lt = DtoFunctionType(tf, NULL, nestedContextOverride);
+
+ if (!dt->irtype)
+ dt->irtype = new IrTypeFunction(dt, lt);
+ return dt->irtype->isFunction();
}
//////////////////////////////////////////////////////////////////////////////
-IrTypeDelegate::IrTypeDelegate(Type * dt)
-: IrType(dt, delegate2llvm(dt))
+IrTypeDelegate::IrTypeDelegate(Type * dt, LLType* lt)
+: IrType(dt, lt)
{
}
-llvm::Type* IrTypeDelegate::buildType()
-{
- return type;
-}
-
-llvm::Type* IrTypeDelegate::delegate2llvm(Type* dt)
+IrTypeDelegate* IrTypeDelegate::get(Type* dt)
{
+ assert(!dt->irtype);
assert(dt->ty == Tdelegate);
- LLType* func = DtoFunctionType(dt->nextOf(), NULL, Type::tvoid->pointerTo());
- llvm::SmallVector<LLType*, 2> types;
- types.push_back(getVoidPtrType());
- types.push_back(getPtrToType(func));
- LLStructType* dgtype = LLStructType::get(gIR->context(), types);
- return dgtype;
+
+ // We can't get cycles here, but we could end up building the type as part
+ // of a class vtbl, ...
+ if (!dt->nextOf()->irtype)
+ {
+ // Build the underlying function type. Be sure to set irtype here, so
+ // the nested context arg doesn't disappear if DtoType is ever called
+ // on dt->nextOf().
+ IrTypeFunction::get(dt->nextOf(), Type::tvoid->pointerTo());
+ }
+ if (!dt->irtype)
+ {
+ assert(static_cast<TypeFunction*>(dt->nextOf())->fty.arg_nest &&
+ "Underlying function type should have nested context arg, "
+ "picked up random pre-existing type?"
+ );
+
+ llvm::SmallVector<LLType*, 2> types;
+ types.push_back(getVoidPtrType());
+ types.push_back(getPtrToType(dt->nextOf()->irtype->getLLType()));
+ LLStructType* lt = LLStructType::get(gIR->context(), types);
+ dt->irtype = new IrTypeDelegate(dt, lt);
+ }
+
+ return dt->irtype->isDelegate();
}
View
16 ir/irtypefunction.h
@@ -23,18 +23,17 @@ class IrTypeFunction : public IrType
{
public:
///
- IrTypeFunction(Type* dt);
+ static IrTypeFunction* get(Type* dt, Type* nestedContextOverride = 0);
///
IrTypeFunction* isFunction() { return this; }
- ///
- llvm::Type* buildType();
-
IrFuncTy* fty() { return irfty; }
protected:
- llvm::Type* func2llvm(Type* dt);
+ ///
+ IrTypeFunction(Type* dt, llvm::Type* lt);
+
///
IrFuncTy* irfty;
};
@@ -44,15 +43,14 @@ class IrTypeDelegate : public IrType
{
public:
///
- IrTypeDelegate(Type* dt);
+ static IrTypeDelegate* get(Type* dt);
///
IrTypeDelegate* isDelegate() { return this; }
- ///
- llvm::Type* buildType();
protected:
- llvm::Type* delegate2llvm(Type* dt);
+ ///
+ IrTypeDelegate(Type* dt, llvm::Type* lt);
};
#endif
View
17 ir/irtypestruct.cpp
@@ -84,20 +84,23 @@ bool var_offset_sort_cb(const VarDeclaration* v1, const VarDeclaration* v2)
// this is pretty much the exact same thing we need to do for fields in each
// base class of a class
-llvm::Type* IrTypeStruct::buildType()
+IrTypeStruct* IrTypeStruct::get(StructDeclaration* sd)
{
+ IrTypeStruct* t = new IrTypeStruct(sd);
+ sd->type->irtype = t;
+
IF_LOG Logger::println("Building struct type %s @ %s",
sd->toPrettyChars(), sd->loc.toChars());
LOG_SCOPE;
// if it's a forward declaration, all bets are off, stick with the opaque
if (sd->sizeok != 1)
- return type;
+ return t;
// mirror the sd->fields array but only fill in contributors
size_t n = sd->fields.dim;
LLSmallVector<VarDeclaration*, 16> data(n, NULL);
- default_fields.reserve(n);
+ t->default_fields.reserve(n);
// first fill in the fields with explicit initializers
VarDeclarationIter field_it(sd->fields);
@@ -197,7 +200,7 @@ llvm::Type* IrTypeStruct::buildType()
assert(vd->offset >= offset);
// add to default field list
- default_fields.push_back(vd);
+ t->default_fields.push_back(vd);
// get next aligned offset for this type
size_t alignedoffset = offset;
@@ -229,11 +232,11 @@ llvm::Type* IrTypeStruct::buildType()
}
// set struct body
- isaStruct(type)->setBody(defaultTypes, packed);
+ isaStruct(t->type)->setBody(defaultTypes, packed);
- IF_LOG Logger::cout() << "final struct type: " << *type << std::endl;
+ IF_LOG Logger::cout() << "final struct type: " << *t->type << std::endl;
- return type;
+ return t;
}
//////////////////////////////////////////////////////////////////////////////
View
11 ir/irtypestruct.h
@@ -29,9 +29,6 @@ class IrTypeAggr : public IrType
{
public:
///
- IrTypeAggr(AggregateDeclaration* ad);
-
- ///
IrTypeAggr* isAggr() { return this; }
///
@@ -44,6 +41,9 @@ class IrTypeAggr : public IrType
iterator def_end() { return default_fields.end(); }
protected:
+ ///
+ IrTypeAggr(AggregateDeclaration* ad);
+
/// AggregateDeclaration this type represents.
AggregateDeclaration* aggr;
@@ -61,7 +61,7 @@ class IrTypeStruct : public IrTypeAggr
{
public:
///
- IrTypeStruct(StructDeclaration* sd);
+ static IrTypeStruct* get(StructDeclaration* sd);
///
IrTypeStruct* isStruct() { return this; }
@@ -70,6 +70,9 @@ class IrTypeStruct : public IrTypeAggr
llvm::Type* buildType();
protected:
+ ///
+ IrTypeStruct(StructDeclaration* sd);
+
/// StructDeclaration this type represents.
StructDeclaration* sd;
Something went wrong with that request. Please try again.