diff --git a/gen/irstate.cpp b/gen/irstate.cpp index e2ca388d..73837b1f 100644 --- a/gen/irstate.cpp +++ b/gen/irstate.cpp @@ -1,175 +1,175 @@ -/* DMDFE backend stubs - * This file contains the implementations of the backend routines. - * For dmdfe these do nothing but print a message saying the module - * has been parsed. Substitute your own behaviors for these routimes. - */ - -#include - -#include "gen/llvm.h" - -#include "mtype.h" -#include "declaration.h" -#include "statement.h" - -#include "gen/irstate.h" -#include "tollvm.h" - -IRState* gIR = 0; -llvm::TargetMachine* gTargetMachine = 0; -const llvm::TargetData* gTargetData = 0; -TargetABI* gABI = 0; - -////////////////////////////////////////////////////////////////////////////////////////// -IRScope::IRScope() - : builder(gIR->context()) -{ - begin = end = NULL; -} - -IRScope::IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e) - : builder(b) -{ - begin = b; - end = e; -} - -const IRScope& IRScope::operator=(const IRScope& rhs) -{ - begin = rhs.begin; - end = rhs.end; - builder.SetInsertPoint(begin); - return *this; -} - -////////////////////////////////////////////////////////////////////////////////////////// -IRTargetScope::IRTargetScope() -{ -} - -IRTargetScope::IRTargetScope(Statement* s, EnclosingHandler* enclosinghandler, llvm::BasicBlock* continueTarget, llvm::BasicBlock* breakTarget) -{ - this->s = s; - this->enclosinghandler = enclosinghandler; - this->breakTarget = breakTarget; - this->continueTarget = continueTarget; -} - -////////////////////////////////////////////////////////////////////////////////////////// -IRState::IRState(llvm::Module* m) - : module(m), dibuilder(*m) -{ - interfaceInfoType = NULL; - mutexType = NULL; - moduleRefType = NULL; - - dmodule = 0; - emitMain = false; - mainFunc = 0; - ir.state = this; - asmBlock = NULL; -} - -IrFunction* IRState::func() -{ - assert(!functions.empty() && "Function stack is empty!"); - return functions.back(); -} - -llvm::Function* IRState::topfunc() -{ - assert(!functions.empty() && "Function stack is empty!"); - return functions.back()->func; -} - -TypeFunction* IRState::topfunctype() -{ - assert(!functions.empty() && "Function stack is empty!"); - return functions.back()->type; -} - -llvm::Instruction* IRState::topallocapoint() -{ - assert(!functions.empty() && "AllocaPoint stack is empty!"); - return functions.back()->allocapoint; -} - -IrStruct* IRState::topstruct() -{ - assert(!structs.empty() && "Struct vector is empty!"); - return structs.back(); -} - -IRScope& IRState::scope() -{ - assert(!scopes.empty()); - return scopes.back(); -} - -llvm::BasicBlock* IRState::scopebb() -{ - IRScope& s = scope(); - assert(s.begin); - return s.begin; -} -llvm::BasicBlock* IRState::scopeend() -{ - IRScope& s = scope(); - assert(s.end); - return s.end; -} -bool IRState::scopereturned() -{ - //return scope().returned; - return !scopebb()->empty() && scopebb()->back().isTerminator(); -} - -LLCallSite IRState::CreateCallOrInvoke(LLValue* Callee, const char* Name) -{ - LLSmallVector args; - return CreateCallOrInvoke(Callee, args, Name); -} - -LLCallSite IRState::CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, const char* Name) -{ - LLSmallVector args; - args.push_back(Arg1); - return CreateCallOrInvoke(Callee, args, Name); -} - -LLCallSite IRState::CreateCallOrInvoke2(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, const char* Name) -{ - LLSmallVector args; - args.push_back(Arg1); - args.push_back(Arg2); - return CreateCallOrInvoke(Callee, args, Name); -} - -LLCallSite IRState::CreateCallOrInvoke3(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, const char* Name) -{ - LLSmallVector args; - args.push_back(Arg1); - args.push_back(Arg2); - args.push_back(Arg3); - return CreateCallOrInvoke(Callee, args, Name); -} - -LLCallSite IRState::CreateCallOrInvoke4(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, LLValue* Arg4, const char* Name) -{ - LLSmallVector args; - args.push_back(Arg1); - args.push_back(Arg2); - args.push_back(Arg3); - args.push_back(Arg4); - return CreateCallOrInvoke(Callee, args, Name); -} - - -////////////////////////////////////////////////////////////////////////////////////////// - -IRBuilder<>* IRBuilderHelper::operator->() -{ - IRBuilder<>& b = state->scope().builder; - assert(b.GetInsertBlock() != NULL); - return &b; -} +/* DMDFE backend stubs + * This file contains the implementations of the backend routines. + * For dmdfe these do nothing but print a message saying the module + * has been parsed. Substitute your own behaviors for these routimes. + */ + +#include + +#include "gen/llvm.h" + +#include "mtype.h" +#include "declaration.h" +#include "statement.h" + +#include "gen/irstate.h" +#include "tollvm.h" + +IRState* gIR = 0; +llvm::TargetMachine* gTargetMachine = 0; +const llvm::TargetData* gTargetData = 0; +TargetABI* gABI = 0; + +////////////////////////////////////////////////////////////////////////////////////////// +IRScope::IRScope() + : builder(gIR->context()) +{ + begin = end = NULL; +} + +IRScope::IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e) + : builder(b) +{ + begin = b; + end = e; +} + +const IRScope& IRScope::operator=(const IRScope& rhs) +{ + begin = rhs.begin; + end = rhs.end; + builder.SetInsertPoint(begin); + return *this; +} + +////////////////////////////////////////////////////////////////////////////////////////// +IRTargetScope::IRTargetScope() +{ +} + +IRTargetScope::IRTargetScope(Statement* s, EnclosingHandler* enclosinghandler, llvm::BasicBlock* continueTarget, llvm::BasicBlock* breakTarget) +{ + this->s = s; + this->enclosinghandler = enclosinghandler; + this->breakTarget = breakTarget; + this->continueTarget = continueTarget; +} + +////////////////////////////////////////////////////////////////////////////////////////// +IRState::IRState(llvm::Module* m) + : module(m), dibuilder(*m) +{ + interfaceInfoType = NULL; + mutexType = NULL; + moduleRefType = NULL; + + dmodule = 0; + emitMain = false; + mainFunc = 0; + ir.state = this; + asmBlock = NULL; +} + +IrFunction* IRState::func() +{ + assert(!functions.empty() && "Function stack is empty!"); + return functions.back(); +} + +llvm::Function* IRState::topfunc() +{ + assert(!functions.empty() && "Function stack is empty!"); + return functions.back()->func; +} + +TypeFunction* IRState::topfunctype() +{ + assert(!functions.empty() && "Function stack is empty!"); + return functions.back()->type; +} + +llvm::Instruction* IRState::topallocapoint() +{ + assert(!functions.empty() && "AllocaPoint stack is empty!"); + return functions.back()->allocapoint; +} + +IrStruct* IRState::topstruct() +{ + assert(!structs.empty() && "Struct vector is empty!"); + return structs.back(); +} + +IRScope& IRState::scope() +{ + assert(!scopes.empty()); + return scopes.back(); +} + +llvm::BasicBlock* IRState::scopebb() +{ + IRScope& s = scope(); + assert(s.begin); + return s.begin; +} +llvm::BasicBlock* IRState::scopeend() +{ + IRScope& s = scope(); + assert(s.end); + return s.end; +} +bool IRState::scopereturned() +{ + //return scope().returned; + return !scopebb()->empty() && scopebb()->back().isTerminator(); +} + +LLCallSite IRState::CreateCallOrInvoke(LLValue* Callee, const char* Name) +{ + LLSmallVector args; + return CreateCallOrInvoke(Callee, args, Name); +} + +LLCallSite IRState::CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, const char* Name) +{ + LLSmallVector args; + args.push_back(Arg1); + return CreateCallOrInvoke(Callee, args, Name); +} + +LLCallSite IRState::CreateCallOrInvoke2(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, const char* Name) +{ + LLSmallVector args; + args.push_back(Arg1); + args.push_back(Arg2); + return CreateCallOrInvoke(Callee, args, Name); +} + +LLCallSite IRState::CreateCallOrInvoke3(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, const char* Name) +{ + LLSmallVector args; + args.push_back(Arg1); + args.push_back(Arg2); + args.push_back(Arg3); + return CreateCallOrInvoke(Callee, args, Name); +} + +LLCallSite IRState::CreateCallOrInvoke4(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, LLValue* Arg4, const char* Name) +{ + LLSmallVector args; + args.push_back(Arg1); + args.push_back(Arg2); + args.push_back(Arg3); + args.push_back(Arg4); + return CreateCallOrInvoke(Callee, args, Name); +} + + +////////////////////////////////////////////////////////////////////////////////////////// + +IRBuilder<>* IRBuilderHelper::operator->() +{ + IRBuilder<>& b = state->scope().builder; + assert(b.GetInsertBlock() != NULL); + return &b; +} diff --git a/gen/irstate.h b/gen/irstate.h index 3c4c7804..e4aa387c 100644 --- a/gen/irstate.h +++ b/gen/irstate.h @@ -1,234 +1,234 @@ -#ifndef LDC_GEN_IRSTATE_H -#define LDC_GEN_IRSTATE_H - -#include -#include -#include -#include - -#include "root.h" -#include "aggregate.h" - -#include "ir/irfunction.h" -#include "ir/irstruct.h" -#include "ir/irvar.h" - -#if LDC_LLVM_VER >= 302 -#include "llvm/DIBuilder.h" -#else -#include "llvm/Analysis/DIBuilder.h" -#endif -#include "llvm/Support/CallSite.h" - -namespace llvm { - class LLVMContext; - class TargetMachine; -} - -// global ir state for current module -struct IRState; -struct TargetABI; - -extern IRState* gIR; -extern llvm::TargetMachine* gTargetMachine; -extern const llvm::TargetData* gTargetData; -extern TargetABI* gABI; - -struct TypeFunction; -struct TypeStruct; -struct ClassDeclaration; -struct FuncDeclaration; -struct Module; -struct TypeStruct; -struct BaseClass; -struct AnonDeclaration; - -struct IrModule; - -// represents a scope -struct IRScope -{ - llvm::BasicBlock* begin; - llvm::BasicBlock* end; - IRBuilder<> builder; - - IRScope(); - IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e); - - const IRScope& operator=(const IRScope& rhs); - -#if DMDV2 - // list of variables needing destruction - std::vector varsInScope; -#endif -}; - -struct IRBuilderHelper -{ - IRState* state; - IRBuilder<>* operator->(); -}; - -struct IRAsmStmt -{ - IRAsmStmt() - : isBranchToLabel(NULL) {} - - std::string code; - std::string out_c; - std::string in_c; - std::vector out; - std::vector in; - - // if this is nonzero, it contains the target label - Identifier* isBranchToLabel; -}; - -struct IRAsmBlock -{ - std::deque s; - std::set clobs; - size_t outputcount; - - // stores the labels within the asm block - std::vector internalLabels; - - AsmBlockStatement* asmBlock; - LLType* retty; - unsigned retn; - bool retemu; // emulate abi ret with a temporary - LLValue* (*retfixup)(IRBuilderHelper b, LLValue* orig); // Modifies retval - - IRAsmBlock(AsmBlockStatement* b) - : outputcount(0), asmBlock(b), retty(NULL), retn(0), retemu(false), - retfixup(NULL) - {} -}; - -// represents the module -struct IRState -{ - IRState(llvm::Module* m); - - // module - Module* dmodule; - llvm::Module* module; - - // interface info type, used in DtoInterfaceInfoType - LLStructType* interfaceInfoType; - LLStructType* mutexType; - LLStructType* moduleRefType; - - // helper to get the LLVMContext of the module - llvm::LLVMContext& context() const { return module->getContext(); } - - // functions - typedef std::vector FunctionVector; - FunctionVector functions; - IrFunction* func(); - - llvm::Function* topfunc(); - TypeFunction* topfunctype(); - llvm::Instruction* topallocapoint(); - - // structs - typedef std::vector StructVector; - StructVector structs; - IrStruct* topstruct(); - - // D main function - bool emitMain; - llvm::Function* mainFunc; - - // basic block scopes - std::vector scopes; - IRScope& scope(); -#if DMDV2 - std::vector &varsInScope() { return scope().varsInScope; } -#endif - llvm::BasicBlock* scopebb(); - llvm::BasicBlock* scopeend(); - bool scopereturned(); - - // create a call or invoke, depending on the landing pad info - // the template function is defined further down in this file - template - llvm::CallSite CreateCallOrInvoke(LLValue* Callee, const T& args, const char* Name=""); - llvm::CallSite CreateCallOrInvoke(LLValue* Callee, const char* Name=""); - llvm::CallSite CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, const char* Name=""); - llvm::CallSite CreateCallOrInvoke2(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, const char* Name=""); - llvm::CallSite CreateCallOrInvoke3(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, const char* Name=""); - llvm::CallSite CreateCallOrInvoke4(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, LLValue* Arg4, const char* Name=""); - - // this holds the array being indexed or sliced so $ will work - // might be a better way but it works. problem is I only get a - // VarDeclaration for __dollar, but I can't see how to get the - // array pointer from this :( - std::vector arrays; - - // builder helper - IRBuilderHelper ir; - - // debug info helper - llvm::DIBuilder dibuilder; - - // static ctors/dtors/unittests - typedef std::list FuncDeclList; - typedef std::list GatesList; - FuncDeclList ctors; - FuncDeclList dtors; -#if DMDV2 - FuncDeclList sharedCtors; - FuncDeclList sharedDtors; - GatesList gates; - GatesList sharedGates; -#endif - FuncDeclList unitTests; - - // all template instances that had members emitted - // currently only filled for singleobj - // used to make sure the complete template instance gets emitted in the - // first file that touches a member, see #318 - typedef std::set TemplateInstanceSet; - TemplateInstanceSet seenTemplateInstances; - - // for inline asm - IRAsmBlock* asmBlock; - std::ostringstream nakedAsm; - - // 'used' array solely for keeping a reference to globals - std::vector usedArray; -}; - -template -llvm::CallSite IRState::CreateCallOrInvoke(LLValue* Callee, const T &args, const char* Name) -{ - llvm::BasicBlock* pad = func()->gen->landingPad; - if(pad) - { - // intrinsics don't support invoking and 'nounwind' functions don't need it. - LLFunction* funcval = llvm::dyn_cast(Callee); - if (funcval && (funcval->isIntrinsic() || funcval->doesNotThrow())) - { - llvm::CallInst* call = ir->CreateCall(Callee, args, Name); - call->setAttributes(funcval->getAttributes()); - return call; - } - - llvm::BasicBlock* postinvoke = llvm::BasicBlock::Create(gIR->context(), "postinvoke", topfunc(), scopeend()); - llvm::InvokeInst* invoke = ir->CreateInvoke(Callee, postinvoke, pad, args, Name); - if (LLFunction* fn = llvm::dyn_cast(Callee)) - invoke->setAttributes(fn->getAttributes()); - scope() = IRScope(postinvoke, scopeend()); - return invoke; - } - else - { - llvm::CallInst* call = ir->CreateCall(Callee, args, Name); - if (LLFunction* fn = llvm::dyn_cast(Callee)) - call->setAttributes(fn->getAttributes()); - return call; - } -} - -#endif // LDC_GEN_IRSTATE_H +#ifndef LDC_GEN_IRSTATE_H +#define LDC_GEN_IRSTATE_H + +#include +#include +#include +#include + +#include "root.h" +#include "aggregate.h" + +#include "ir/irfunction.h" +#include "ir/irstruct.h" +#include "ir/irvar.h" + +#if LDC_LLVM_VER >= 302 +#include "llvm/DIBuilder.h" +#else +#include "llvm/Analysis/DIBuilder.h" +#endif +#include "llvm/Support/CallSite.h" + +namespace llvm { + class LLVMContext; + class TargetMachine; +} + +// global ir state for current module +struct IRState; +struct TargetABI; + +extern IRState* gIR; +extern llvm::TargetMachine* gTargetMachine; +extern const llvm::TargetData* gTargetData; +extern TargetABI* gABI; + +struct TypeFunction; +struct TypeStruct; +struct ClassDeclaration; +struct FuncDeclaration; +struct Module; +struct TypeStruct; +struct BaseClass; +struct AnonDeclaration; + +struct IrModule; + +// represents a scope +struct IRScope +{ + llvm::BasicBlock* begin; + llvm::BasicBlock* end; + IRBuilder<> builder; + + IRScope(); + IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e); + + const IRScope& operator=(const IRScope& rhs); + +#if DMDV2 + // list of variables needing destruction + std::vector varsInScope; +#endif +}; + +struct IRBuilderHelper +{ + IRState* state; + IRBuilder<>* operator->(); +}; + +struct IRAsmStmt +{ + IRAsmStmt() + : isBranchToLabel(NULL) {} + + std::string code; + std::string out_c; + std::string in_c; + std::vector out; + std::vector in; + + // if this is nonzero, it contains the target label + Identifier* isBranchToLabel; +}; + +struct IRAsmBlock +{ + std::deque s; + std::set clobs; + size_t outputcount; + + // stores the labels within the asm block + std::vector internalLabels; + + AsmBlockStatement* asmBlock; + LLType* retty; + unsigned retn; + bool retemu; // emulate abi ret with a temporary + LLValue* (*retfixup)(IRBuilderHelper b, LLValue* orig); // Modifies retval + + IRAsmBlock(AsmBlockStatement* b) + : outputcount(0), asmBlock(b), retty(NULL), retn(0), retemu(false), + retfixup(NULL) + {} +}; + +// represents the module +struct IRState +{ + IRState(llvm::Module* m); + + // module + Module* dmodule; + llvm::Module* module; + + // interface info type, used in DtoInterfaceInfoType + LLStructType* interfaceInfoType; + LLStructType* mutexType; + LLStructType* moduleRefType; + + // helper to get the LLVMContext of the module + llvm::LLVMContext& context() const { return module->getContext(); } + + // functions + typedef std::vector FunctionVector; + FunctionVector functions; + IrFunction* func(); + + llvm::Function* topfunc(); + TypeFunction* topfunctype(); + llvm::Instruction* topallocapoint(); + + // structs + typedef std::vector StructVector; + StructVector structs; + IrStruct* topstruct(); + + // D main function + bool emitMain; + llvm::Function* mainFunc; + + // basic block scopes + std::vector scopes; + IRScope& scope(); +#if DMDV2 + std::vector &varsInScope() { return scope().varsInScope; } +#endif + llvm::BasicBlock* scopebb(); + llvm::BasicBlock* scopeend(); + bool scopereturned(); + + // create a call or invoke, depending on the landing pad info + // the template function is defined further down in this file + template + llvm::CallSite CreateCallOrInvoke(LLValue* Callee, const T& args, const char* Name=""); + llvm::CallSite CreateCallOrInvoke(LLValue* Callee, const char* Name=""); + llvm::CallSite CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, const char* Name=""); + llvm::CallSite CreateCallOrInvoke2(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, const char* Name=""); + llvm::CallSite CreateCallOrInvoke3(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, const char* Name=""); + llvm::CallSite CreateCallOrInvoke4(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, LLValue* Arg4, const char* Name=""); + + // this holds the array being indexed or sliced so $ will work + // might be a better way but it works. problem is I only get a + // VarDeclaration for __dollar, but I can't see how to get the + // array pointer from this :( + std::vector arrays; + + // builder helper + IRBuilderHelper ir; + + // debug info helper + llvm::DIBuilder dibuilder; + + // static ctors/dtors/unittests + typedef std::list FuncDeclList; + typedef std::list GatesList; + FuncDeclList ctors; + FuncDeclList dtors; +#if DMDV2 + FuncDeclList sharedCtors; + FuncDeclList sharedDtors; + GatesList gates; + GatesList sharedGates; +#endif + FuncDeclList unitTests; + + // all template instances that had members emitted + // currently only filled for singleobj + // used to make sure the complete template instance gets emitted in the + // first file that touches a member, see #318 + typedef std::set TemplateInstanceSet; + TemplateInstanceSet seenTemplateInstances; + + // for inline asm + IRAsmBlock* asmBlock; + std::ostringstream nakedAsm; + + // 'used' array solely for keeping a reference to globals + std::vector usedArray; +}; + +template +llvm::CallSite IRState::CreateCallOrInvoke(LLValue* Callee, const T &args, const char* Name) +{ + llvm::BasicBlock* pad = func()->gen->landingPad; + if(pad) + { + // intrinsics don't support invoking and 'nounwind' functions don't need it. + LLFunction* funcval = llvm::dyn_cast(Callee); + if (funcval && (funcval->isIntrinsic() || funcval->doesNotThrow())) + { + llvm::CallInst* call = ir->CreateCall(Callee, args, Name); + call->setAttributes(funcval->getAttributes()); + return call; + } + + llvm::BasicBlock* postinvoke = llvm::BasicBlock::Create(gIR->context(), "postinvoke", topfunc(), scopeend()); + llvm::InvokeInst* invoke = ir->CreateInvoke(Callee, postinvoke, pad, args, Name); + if (LLFunction* fn = llvm::dyn_cast(Callee)) + invoke->setAttributes(fn->getAttributes()); + scope() = IRScope(postinvoke, scopeend()); + return invoke; + } + else + { + llvm::CallInst* call = ir->CreateCall(Callee, args, Name); + if (LLFunction* fn = llvm::dyn_cast(Callee)) + call->setAttributes(fn->getAttributes()); + return call; + } +} + +#endif // LDC_GEN_IRSTATE_H diff --git a/gen/typinf.cpp b/gen/typinf.cpp index 2dca8aa6..acd2264e 100644 --- a/gen/typinf.cpp +++ b/gen/typinf.cpp @@ -1,924 +1,924 @@ - - -// Copyright (c) 1999-2004 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// Modifications for LDC: -// Copyright (c) 2007 by Tomas Lindquist Olsen -// tomas at famolsen dk - -#include -#include - -#include "gen/llvm.h" - -#include "mars.h" -#include "module.h" -#include "mtype.h" -#include "scope.h" -#include "init.h" -#include "expression.h" -#include "attrib.h" -#include "declaration.h" -#include "template.h" -#include "id.h" -#include "enum.h" -#include "import.h" -#include "aggregate.h" - -#include "gen/irstate.h" -#include "gen/logger.h" -#include "gen/runtime.h" -#include "gen/tollvm.h" -#include "gen/llvmhelpers.h" -#include "gen/arrays.h" -#include "gen/structs.h" -#include "gen/classes.h" -#include "gen/linkage.h" -#include "gen/metadata.h" -#include "gen/rttibuilder.h" - -#include "ir/irvar.h" -#include "ir/irtype.h" - -/******************************************* - * Get a canonicalized form of the TypeInfo for use with the internal - * runtime library routines. Canonicalized in that static arrays are - * represented as dynamic arrays, enums are represented by their - * underlying type, etc. This reduces the number of TypeInfo's needed, - * so we can use the custom internal ones more. - */ - -Expression *Type::getInternalTypeInfo(Scope *sc) -{ TypeInfoDeclaration *tid; - Expression *e; - Type *t; - static TypeInfoDeclaration *internalTI[TMAX]; - - //printf("Type::getInternalTypeInfo() %s\n", toChars()); - t = toBasetype(); - switch (t->ty) - { - case Tsarray: -#if 0 - // convert to corresponding dynamic array type - t = t->nextOf()->mutableOf()->arrayOf(); -#endif - break; - - case Tclass: - if (static_cast(t)->sym->isInterfaceDeclaration()) - break; - goto Linternal; - - case Tarray: - #if DMDV2 - // convert to corresponding dynamic array type - t = t->nextOf()->mutableOf()->arrayOf(); - #endif - if (t->nextOf()->ty != Tclass) - break; - goto Linternal; - - case Tfunction: - case Tdelegate: - case Tpointer: - Linternal: - tid = internalTI[t->ty]; - if (!tid) - { tid = new TypeInfoDeclaration(t, 1); - internalTI[t->ty] = tid; - } - e = new VarExp(0, tid); - e = e->addressOf(sc); - e->type = tid->type; // do this so we don't get redundant dereference - return e; - - default: - break; - } - //printf("\tcalling getTypeInfo() %s\n", t->toChars()); - return t->getTypeInfo(sc); -} - -/**************************************************** - * Get the exact TypeInfo. - */ - -Expression *Type::getTypeInfo(Scope *sc) -{ - //printf("Type::getTypeInfo() %p, %s\n", this, toChars()); - if (!Type::typeinfo) - { - error(0, "TypeInfo not found. object.d may be incorrectly installed or corrupt, compile with -v switch"); - fatal(); - } - - Expression *e = 0; - Type *t = merge2(); // do this since not all Type's are merge'd - - if (!t->vtinfo) - { -#if DMDV2 - if (t->isShared()) - t->vtinfo = new TypeInfoSharedDeclaration(t); - else if (t->isConst()) - t->vtinfo = new TypeInfoConstDeclaration(t); - else if (t->isImmutable()) - t->vtinfo = new TypeInfoInvariantDeclaration(t); - else if (t->isWild()) - t->vtinfo = new TypeInfoWildDeclaration(t); - else -#endif - t->vtinfo = t->getTypeInfoDeclaration(); - assert(t->vtinfo); - - /* If this has a custom implementation in std/typeinfo, then - * do not generate a COMDAT for it. - */ - if (!t->builtinTypeInfo()) - { // Generate COMDAT - if (sc) // if in semantic() pass - { // Find module that will go all the way to an object file - Module *m = sc->module->importedFrom; - m->members->push(t->vtinfo); - } - else // if in obj generation pass - { -#if IN_DMD - t->vtinfo->toObjFile(0); // TODO: multiobj -#else - t->vtinfo->codegen(sir); -#endif - } - } - } - e = new VarExp(0, t->vtinfo); - e = e->addressOf(sc); - e->type = t->vtinfo->type; // do this so we don't get redundant dereference - return e; -} - -enum RET TypeFunction::retStyle() -{ - return RETstack; -} - -TypeInfoDeclaration *Type::getTypeInfoDeclaration() -{ - //printf("Type::getTypeInfoDeclaration() %s\n", toChars()); - return new TypeInfoDeclaration(this, 0); -} - -TypeInfoDeclaration *TypeTypedef::getTypeInfoDeclaration() -{ - return new TypeInfoTypedefDeclaration(this); -} - -TypeInfoDeclaration *TypePointer::getTypeInfoDeclaration() -{ - return new TypeInfoPointerDeclaration(this); -} - -TypeInfoDeclaration *TypeDArray::getTypeInfoDeclaration() -{ - return new TypeInfoArrayDeclaration(this); -} - -TypeInfoDeclaration *TypeSArray::getTypeInfoDeclaration() -{ - return new TypeInfoStaticArrayDeclaration(this); -} - -TypeInfoDeclaration *TypeAArray::getTypeInfoDeclaration() -{ - return new TypeInfoAssociativeArrayDeclaration(this); -} - -TypeInfoDeclaration *TypeStruct::getTypeInfoDeclaration() -{ - return new TypeInfoStructDeclaration(this); -} - -TypeInfoDeclaration *TypeClass::getTypeInfoDeclaration() -{ - if (sym->isInterfaceDeclaration()) - return new TypeInfoInterfaceDeclaration(this); - else - return new TypeInfoClassDeclaration(this); -} - -#if DMDV2 -TypeInfoDeclaration *TypeVector::getTypeInfoDeclaration() -{ - return new TypeInfoVectorDeclaration(this); -} -#endif - -TypeInfoDeclaration *TypeEnum::getTypeInfoDeclaration() -{ - return new TypeInfoEnumDeclaration(this); -} - -TypeInfoDeclaration *TypeFunction::getTypeInfoDeclaration() -{ - return new TypeInfoFunctionDeclaration(this); -} - -TypeInfoDeclaration *TypeDelegate::getTypeInfoDeclaration() -{ - return new TypeInfoDelegateDeclaration(this); -} - -TypeInfoDeclaration *TypeTuple::getTypeInfoDeclaration() -{ - return new TypeInfoTupleDeclaration(this); -} - -/* ========================================================================= */ - -/* These decide if there's an instance for them already in std.typeinfo, - * because then the compiler doesn't need to build one. - */ - -int Type::builtinTypeInfo() -{ - return 0; -} - -int TypeBasic::builtinTypeInfo() -{ -#if DMDV2 - return mod ? 0 : 1; -#else - return 1; -#endif -} - -int TypeDArray::builtinTypeInfo() -{ -#if DMDV2 - return !mod && (next->isTypeBasic() != NULL && !next->mod || - // strings are so common, make them builtin - next->ty == Tchar && next->mod == MODimmutable); -#else - return next->isTypeBasic() != NULL; -#endif -} - -int TypeClass::builtinTypeInfo() -{ - /* This is statically put out with the ClassInfo, so - * claim it is built in so it isn't regenerated by each module. - */ -#if IN_DMD - return mod ? 0 : 1; -#elif IN_LLVM - // FIXME if I enable this, the way LDC does typeinfo will cause a bunch - // of linker errors to missing class typeinfo definitions. - return 0; -#endif -} - -/* ========================================================================= */ - -////////////////////////////////////////////////////////////////////////////// -// MAGIC PLACE -// (wut?) -////////////////////////////////////////////////////////////////////////////// - -void DtoResolveTypeInfo(TypeInfoDeclaration* tid); -void DtoDeclareTypeInfo(TypeInfoDeclaration* tid); - -void TypeInfoDeclaration::codegen(Ir*) -{ - DtoResolveTypeInfo(this); -} - -void DtoResolveTypeInfo(TypeInfoDeclaration* tid) -{ - if (tid->ir.resolved) return; - tid->ir.resolved = true; - - Logger::println("DtoResolveTypeInfo(%s)", tid->toChars()); - LOG_SCOPE; - - std::string mangle(tid->mangle()); - - IrGlobal* irg = new IrGlobal(tid); - irg->value = gIR->module->getGlobalVariable(mangle); - - if (!irg->value) { - if (tid->tinfo->builtinTypeInfo()) // this is a declaration of a builtin __initZ var - irg->type = Type::typeinfo->type->irtype->getType(); - else - irg->type = LLStructType::create(gIR->context(), tid->toPrettyChars()); - irg->value = new llvm::GlobalVariable(*gIR->module, irg->type, true, - TYPEINFO_LINKAGE_TYPE, NULL, mangle); - } else { - irg->type = irg->value->getType()->getContainedType(0); - } - - tid->ir.irGlobal = irg; - -#if USE_METADATA - // don't do this for void or llvm will crash - if (tid->tinfo->ty != Tvoid) { - // Add some metadata for use by optimization passes. - std::string metaname = std::string(TD_PREFIX) + mangle; - llvm::NamedMDNode* meta = gIR->module->getNamedMetadata(metaname); - // Don't generate metadata for non-concrete types - // (such as tuple types, slice types, typeof(expr), etc.) - if (!meta && tid->tinfo->toBasetype()->ty < Terror) { - // Construct the fields - MDNodeField* mdVals[TD_NumFields]; - if (TD_Confirm >= 0) - mdVals[TD_Confirm] = llvm::cast(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); - } - } -#endif // USE_METADATA - - DtoDeclareTypeInfo(tid); -} - -void DtoDeclareTypeInfo(TypeInfoDeclaration* tid) -{ - DtoResolveTypeInfo(tid); - - if (tid->ir.declared) return; - tid->ir.declared = true; - - Logger::println("DtoDeclareTypeInfo(%s)", tid->toChars()); - LOG_SCOPE; - - if (Logger::enabled()) - { - std::string mangled(tid->mangle()); - Logger::println("type = '%s'", tid->tinfo->toChars()); - Logger::println("typeinfo mangle: %s", mangled.c_str()); - } - - IrGlobal* irg = tid->ir.irGlobal; - assert(irg->value != NULL); - - // this is a declaration of a builtin __initZ var - if (tid->tinfo->builtinTypeInfo()) { - LLGlobalVariable* g = isaGlobalVar(irg->value); - g->setLinkage(llvm::GlobalValue::ExternalLinkage); - return; - } - - // define custom typedef - tid->llvmDefine(); -} - -/* ========================================================================= */ - -void TypeInfoDeclaration::llvmDefine() -{ - Logger::println("TypeInfoDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfo); - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoTypedefDeclaration::llvmDefine() -{ - Logger::println("TypeInfoTypedefDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfotypedef); - - assert(tinfo->ty == Ttypedef); - TypeTypedef *tc = static_cast(tinfo); - TypedefDeclaration *sd = tc->sym; - - // TypeInfo base - sd->basetype = sd->basetype->merge(); // dmd does it ... why? - b.push_typeinfo(sd->basetype); - - // char[] name - b.push_string(sd->toPrettyChars()); - - // void[] init - // emit null array if we should use the basetype, or if the basetype - // uses default initialization. - if (tinfo->isZeroInit(0) || !sd->init) - { - b.push_null_void_array(); - } - // otherwise emit a void[] with the default initializer - else - { - LLConstant* C = DtoConstInitializer(sd->loc, sd->basetype, sd->init); - b.push_void_array(C, sd->basetype, sd); - } - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoEnumDeclaration::llvmDefine() -{ - Logger::println("TypeInfoEnumDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfoenum); - - assert(tinfo->ty == Tenum); - TypeEnum *tc = static_cast(tinfo); - EnumDeclaration *sd = tc->sym; - - // TypeInfo base - b.push_typeinfo(sd->memtype); - - // char[] name - b.push_string(sd->toPrettyChars()); - - // void[] init - // emit void[] with the default initialier, the array is null if the default - // initializer is zero - if (!sd->defaultval || tinfo->isZeroInit(0)) - { - b.push_null_void_array(); - } - // otherwise emit a void[] with the default initializer - else - { - LLType* memty = DtoType(sd->memtype); -#if DMDV2 - LLConstant* C = LLConstantInt::get(memty, sd->defaultval->toInteger(), !sd->memtype->isunsigned()); -#else - LLConstant* C = LLConstantInt::get(memty, sd->defaultval, !sd->memtype->isunsigned()); -#endif - b.push_void_array(C, sd->memtype, sd); - } - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoPointerDeclaration::llvmDefine() -{ - Logger::println("TypeInfoPointerDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfopointer); - // TypeInfo base - b.push_typeinfo(tinfo->nextOf()); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoArrayDeclaration::llvmDefine() -{ - Logger::println("TypeInfoArrayDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfoarray); - // TypeInfo base - b.push_typeinfo(tinfo->nextOf()); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoStaticArrayDeclaration::llvmDefine() -{ - Logger::println("TypeInfoStaticArrayDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - assert(tinfo->ty == Tsarray); - TypeSArray *tc = static_cast(tinfo); - - RTTIBuilder b(Type::typeinfostaticarray); - - // value typeinfo - b.push_typeinfo(tc->nextOf()); - - // length - b.push(DtoConstSize_t(static_cast(tc->dim->toUInteger()))); - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoAssociativeArrayDeclaration::llvmDefine() -{ - Logger::println("TypeInfoAssociativeArrayDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - assert(tinfo->ty == Taarray); - TypeAArray *tc = static_cast(tinfo); - - RTTIBuilder b(Type::typeinfoassociativearray); - - // value typeinfo - b.push_typeinfo(tc->nextOf()); - - // key typeinfo - b.push_typeinfo(tc->index); - -#if DMDV2 - // impl typeinfo - b.push_typeinfo(tc->getImpl()->type); -#endif - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoFunctionDeclaration::llvmDefine() -{ - Logger::println("TypeInfoFunctionDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfofunction); - // TypeInfo base - b.push_typeinfo(tinfo->nextOf()); - // string deco - b.push_string(tinfo->deco); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoDelegateDeclaration::llvmDefine() -{ - Logger::println("TypeInfoDelegateDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - assert(tinfo->ty == Tdelegate); - Type* ret_type = tinfo->nextOf()->nextOf(); - - RTTIBuilder b(Type::typeinfodelegate); - // TypeInfo base - b.push_typeinfo(ret_type); - // string deco - b.push_string(tinfo->deco); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -static FuncDeclaration* find_method_overload(AggregateDeclaration* ad, Identifier* id, TypeFunction* tf, Module* mod) -{ - Dsymbol *s = search_function(ad, id); - FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; - if (fdx) - { - FuncDeclaration *fd = fdx->overloadExactMatch(tf, mod); - if (fd) - { - return fd; - } - } - return NULL; -} - -void TypeInfoStructDeclaration::llvmDefine() -{ - Logger::println("TypeInfoStructDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - // make sure struct is resolved - assert(tinfo->ty == Tstruct); - TypeStruct *tc = static_cast(tinfo); - StructDeclaration *sd = tc->sym; - - // can't emit typeinfo for forward declarations - if (sd->sizeok != 1) - { - sd->error("cannot emit TypeInfo for forward declaration"); - fatal(); - } - - sd->codegen(Type::sir); - IrStruct* irstruct = sd->ir.irStruct; - - RTTIBuilder b(Type::typeinfostruct); - - // char[] name - b.push_string(sd->toPrettyChars()); - - // 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()); - b.push_void_array(init_size, irstruct->getInitSymbol()); - - // toX functions ground work - static TypeFunction *tftohash; - static TypeFunction *tftostring; - - if (!tftohash) - { - Scope sc; - tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd); -#if DMDV2 - tftohash ->mod = MODconst; -#endif - tftohash = static_cast(tftohash->semantic(0, &sc)); - -#if DMDV2 - Type *retType = Type::tchar->invariantOf()->arrayOf(); -#else - Type *retType = Type::tchar->arrayOf(); -#endif - tftostring = new TypeFunction(NULL, retType, 0, LINKd); - tftostring = static_cast(tftostring->semantic(0, &sc)); - } - - // this one takes a parameter, so we need to build a new one each time - // to get the right type. can we avoid this? - TypeFunction *tfcmpptr; - { - Scope sc; - Parameters *arguments = new Parameters; -#if STRUCTTHISREF - // arg type is ref const T - Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL); -#else - // arg type is const T* - Parameter *arg = new Parameter(STCin, tc->pointerTo(), NULL, NULL); -#endif - arguments->push(arg); - tfcmpptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); -#if DMDV2 - tfcmpptr->mod = MODconst; -#endif - tfcmpptr = static_cast(tfcmpptr->semantic(0, &sc)); - } - - // well use this module for all overload lookups - Module *gm = getModule(); - - // toHash - FuncDeclaration* fd = find_method_overload(sd, Id::tohash, tftohash, gm); - b.push_funcptr(fd); - - // opEquals -#if DMDV2 - fd = sd->xeq; -#else - fd = find_method_overload(sd, Id::eq, tfcmpptr, gm); -#endif - b.push_funcptr(fd); - - // opCmp - fd = find_method_overload(sd, Id::cmp, tfcmpptr, gm); - b.push_funcptr(fd); - - // toString - fd = find_method_overload(sd, Id::tostring, tftostring, gm); - b.push_funcptr(fd); - - // uint m_flags; - unsigned hasptrs = tc->hasPointers() ? 1 : 0; - b.push_uint(hasptrs); - -#if DMDV2 - - ClassDeclaration* tscd = Type::typeinfostruct; - - assert((!global.params.is64bit && tscd->fields.dim == 11) || - (global.params.is64bit && tscd->fields.dim == 13)); - - // const(MemberInfo[]) function(in char[]) xgetMembers; - b.push_funcptr(sd->findGetMembers()); - - //void function(void*) xdtor; - b.push_funcptr(sd->dtor); - - //void function(void*) xpostblit; - FuncDeclaration *xpostblit = sd->postblit; - if (xpostblit && sd->postblit->storage_class & STCdisable) - xpostblit = 0; - b.push_funcptr(xpostblit); - - //uint m_align; - b.push_uint(tc->alignsize()); - - if (global.params.is64bit) - { - TypeTuple *tup = tc->toArgTypes(); - assert(tup->arguments->dim <= 2); - for (unsigned i = 0; i < 2; i++) - { - if (i < tup->arguments->dim) - { - Type *targ = static_cast(tup->arguments->data[i])->type; - targ = targ->merge(); - b.push_typeinfo(targ); - } - else - b.push_null(Type::typeinfo->type); - } - } - -#endif - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -#if DMDV2 -void TypeInfoClassDeclaration::codegen(Ir*i) -{ - - IrGlobal* irg = new IrGlobal(this); - ir.irGlobal = irg; - assert(tinfo->ty == Tclass); - TypeClass *tc = static_cast(tinfo); - tc->sym->codegen(Type::sir); // make sure class is resolved - irg->value = tc->sym->ir.irStruct->getClassInfoSymbol(); -} -#endif - -void TypeInfoClassDeclaration::llvmDefine() -{ -#if DMDV2 - assert(0); -#endif - Logger::println("TypeInfoClassDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - // make sure class is resolved - assert(tinfo->ty == Tclass); - TypeClass *tc = static_cast(tinfo); - tc->sym->codegen(Type::sir); - - RTTIBuilder b(Type::typeinfoclass); - - // TypeInfo base - b.push_classinfo(tc->sym); - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoInterfaceDeclaration::llvmDefine() -{ - Logger::println("TypeInfoInterfaceDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - // make sure interface is resolved - assert(tinfo->ty == Tclass); - TypeClass *tc = static_cast(tinfo); - tc->sym->codegen(Type::sir); - - RTTIBuilder b(Type::typeinfointerface); - - // TypeInfo base - b.push_classinfo(tc->sym); - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoTupleDeclaration::llvmDefine() -{ - Logger::println("TypeInfoTupleDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - // create elements array - assert(tinfo->ty == Ttuple); - TypeTuple *tu = static_cast(tinfo); - - size_t dim = tu->arguments->dim; - std::vector arrInits; - arrInits.reserve(dim); - - LLType* tiTy = DtoType(Type::typeinfo->type); - - for (size_t i = 0; i < dim; i++) - { - Parameter *arg = static_cast(tu->arguments->data[i]); - arrInits.push_back(DtoTypeInfoOf(arg->type, true)); - } - - // build array - LLArrayType* arrTy = LLArrayType::get(tiTy, dim); - LLConstant* arrC = LLConstantArray::get(arrTy, arrInits); - - RTTIBuilder b(Type::typeinfotypelist); - - // push TypeInfo[] - b.push_array(arrC, dim, Type::typeinfo->type, NULL); - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -#if DMDV2 - -void TypeInfoConstDeclaration::llvmDefine() -{ - Logger::println("TypeInfoConstDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfoconst); - // TypeInfo base - b.push_typeinfo(tinfo->mutableOf()->merge()); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoInvariantDeclaration::llvmDefine() -{ - Logger::println("TypeInfoInvariantDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfoinvariant); - // TypeInfo base - b.push_typeinfo(tinfo->mutableOf()->merge()); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoSharedDeclaration::llvmDefine() -{ - Logger::println("TypeInfoSharedDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfoshared); - // TypeInfo base - b.push_typeinfo(tinfo->unSharedOf()->merge()); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoWildDeclaration::llvmDefine() -{ - Logger::println("TypeInfoWildDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfowild); - // TypeInfo base - b.push_typeinfo(tinfo->mutableOf()->merge()); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -#if DMDV2 - -void TypeInfoVectorDeclaration::llvmDefine() -{ - Logger::println("TypeInfoVectorDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - assert(tinfo->ty == Tvector); - TypeVector *tv = static_cast(tinfo); - - RTTIBuilder b(Type::typeinfovector); - // TypeInfo base - b.push_typeinfo(tv->basetype); - // finish - b.finalize(ir.irGlobal); -} - -#endif - -#endif + + +// Copyright (c) 1999-2004 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +// Modifications for LDC: +// Copyright (c) 2007 by Tomas Lindquist Olsen +// tomas at famolsen dk + +#include +#include + +#include "gen/llvm.h" + +#include "mars.h" +#include "module.h" +#include "mtype.h" +#include "scope.h" +#include "init.h" +#include "expression.h" +#include "attrib.h" +#include "declaration.h" +#include "template.h" +#include "id.h" +#include "enum.h" +#include "import.h" +#include "aggregate.h" + +#include "gen/irstate.h" +#include "gen/logger.h" +#include "gen/runtime.h" +#include "gen/tollvm.h" +#include "gen/llvmhelpers.h" +#include "gen/arrays.h" +#include "gen/structs.h" +#include "gen/classes.h" +#include "gen/linkage.h" +#include "gen/metadata.h" +#include "gen/rttibuilder.h" + +#include "ir/irvar.h" +#include "ir/irtype.h" + +/******************************************* + * Get a canonicalized form of the TypeInfo for use with the internal + * runtime library routines. Canonicalized in that static arrays are + * represented as dynamic arrays, enums are represented by their + * underlying type, etc. This reduces the number of TypeInfo's needed, + * so we can use the custom internal ones more. + */ + +Expression *Type::getInternalTypeInfo(Scope *sc) +{ TypeInfoDeclaration *tid; + Expression *e; + Type *t; + static TypeInfoDeclaration *internalTI[TMAX]; + + //printf("Type::getInternalTypeInfo() %s\n", toChars()); + t = toBasetype(); + switch (t->ty) + { + case Tsarray: +#if 0 + // convert to corresponding dynamic array type + t = t->nextOf()->mutableOf()->arrayOf(); +#endif + break; + + case Tclass: + if (static_cast(t)->sym->isInterfaceDeclaration()) + break; + goto Linternal; + + case Tarray: + #if DMDV2 + // convert to corresponding dynamic array type + t = t->nextOf()->mutableOf()->arrayOf(); + #endif + if (t->nextOf()->ty != Tclass) + break; + goto Linternal; + + case Tfunction: + case Tdelegate: + case Tpointer: + Linternal: + tid = internalTI[t->ty]; + if (!tid) + { tid = new TypeInfoDeclaration(t, 1); + internalTI[t->ty] = tid; + } + e = new VarExp(0, tid); + e = e->addressOf(sc); + e->type = tid->type; // do this so we don't get redundant dereference + return e; + + default: + break; + } + //printf("\tcalling getTypeInfo() %s\n", t->toChars()); + return t->getTypeInfo(sc); +} + +/**************************************************** + * Get the exact TypeInfo. + */ + +Expression *Type::getTypeInfo(Scope *sc) +{ + //printf("Type::getTypeInfo() %p, %s\n", this, toChars()); + if (!Type::typeinfo) + { + error(0, "TypeInfo not found. object.d may be incorrectly installed or corrupt, compile with -v switch"); + fatal(); + } + + Expression *e = 0; + Type *t = merge2(); // do this since not all Type's are merge'd + + if (!t->vtinfo) + { +#if DMDV2 + if (t->isShared()) + t->vtinfo = new TypeInfoSharedDeclaration(t); + else if (t->isConst()) + t->vtinfo = new TypeInfoConstDeclaration(t); + else if (t->isImmutable()) + t->vtinfo = new TypeInfoInvariantDeclaration(t); + else if (t->isWild()) + t->vtinfo = new TypeInfoWildDeclaration(t); + else +#endif + t->vtinfo = t->getTypeInfoDeclaration(); + assert(t->vtinfo); + + /* If this has a custom implementation in std/typeinfo, then + * do not generate a COMDAT for it. + */ + if (!t->builtinTypeInfo()) + { // Generate COMDAT + if (sc) // if in semantic() pass + { // Find module that will go all the way to an object file + Module *m = sc->module->importedFrom; + m->members->push(t->vtinfo); + } + else // if in obj generation pass + { +#if IN_DMD + t->vtinfo->toObjFile(0); // TODO: multiobj +#else + t->vtinfo->codegen(sir); +#endif + } + } + } + e = new VarExp(0, t->vtinfo); + e = e->addressOf(sc); + e->type = t->vtinfo->type; // do this so we don't get redundant dereference + return e; +} + +enum RET TypeFunction::retStyle() +{ + return RETstack; +} + +TypeInfoDeclaration *Type::getTypeInfoDeclaration() +{ + //printf("Type::getTypeInfoDeclaration() %s\n", toChars()); + return new TypeInfoDeclaration(this, 0); +} + +TypeInfoDeclaration *TypeTypedef::getTypeInfoDeclaration() +{ + return new TypeInfoTypedefDeclaration(this); +} + +TypeInfoDeclaration *TypePointer::getTypeInfoDeclaration() +{ + return new TypeInfoPointerDeclaration(this); +} + +TypeInfoDeclaration *TypeDArray::getTypeInfoDeclaration() +{ + return new TypeInfoArrayDeclaration(this); +} + +TypeInfoDeclaration *TypeSArray::getTypeInfoDeclaration() +{ + return new TypeInfoStaticArrayDeclaration(this); +} + +TypeInfoDeclaration *TypeAArray::getTypeInfoDeclaration() +{ + return new TypeInfoAssociativeArrayDeclaration(this); +} + +TypeInfoDeclaration *TypeStruct::getTypeInfoDeclaration() +{ + return new TypeInfoStructDeclaration(this); +} + +TypeInfoDeclaration *TypeClass::getTypeInfoDeclaration() +{ + if (sym->isInterfaceDeclaration()) + return new TypeInfoInterfaceDeclaration(this); + else + return new TypeInfoClassDeclaration(this); +} + +#if DMDV2 +TypeInfoDeclaration *TypeVector::getTypeInfoDeclaration() +{ + return new TypeInfoVectorDeclaration(this); +} +#endif + +TypeInfoDeclaration *TypeEnum::getTypeInfoDeclaration() +{ + return new TypeInfoEnumDeclaration(this); +} + +TypeInfoDeclaration *TypeFunction::getTypeInfoDeclaration() +{ + return new TypeInfoFunctionDeclaration(this); +} + +TypeInfoDeclaration *TypeDelegate::getTypeInfoDeclaration() +{ + return new TypeInfoDelegateDeclaration(this); +} + +TypeInfoDeclaration *TypeTuple::getTypeInfoDeclaration() +{ + return new TypeInfoTupleDeclaration(this); +} + +/* ========================================================================= */ + +/* These decide if there's an instance for them already in std.typeinfo, + * because then the compiler doesn't need to build one. + */ + +int Type::builtinTypeInfo() +{ + return 0; +} + +int TypeBasic::builtinTypeInfo() +{ +#if DMDV2 + return mod ? 0 : 1; +#else + return 1; +#endif +} + +int TypeDArray::builtinTypeInfo() +{ +#if DMDV2 + return !mod && (next->isTypeBasic() != NULL && !next->mod || + // strings are so common, make them builtin + next->ty == Tchar && next->mod == MODimmutable); +#else + return next->isTypeBasic() != NULL; +#endif +} + +int TypeClass::builtinTypeInfo() +{ + /* This is statically put out with the ClassInfo, so + * claim it is built in so it isn't regenerated by each module. + */ +#if IN_DMD + return mod ? 0 : 1; +#elif IN_LLVM + // FIXME if I enable this, the way LDC does typeinfo will cause a bunch + // of linker errors to missing class typeinfo definitions. + return 0; +#endif +} + +/* ========================================================================= */ + +////////////////////////////////////////////////////////////////////////////// +// MAGIC PLACE +// (wut?) +////////////////////////////////////////////////////////////////////////////// + +void DtoResolveTypeInfo(TypeInfoDeclaration* tid); +void DtoDeclareTypeInfo(TypeInfoDeclaration* tid); + +void TypeInfoDeclaration::codegen(Ir*) +{ + DtoResolveTypeInfo(this); +} + +void DtoResolveTypeInfo(TypeInfoDeclaration* tid) +{ + if (tid->ir.resolved) return; + tid->ir.resolved = true; + + Logger::println("DtoResolveTypeInfo(%s)", tid->toChars()); + LOG_SCOPE; + + std::string mangle(tid->mangle()); + + IrGlobal* irg = new IrGlobal(tid); + irg->value = gIR->module->getGlobalVariable(mangle); + + if (!irg->value) { + if (tid->tinfo->builtinTypeInfo()) // this is a declaration of a builtin __initZ var + irg->type = Type::typeinfo->type->irtype->getType(); + else + irg->type = LLStructType::create(gIR->context(), tid->toPrettyChars()); + irg->value = new llvm::GlobalVariable(*gIR->module, irg->type, true, + TYPEINFO_LINKAGE_TYPE, NULL, mangle); + } else { + irg->type = irg->value->getType()->getContainedType(0); + } + + tid->ir.irGlobal = irg; + +#if USE_METADATA + // don't do this for void or llvm will crash + if (tid->tinfo->ty != Tvoid) { + // Add some metadata for use by optimization passes. + std::string metaname = std::string(TD_PREFIX) + mangle; + llvm::NamedMDNode* meta = gIR->module->getNamedMetadata(metaname); + // Don't generate metadata for non-concrete types + // (such as tuple types, slice types, typeof(expr), etc.) + if (!meta && tid->tinfo->toBasetype()->ty < Terror) { + // Construct the fields + MDNodeField* mdVals[TD_NumFields]; + if (TD_Confirm >= 0) + mdVals[TD_Confirm] = llvm::cast(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); + } + } +#endif // USE_METADATA + + DtoDeclareTypeInfo(tid); +} + +void DtoDeclareTypeInfo(TypeInfoDeclaration* tid) +{ + DtoResolveTypeInfo(tid); + + if (tid->ir.declared) return; + tid->ir.declared = true; + + Logger::println("DtoDeclareTypeInfo(%s)", tid->toChars()); + LOG_SCOPE; + + if (Logger::enabled()) + { + std::string mangled(tid->mangle()); + Logger::println("type = '%s'", tid->tinfo->toChars()); + Logger::println("typeinfo mangle: %s", mangled.c_str()); + } + + IrGlobal* irg = tid->ir.irGlobal; + assert(irg->value != NULL); + + // this is a declaration of a builtin __initZ var + if (tid->tinfo->builtinTypeInfo()) { + LLGlobalVariable* g = isaGlobalVar(irg->value); + g->setLinkage(llvm::GlobalValue::ExternalLinkage); + return; + } + + // define custom typedef + tid->llvmDefine(); +} + +/* ========================================================================= */ + +void TypeInfoDeclaration::llvmDefine() +{ + Logger::println("TypeInfoDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfo); + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoTypedefDeclaration::llvmDefine() +{ + Logger::println("TypeInfoTypedefDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfotypedef); + + assert(tinfo->ty == Ttypedef); + TypeTypedef *tc = static_cast(tinfo); + TypedefDeclaration *sd = tc->sym; + + // TypeInfo base + sd->basetype = sd->basetype->merge(); // dmd does it ... why? + b.push_typeinfo(sd->basetype); + + // char[] name + b.push_string(sd->toPrettyChars()); + + // void[] init + // emit null array if we should use the basetype, or if the basetype + // uses default initialization. + if (tinfo->isZeroInit(0) || !sd->init) + { + b.push_null_void_array(); + } + // otherwise emit a void[] with the default initializer + else + { + LLConstant* C = DtoConstInitializer(sd->loc, sd->basetype, sd->init); + b.push_void_array(C, sd->basetype, sd); + } + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoEnumDeclaration::llvmDefine() +{ + Logger::println("TypeInfoEnumDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfoenum); + + assert(tinfo->ty == Tenum); + TypeEnum *tc = static_cast(tinfo); + EnumDeclaration *sd = tc->sym; + + // TypeInfo base + b.push_typeinfo(sd->memtype); + + // char[] name + b.push_string(sd->toPrettyChars()); + + // void[] init + // emit void[] with the default initialier, the array is null if the default + // initializer is zero + if (!sd->defaultval || tinfo->isZeroInit(0)) + { + b.push_null_void_array(); + } + // otherwise emit a void[] with the default initializer + else + { + LLType* memty = DtoType(sd->memtype); +#if DMDV2 + LLConstant* C = LLConstantInt::get(memty, sd->defaultval->toInteger(), !sd->memtype->isunsigned()); +#else + LLConstant* C = LLConstantInt::get(memty, sd->defaultval, !sd->memtype->isunsigned()); +#endif + b.push_void_array(C, sd->memtype, sd); + } + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoPointerDeclaration::llvmDefine() +{ + Logger::println("TypeInfoPointerDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfopointer); + // TypeInfo base + b.push_typeinfo(tinfo->nextOf()); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoArrayDeclaration::llvmDefine() +{ + Logger::println("TypeInfoArrayDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfoarray); + // TypeInfo base + b.push_typeinfo(tinfo->nextOf()); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoStaticArrayDeclaration::llvmDefine() +{ + Logger::println("TypeInfoStaticArrayDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + assert(tinfo->ty == Tsarray); + TypeSArray *tc = static_cast(tinfo); + + RTTIBuilder b(Type::typeinfostaticarray); + + // value typeinfo + b.push_typeinfo(tc->nextOf()); + + // length + b.push(DtoConstSize_t(static_cast(tc->dim->toUInteger()))); + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoAssociativeArrayDeclaration::llvmDefine() +{ + Logger::println("TypeInfoAssociativeArrayDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + assert(tinfo->ty == Taarray); + TypeAArray *tc = static_cast(tinfo); + + RTTIBuilder b(Type::typeinfoassociativearray); + + // value typeinfo + b.push_typeinfo(tc->nextOf()); + + // key typeinfo + b.push_typeinfo(tc->index); + +#if DMDV2 + // impl typeinfo + b.push_typeinfo(tc->getImpl()->type); +#endif + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoFunctionDeclaration::llvmDefine() +{ + Logger::println("TypeInfoFunctionDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfofunction); + // TypeInfo base + b.push_typeinfo(tinfo->nextOf()); + // string deco + b.push_string(tinfo->deco); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoDelegateDeclaration::llvmDefine() +{ + Logger::println("TypeInfoDelegateDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + assert(tinfo->ty == Tdelegate); + Type* ret_type = tinfo->nextOf()->nextOf(); + + RTTIBuilder b(Type::typeinfodelegate); + // TypeInfo base + b.push_typeinfo(ret_type); + // string deco + b.push_string(tinfo->deco); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +static FuncDeclaration* find_method_overload(AggregateDeclaration* ad, Identifier* id, TypeFunction* tf, Module* mod) +{ + Dsymbol *s = search_function(ad, id); + FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; + if (fdx) + { + FuncDeclaration *fd = fdx->overloadExactMatch(tf, mod); + if (fd) + { + return fd; + } + } + return NULL; +} + +void TypeInfoStructDeclaration::llvmDefine() +{ + Logger::println("TypeInfoStructDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + // make sure struct is resolved + assert(tinfo->ty == Tstruct); + TypeStruct *tc = static_cast(tinfo); + StructDeclaration *sd = tc->sym; + + // can't emit typeinfo for forward declarations + if (sd->sizeok != 1) + { + sd->error("cannot emit TypeInfo for forward declaration"); + fatal(); + } + + sd->codegen(Type::sir); + IrStruct* irstruct = sd->ir.irStruct; + + RTTIBuilder b(Type::typeinfostruct); + + // char[] name + b.push_string(sd->toPrettyChars()); + + // 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()); + b.push_void_array(init_size, irstruct->getInitSymbol()); + + // toX functions ground work + static TypeFunction *tftohash; + static TypeFunction *tftostring; + + if (!tftohash) + { + Scope sc; + tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd); +#if DMDV2 + tftohash ->mod = MODconst; +#endif + tftohash = static_cast(tftohash->semantic(0, &sc)); + +#if DMDV2 + Type *retType = Type::tchar->invariantOf()->arrayOf(); +#else + Type *retType = Type::tchar->arrayOf(); +#endif + tftostring = new TypeFunction(NULL, retType, 0, LINKd); + tftostring = static_cast(tftostring->semantic(0, &sc)); + } + + // this one takes a parameter, so we need to build a new one each time + // to get the right type. can we avoid this? + TypeFunction *tfcmpptr; + { + Scope sc; + Parameters *arguments = new Parameters; +#if STRUCTTHISREF + // arg type is ref const T + Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL); +#else + // arg type is const T* + Parameter *arg = new Parameter(STCin, tc->pointerTo(), NULL, NULL); +#endif + arguments->push(arg); + tfcmpptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); +#if DMDV2 + tfcmpptr->mod = MODconst; +#endif + tfcmpptr = static_cast(tfcmpptr->semantic(0, &sc)); + } + + // well use this module for all overload lookups + Module *gm = getModule(); + + // toHash + FuncDeclaration* fd = find_method_overload(sd, Id::tohash, tftohash, gm); + b.push_funcptr(fd); + + // opEquals +#if DMDV2 + fd = sd->xeq; +#else + fd = find_method_overload(sd, Id::eq, tfcmpptr, gm); +#endif + b.push_funcptr(fd); + + // opCmp + fd = find_method_overload(sd, Id::cmp, tfcmpptr, gm); + b.push_funcptr(fd); + + // toString + fd = find_method_overload(sd, Id::tostring, tftostring, gm); + b.push_funcptr(fd); + + // uint m_flags; + unsigned hasptrs = tc->hasPointers() ? 1 : 0; + b.push_uint(hasptrs); + +#if DMDV2 + + ClassDeclaration* tscd = Type::typeinfostruct; + + assert((!global.params.is64bit && tscd->fields.dim == 11) || + (global.params.is64bit && tscd->fields.dim == 13)); + + // const(MemberInfo[]) function(in char[]) xgetMembers; + b.push_funcptr(sd->findGetMembers()); + + //void function(void*) xdtor; + b.push_funcptr(sd->dtor); + + //void function(void*) xpostblit; + FuncDeclaration *xpostblit = sd->postblit; + if (xpostblit && sd->postblit->storage_class & STCdisable) + xpostblit = 0; + b.push_funcptr(xpostblit); + + //uint m_align; + b.push_uint(tc->alignsize()); + + if (global.params.is64bit) + { + TypeTuple *tup = tc->toArgTypes(); + assert(tup->arguments->dim <= 2); + for (unsigned i = 0; i < 2; i++) + { + if (i < tup->arguments->dim) + { + Type *targ = static_cast(tup->arguments->data[i])->type; + targ = targ->merge(); + b.push_typeinfo(targ); + } + else + b.push_null(Type::typeinfo->type); + } + } + +#endif + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +#if DMDV2 +void TypeInfoClassDeclaration::codegen(Ir*i) +{ + + IrGlobal* irg = new IrGlobal(this); + ir.irGlobal = irg; + assert(tinfo->ty == Tclass); + TypeClass *tc = static_cast(tinfo); + tc->sym->codegen(Type::sir); // make sure class is resolved + irg->value = tc->sym->ir.irStruct->getClassInfoSymbol(); +} +#endif + +void TypeInfoClassDeclaration::llvmDefine() +{ +#if DMDV2 + assert(0); +#endif + Logger::println("TypeInfoClassDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + // make sure class is resolved + assert(tinfo->ty == Tclass); + TypeClass *tc = static_cast(tinfo); + tc->sym->codegen(Type::sir); + + RTTIBuilder b(Type::typeinfoclass); + + // TypeInfo base + b.push_classinfo(tc->sym); + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoInterfaceDeclaration::llvmDefine() +{ + Logger::println("TypeInfoInterfaceDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + // make sure interface is resolved + assert(tinfo->ty == Tclass); + TypeClass *tc = static_cast(tinfo); + tc->sym->codegen(Type::sir); + + RTTIBuilder b(Type::typeinfointerface); + + // TypeInfo base + b.push_classinfo(tc->sym); + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoTupleDeclaration::llvmDefine() +{ + Logger::println("TypeInfoTupleDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + // create elements array + assert(tinfo->ty == Ttuple); + TypeTuple *tu = static_cast(tinfo); + + size_t dim = tu->arguments->dim; + std::vector arrInits; + arrInits.reserve(dim); + + LLType* tiTy = DtoType(Type::typeinfo->type); + + for (size_t i = 0; i < dim; i++) + { + Parameter *arg = static_cast(tu->arguments->data[i]); + arrInits.push_back(DtoTypeInfoOf(arg->type, true)); + } + + // build array + LLArrayType* arrTy = LLArrayType::get(tiTy, dim); + LLConstant* arrC = LLConstantArray::get(arrTy, arrInits); + + RTTIBuilder b(Type::typeinfotypelist); + + // push TypeInfo[] + b.push_array(arrC, dim, Type::typeinfo->type, NULL); + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +#if DMDV2 + +void TypeInfoConstDeclaration::llvmDefine() +{ + Logger::println("TypeInfoConstDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfoconst); + // TypeInfo base + b.push_typeinfo(tinfo->mutableOf()->merge()); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoInvariantDeclaration::llvmDefine() +{ + Logger::println("TypeInfoInvariantDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfoinvariant); + // TypeInfo base + b.push_typeinfo(tinfo->mutableOf()->merge()); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoSharedDeclaration::llvmDefine() +{ + Logger::println("TypeInfoSharedDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfoshared); + // TypeInfo base + b.push_typeinfo(tinfo->unSharedOf()->merge()); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoWildDeclaration::llvmDefine() +{ + Logger::println("TypeInfoWildDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfowild); + // TypeInfo base + b.push_typeinfo(tinfo->mutableOf()->merge()); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +#if DMDV2 + +void TypeInfoVectorDeclaration::llvmDefine() +{ + Logger::println("TypeInfoVectorDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + assert(tinfo->ty == Tvector); + TypeVector *tv = static_cast(tinfo); + + RTTIBuilder b(Type::typeinfovector); + // TypeInfo base + b.push_typeinfo(tv->basetype); + // finish + b.finalize(ir.irGlobal); +} + +#endif + +#endif