From 787c147986913f74fc02546dde068fe421c8cf05 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 13 Oct 2013 04:31:41 +0200 Subject: [PATCH] Use Module::members -> Dsymbol::codegen to define symbols. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fundamentally changes the way symbol emission in LDC works: Previously, whenever a declaration was used in some way, the compiler would check whether it actually needs to be defined in the currently processed module, based only on the symbol itself. This lack of contextual information proved to be a major problem in correctly handling emission of templates (see e.g. #454). Now, the DtoResolve…() family of functions and similar only ever declare the symbols, and definition is handled by doing a single pass over Module::members for the root module. This is the same strategy that DMD uses as well, which should also reduce the maintainance burden down the road (which is important as during the last few releases, there was pretty much always a symbol emission related problem slowing us down). Our old approach might have been a bit better tuned w.r.t. avoiding emission of unneeded template instances, but 2.064 will bring improvements here (DMD: FuncDeclaration::toObjFile). Barring such issues, the change shoud also marginally improve compile times because of declarations no longer being emitted when they are not needed. In the future, we should also consider refactoring the code so that it no longer directly accesses Dsymbol::ir but uses wrapper functions that ensure that the appropriate DtoResolve…() function has been called. GitHub: Fixes #454. --- dmd2/declaration.h | 8 +- dmd2/func.c | 4 - gen/arrays.cpp | 8 -- gen/classes.cpp | 85 +++++------------- gen/declarations.cpp | 181 ++++++++++++++++++++++++++------------- gen/functions.cpp | 91 +++++++++----------- gen/llvmhelpers.cpp | 200 ++++++++++++++++++++----------------------- gen/llvmhelpers.h | 16 ++-- gen/module.cpp | 11 +-- gen/naked.cpp | 1 + gen/rttibuilder.cpp | 9 +- gen/structs.cpp | 26 ------ gen/toir.cpp | 50 +++++++---- gen/tollvm.cpp | 103 +++++++++------------- gen/typeinf.h | 1 - gen/typinf.cpp | 110 ++++++++++++------------ ir/ir.cpp | 15 ---- ir/ir.h | 3 - ir/iraggr.cpp | 4 +- ir/iraggr.h | 4 +- ir/irclass.cpp | 24 +++--- ir/irlandingpad.cpp | 2 +- 22 files changed, 439 insertions(+), 517 deletions(-) diff --git a/dmd2/declaration.h b/dmd2/declaration.h index 8b73bad9..a503a20d 100644 --- a/dmd2/declaration.h +++ b/dmd2/declaration.h @@ -478,7 +478,11 @@ struct TypeInfoClassDeclaration : TypeInfoDeclaration #endif #if IN_LLVM - void codegen(Ir*); + // TypeInfoClassDeclaration instances are different; they describe + // __ClassZ/__InterfaceZ symbols instead of a TypeInfo_….init one. DMD also + // generates them for SomeInterface.classinfo access, so we can't just + // distinguish between them using tinfo and thus need to override codegen(). + void codegen(Ir* p); void llvmDefine(); #endif }; @@ -814,7 +818,9 @@ struct FuncDeclaration : Declaration // functions FuncDeclarations siblingCallers; // Sibling nested functions which // called this one +#if IN_DMD FuncDeclarations deferred; // toObjFile() these functions after this one +#endif unsigned flags; #define FUNCFLAGpurityInprocess 1 // working on determining purity diff --git a/dmd2/func.c b/dmd2/func.c index 81121c65..db81f48e 100644 --- a/dmd2/func.c +++ b/dmd2/func.c @@ -4735,11 +4735,7 @@ void UnitTestDeclaration::semantic(Scope *sc) { sc = scope; scope = NULL; } -#if IN_LLVM - if (global.params.useUnitTests && sc->module->isRoot) -#else if (global.params.useUnitTests) -#endif { if (!type) type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); diff --git a/gen/arrays.cpp b/gen/arrays.cpp index db90c9a4..399509e9 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -867,14 +867,6 @@ static LLValue* DtoArrayEqCmp_impl(Loc& loc, const char* func, DValue* l, DValue if (useti) { Type* t = l->getType(); LLValue* tival = DtoTypeInfoOf(t); - // DtoTypeInfoOf only does declare, not enough in this case :/ - t->vtinfo->codegen(Type::sir); - -#if 0 - if (Logger::enabled()) - Logger::cout() << "typeinfo decl: " << *tival << '\n'; -#endif - args.push_back(DtoBitCast(tival, fn->getFunctionType()->getParamType(2))); } diff --git a/gen/classes.cpp b/gen/classes.cpp index c7af9b7d..8dc9a9e6 100644 --- a/gen/classes.cpp +++ b/gen/classes.cpp @@ -35,24 +35,21 @@ void DtoResolveClass(ClassDeclaration* cd) { - // make sure the base classes are processed first - ArrayIter base_iter(cd->baseclasses); - while (base_iter.more()) - { - BaseClass* bc = base_iter.get(); - if (bc) - { - bc->base->codegen(Type::sir); - } - base_iter.next(); - } - if (cd->ir.resolved) return; cd->ir.resolved = true; Logger::println("DtoResolveClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); LOG_SCOPE; + // make sure the base classes are processed first + ArrayIter base_iter(cd->baseclasses); + while (base_iter.more()) + { + BaseClass* bc = base_iter.get(); + DtoResolveClass(bc->base); + base_iter.next(); + } + // make sure type exists DtoType(cd->type); @@ -73,11 +70,6 @@ void DtoResolveClass(ClassDeclaration* cd) } } - bool needs_def = mustDefineSymbol(cd); - - // emit the ClassZ symbol - LLGlobalVariable* ClassZ = irAggr->getClassInfoSymbol(); - // emit the interfaceInfosZ symbol if necessary if (cd->vtblInterfaces && cd->vtblInterfaces->dim > 0) irAggr->getInterfaceArraySymbol(); // initializer is applied when it's built @@ -87,43 +79,6 @@ void DtoResolveClass(ClassDeclaration* cd) { irAggr->initializeInterface(); } - else - { - // emit the initZ symbol - LLGlobalVariable* initZ = irAggr->getInitSymbol(); - // emit the vtblZ symbol - LLGlobalVariable* vtblZ = irAggr->getVtblSymbol(); - - // perform definition - if (needs_def) - { - // set symbol initializers - initZ->setInitializer(irAggr->getDefaultInit()); - vtblZ->setInitializer(irAggr->getVtblInit()); - } - } - - // emit members - if (cd->members) - { - ArrayIter it(*cd->members); - while (!it.done()) - { - Dsymbol* member = it.get(); - if (member) - member->codegen(Type::sir); - it.next(); - } - } - - if (needs_def) - { - // emit typeinfo - DtoTypeInfoOf(cd->type); - - // define classinfo - ClassZ->setInitializer(irAggr->getClassInfoInit()); - } } ////////////////////////////////////////////////////////////////////////////////////////// @@ -131,7 +86,7 @@ void DtoResolveClass(ClassDeclaration* cd) DValue* DtoNewClass(Loc loc, TypeClass* tc, NewExp* newexp) { // resolve type - tc->sym->codegen(Type::sir); + DtoResolveClass(tc->sym); // allocate LLValue* mem; @@ -143,7 +98,7 @@ DValue* DtoNewClass(Loc loc, TypeClass* tc, NewExp* newexp) // custom allocator else if (newexp->allocator) { - newexp->allocator->codegen(Type::sir); + DtoResolveDsymbol(newexp->allocator); DFuncValue dfn(newexp->allocator, newexp->allocator->ir.irFunc->func); DValue* res = DtoCallFunction(newexp->loc, NULL, &dfn, newexp->newargs); mem = DtoBitCast(res->getRVal(), DtoType(tc), ".newclass_custom"); @@ -184,7 +139,7 @@ DValue* DtoNewClass(Loc loc, TypeClass* tc, NewExp* newexp) { Logger::println("Calling constructor"); assert(newexp->arguments != NULL); - newexp->member->codegen(Type::sir); + DtoResolveDsymbol(newexp->member); DFuncValue dfn(newexp->member, newexp->member->ir.irFunc->func, mem); return DtoCallFunction(newexp->loc, tc, &dfn, newexp->arguments); } @@ -197,7 +152,7 @@ DValue* DtoNewClass(Loc loc, TypeClass* tc, NewExp* newexp) void DtoInitClass(TypeClass* tc, LLValue* dst) { - tc->sym->codegen(Type::sir); + DtoResolveClass(tc->sym); uint64_t n = tc->sym->structsize - Target::ptrsize * 2; @@ -365,8 +320,8 @@ DValue* DtoDynamicCastObject(DValue* val, Type* _to) // call: // Object _d_dynamic_cast(Object o, ClassInfo c) - ClassDeclaration::object->codegen(Type::sir); - ClassDeclaration::classinfo->codegen(Type::sir); + DtoResolveClass(ClassDeclaration::object); + DtoResolveClass(ClassDeclaration::classinfo); llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_dynamic_cast"); LLFunctionType* funcTy = func->getFunctionType(); @@ -378,7 +333,7 @@ DValue* DtoDynamicCastObject(DValue* val, Type* _to) // ClassInfo c TypeClass* to = static_cast(_to->toBasetype()); - to->sym->codegen(Type::sir); + DtoResolveClass(to->sym); LLValue* cinfo = to->sym->ir.irAggr->getClassInfoSymbol(); // unfortunately this is needed as the implementation of object differs somehow from the declaration @@ -428,8 +383,8 @@ DValue* DtoDynamicCastInterface(DValue* val, Type* _to) // call: // Object _d_interface_cast(void* p, ClassInfo c) - ClassDeclaration::object->codegen(Type::sir); - ClassDeclaration::classinfo->codegen(Type::sir); + DtoResolveClass(ClassDeclaration::object); + DtoResolveClass(ClassDeclaration::classinfo); llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_interface_cast"); LLFunctionType* funcTy = func->getFunctionType(); @@ -440,7 +395,7 @@ DValue* DtoDynamicCastInterface(DValue* val, Type* _to) // ClassInfo c TypeClass* to = static_cast(_to->toBasetype()); - to->sym->codegen(Type::sir); + DtoResolveClass(to->sym); LLValue* cinfo = to->sym->ir.irAggr->getClassInfoSymbol(); // unfortunately this is needed as the implementation of object differs somehow from the declaration // this could happen in user code as well :/ @@ -623,7 +578,7 @@ static LLConstant* build_class_dtor(ClassDeclaration* cd) if (!dtor) return getNullPtr(getVoidPtrType()); - dtor->codegen(Type::sir); + DtoResolveDsymbol(dtor); return llvm::ConstantExpr::getBitCast(dtor->ir.irFunc->func, getPtrToType(LLType::getInt8Ty(gIR->context()))); } diff --git a/gen/declarations.cpp b/gen/declarations.cpp index aea69157..e9bff5c8 100644 --- a/gen/declarations.cpp +++ b/gen/declarations.cpp @@ -14,11 +14,14 @@ #include "init.h" #include "rmem.h" #include "template.h" +#include "gen/classes.h" +#include "gen/functions.h" #include "gen/irstate.h" #include "gen/llvm.h" #include "gen/llvmhelpers.h" #include "gen/logger.h" #include "gen/tollvm.h" +#include "gen/utils.h" #include "ir/ir.h" #include "ir/irtype.h" #include "ir/irvar.h" @@ -27,53 +30,129 @@ void Dsymbol::codegen(Ir*) { - Logger::println("Ignoring Dsymbol::codegen for %s", toPrettyChars()); + IF_LOG Logger::println("Ignoring Dsymbol::codegen for %s", toPrettyChars()); } /* ================================================================== */ -void InterfaceDeclaration::codegen(Ir*) +void InterfaceDeclaration::codegen(Ir* p) { + IF_LOG Logger::println("InterfaceDeclaration::codegen: '%s'", toPrettyChars()); + LOG_SCOPE + + if (ir.defined) return; + ir.defined = true; + if (type->ty == Terror) { error("had semantic errors when compiling"); return; } if (members && symtab) + { DtoResolveDsymbol(this); + + // Emit any members (e.g. final functions). + for (ArrayIter it(members); !it.done(); it.next()) + { + it->codegen(p); + } + + // Emit TypeInfo. + DtoTypeInfoOf(type); + + // Define __InterfaceZ. + llvm::GlobalVariable *interfaceZ = ir.irAggr->getClassInfoSymbol(); + interfaceZ->setInitializer(ir.irAggr->getClassInfoInit()); + interfaceZ->setLinkage(DtoExternalLinkage(this)); + } } /* ================================================================== */ -void StructDeclaration::codegen(Ir*) +void StructDeclaration::codegen(Ir* p) { + IF_LOG Logger::println("StructDeclaration::codegen: '%s'", toPrettyChars()); + LOG_SCOPE + + if (ir.defined) return; + ir.defined = true; + if (type->ty == Terror) { error("had semantic errors when compiling"); return; } if (members && symtab) - DtoResolveDsymbol(this); + { + DtoResolveStruct(this); + + for (ArrayIter it(members); !it.done(); it.next()) + { + it->codegen(p); + } + + // Define the __initZ symbol. + llvm::GlobalVariable *initZ = ir.irAggr->getInitSymbol(); + initZ->setInitializer(ir.irAggr->getDefaultInit()); + initZ->setLinkage(DtoExternalLinkage(this)); + + // emit typeinfo + DtoTypeInfoOf(type); + } } /* ================================================================== */ -void ClassDeclaration::codegen(Ir*) +void ClassDeclaration::codegen(Ir* p) { + IF_LOG Logger::println("ClassDeclaration::codegen: '%s'", toPrettyChars()); + LOG_SCOPE + + if (ir.defined) return; + ir.defined = true; + if (type->ty == Terror) { error("had semantic errors when compiling"); return; } if (members && symtab) - DtoResolveDsymbol(this); + { + DtoResolveClass(this); + + for (ArrayIter it(members); !it.done(); it.next()) + { + it->codegen(p); + } + + llvm::GlobalValue::LinkageTypes const linkage = DtoExternalLinkage(this); + + llvm::GlobalVariable *initZ = ir.irAggr->getInitSymbol(); + initZ->setInitializer(ir.irAggr->getDefaultInit()); + initZ->setLinkage(linkage); + + llvm::GlobalVariable *vtbl = ir.irAggr->getVtblSymbol(); + vtbl->setInitializer(ir.irAggr->getVtblInit()); + vtbl->setLinkage(linkage); + + llvm::GlobalVariable *classZ = ir.irAggr->getClassInfoSymbol(); + classZ->setInitializer(ir.irAggr->getClassInfoInit()); + classZ->setLinkage(linkage); + + // No need to do TypeInfo here, it is __classZ for classes in D2. + } } /* ================================================================== */ void TupleDeclaration::codegen(Ir* p) { - Logger::println("TupleDeclaration::codegen(): %s", toChars()); + IF_LOG Logger::println("TupleDeclaration::codegen(): '%s'", toPrettyChars()); + LOG_SCOPE + + if (ir.defined) return; + ir.defined = true; assert(isexp); assert(objects); @@ -92,14 +171,19 @@ void TupleDeclaration::codegen(Ir* p) void VarDeclaration::codegen(Ir* p) { - Logger::print("VarDeclaration::codegen(): %s | %s\n", toChars(), type->toChars()); + IF_LOG Logger::println("VarDeclaration::codegen(): '%s'", toPrettyChars()); LOG_SCOPE; + if (ir.defined) return; + ir.defined = true; + if (type->ty == Terror) { error("had semantic errors when compiling"); return; } + DtoResolveVariable(this); + // just forward aliases if (aliassym) { @@ -108,10 +192,6 @@ void VarDeclaration::codegen(Ir* p) return; } - // output the parent aggregate first - if (AggregateDeclaration* ad = isMember()) - ad->codegen(p); - // global variable if (isDataseg() || (storage_class & (STCconst | STCimmutable) && init)) { @@ -122,37 +202,14 @@ void VarDeclaration::codegen(Ir* p) "manifest constant being codegen'd!"); #endif - // don't duplicate work - if (this->ir.resolved) return; - this->ir.resolved = true; - this->ir.declared = true; + llvm::GlobalVariable *gvar = llvm::cast( + this->ir.irGlobal->value); + assert(gvar && "DtoResolveVariable should have created value"); - this->ir.irGlobal = new IrGlobal(this); - - Logger::println("parent: %s (%s)", parent->toChars(), parent->kind()); - - const bool isLLConst = isConst() && init; const llvm::GlobalValue::LinkageTypes llLinkage = DtoLinkage(this); - assert(!ir.initialized); - ir.initialized = gIR->dmodule; - std::string llName(mangle()); - - // Since the type of a global must exactly match the type of its - // initializer, we cannot know the type until after we have emitted the - // latter (e.g. in case of unions, …). However, it is legal for the - // initializer to refer to the address of the variable. Thus, we first - // create a global with the generic type (note the assignment to - // this->ir.irGlobal->value!), and in case we also do an initializer - // with a different type later, swap it out and replace any existing - // uses with bitcasts to the previous type. - llvm::GlobalVariable* gvar = getOrCreateGlobal(loc, *gIR->module, - i1ToI8(DtoType(type)), isLLConst, llLinkage, 0, llName, - isThreadlocal()); - this->ir.irGlobal->value = gvar; - // Check if we are defining or just declaring the global in this module. - if (!(storage_class & STCextern) && mustDefineSymbol(this)) + if (!(storage_class & STCextern)) { // Build the initializer. Might use this->ir.irGlobal->value! LLConstant *initVal = DtoConstInitializer(loc, type, init); @@ -161,10 +218,12 @@ void VarDeclaration::codegen(Ir* p) if (initVal->getType() != gvar->getType()->getElementType()) { llvm::GlobalVariable* newGvar = getOrCreateGlobal(loc, - *gIR->module, initVal->getType(), isLLConst, llLinkage, 0, + *gIR->module, initVal->getType(), gvar->isConstant(), + llLinkage, 0, "", // We take on the name of the old global below. - isThreadlocal()); + gvar->isThreadLocal()); + newGvar->setAlignment(gvar->getAlignment()); newGvar->takeName(gvar); llvm::Constant* newValue = @@ -180,17 +239,12 @@ void VarDeclaration::codegen(Ir* p) assert(!ir.irGlobal->constInit); ir.irGlobal->constInit = initVal; gvar->setInitializer(initVal); + gvar->setLinkage(llLinkage); // Also set up the edbug info. gIR->DBuilder.EmitGlobalVariable(gvar, this); } - // Set the alignment (it is important not to use type->alignsize because - // VarDeclarations can have an align() attribute independent of the type - // as well). - if (alignment != STRUCTALIGN_DEFAULT) - gvar->setAlignment(alignment); - // If this global is used from a naked function, we need to create an // artificial "use" for it, or it could be removed by the optimizer if // the only reference to it is in inline asm. @@ -206,9 +260,12 @@ void VarDeclaration::codegen(Ir* p) void TypedefDeclaration::codegen(Ir*) { - Logger::print("TypedefDeclaration::codegen: %s\n", toChars()); + IF_LOG Logger::println("TypedefDeclaration::codegen: '%s'", toPrettyChars()); LOG_SCOPE; + if (ir.defined) return; + ir.defined = true; + if (type->ty == Terror) { error("had semantic errors when compiling"); return; @@ -222,7 +279,7 @@ void TypedefDeclaration::codegen(Ir*) void EnumDeclaration::codegen(Ir*) { - Logger::println("Ignoring EnumDeclaration::codegen for %s", toChars()); + IF_LOG Logger::println("Ignoring EnumDeclaration::codegen: '%s'", toPrettyChars()); if (type->ty == Terror) { error("had semantic errors when compiling"); @@ -237,7 +294,7 @@ void FuncDeclaration::codegen(Ir* p) // don't touch function aliases, they don't contribute any new symbols if (!isFuncAliasDeclaration()) { - DtoResolveDsymbol(this); + DtoDefineFunction(this); } } @@ -245,18 +302,17 @@ void FuncDeclaration::codegen(Ir* p) void TemplateInstance::codegen(Ir* p) { -#if LOG - printf("TemplateInstance::codegen('%s', this = %p)\n", toChars(), this); -#endif - if (ignore) - return; + IF_LOG Logger::println("TemplateInstance::codegen: '%s'", toPrettyChars()); + LOG_SCOPE + + if (ir.defined) return; + ir.defined = true; if (!errors && members) { for (unsigned i = 0; i < members->dim; i++) { - Dsymbol *s = static_cast(members->data[i]); - s->codegen(p); + (*members)[i]->codegen(p); } } } @@ -265,14 +321,17 @@ void TemplateInstance::codegen(Ir* p) void TemplateMixin::codegen(Ir* p) { + IF_LOG Logger::println("TemplateInstance::codegen: '%s'", toPrettyChars()); + LOG_SCOPE + + if (ir.defined) return; + ir.defined = true; + if (!errors && members) { for (unsigned i = 0; i < members->dim; i++) { - Dsymbol *s = static_cast(members->data[i]); - if (s->isVarDeclaration()) - continue; - s->codegen(p); + (*members)[i]->codegen(p); } } } diff --git a/gen/functions.cpp b/gen/functions.cpp index 7e0122a1..74bae086 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -702,6 +702,12 @@ void DtoDeclareFunction(FuncDeclaration* fdecl) Logger::println("DtoDeclareFunction(%s): %s", fdecl->toPrettyChars(), fdecl->loc.toChars()); LOG_SCOPE; + if (fdecl->isUnitTestDeclaration() && !global.params.useUnitTests) + { + Logger::println("unit tests not enabled"); + return; + } + //printf("declare function: %s\n", fdecl->toPrettyChars()); // intrinsic sanity check @@ -715,10 +721,6 @@ void DtoDeclareFunction(FuncDeclaration* fdecl) TypeFunction* f = static_cast(t); IrFuncTy &irFty = fdecl->irFty; - bool declareOnly = !mustDefineSymbol(fdecl); - - if (fdecl->llvmInternal == LLVMva_start) - declareOnly = true; if (!fdecl->ir.irFunc) { fdecl->ir.irFunc = new IrFunction(fdecl); @@ -753,9 +755,16 @@ void DtoDeclareFunction(FuncDeclaration* fdecl) LLFunction* func = vafunc ? vafunc : gIR->module->getFunction(mangledName); if (!func) { if(fdecl->llvmInternal == LLVMinline_ir) + { func = DtoInlineIRFunction(fdecl); + } else - func = LLFunction::Create(functype, DtoLinkage(fdecl), mangledName, gIR->module); + { + // All function declarations are "external" - any other linkage type + // is set when actually defining the function. + func = LLFunction::Create(functype, + llvm::GlobalValue::ExternalLinkage, mangledName, gIR->module); + } } else if (func->getFunctionType() != functype) { error(fdecl->loc, "Function type does not match previously declared function with the same mangled name: %s", fdecl->mangle()); } @@ -792,35 +801,6 @@ void DtoDeclareFunction(FuncDeclaration* fdecl) gIR->mainFunc = func; } - // shared static ctor - if (fdecl->isSharedStaticCtorDeclaration()) { - if (mustDefineSymbol(fdecl)) { - gIR->sharedCtors.push_back(fdecl); - } - } - // shared static dtor - else if (StaticDtorDeclaration *dtorDecl = fdecl->isSharedStaticDtorDeclaration()) { - if (mustDefineSymbol(fdecl)) { - gIR->sharedDtors.push_front(fdecl); - if (dtorDecl->vgate) - gIR->sharedGates.push_front(dtorDecl->vgate); - } - } else - // static ctor - if (fdecl->isStaticCtorDeclaration()) { - if (mustDefineSymbol(fdecl)) { - gIR->ctors.push_back(fdecl); - } - } - // static dtor - else if (StaticDtorDeclaration *dtorDecl = fdecl->isStaticDtorDeclaration()) { - if (mustDefineSymbol(fdecl)) { - gIR->dtors.push_front(fdecl); - if (dtorDecl->vgate) - gIR->gates.push_front(dtorDecl->vgate); - } - } - if (fdecl->neverInline) { fdecl->ir.irFunc->setNeverInline(); @@ -909,14 +889,6 @@ void DtoDeclareFunction(FuncDeclaration* fdecl) } } } - - if (fdecl->isUnitTestDeclaration() && !declareOnly) - gIR->unitTests.push_back(fdecl); - - if (!declareOnly) - Type::sir->addFunctionBody(fdecl->ir.irFunc); - else - assert(func->getLinkage() != llvm::GlobalValue::InternalLinkage); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -927,15 +899,37 @@ void DtoDefineFunction(FuncDeclaration* fd) { DtoDeclareFunction(fd); - if (fd->ir.defined) return; - fd->ir.defined = true; - assert(fd->ir.declared); if (Logger::enabled()) - Logger::println("DtoDefineFunc(%s): %s", fd->toPrettyChars(), fd->loc.toChars()); + Logger::println("DtoDefineFunction(%s): %s", fd->toPrettyChars(), fd->loc.toChars()); LOG_SCOPE; + // Be sure to call DtoDeclareFunction first, as LDC_inline_asm functions are + // "defined" there. TODO: Clean this up. + if (fd->ir.defined) return; + fd->ir.defined = true; + + if (fd->isUnitTestDeclaration()) { + if (global.params.useUnitTests) + gIR->unitTests.push_back(fd); + else + return; + } else if (fd->isSharedStaticCtorDeclaration()) { + gIR->sharedCtors.push_back(fd); + } else if (StaticDtorDeclaration *dtorDecl = fd->isSharedStaticDtorDeclaration()) { + gIR->sharedDtors.push_front(fd); + if (dtorDecl->vgate) + gIR->sharedGates.push_front(dtorDecl->vgate); + } else if (fd->isStaticCtorDeclaration()) { + gIR->ctors.push_back(fd); + } else if (StaticDtorDeclaration *dtorDecl = fd->isStaticDtorDeclaration()) { + gIR->dtors.push_front(fd); + if (dtorDecl->vgate) + gIR->gates.push_front(dtorDecl->vgate); + } + + // if this function is naked, we take over right away! no standard processing! if (fd->naked) { @@ -954,9 +948,6 @@ void DtoDefineFunction(FuncDeclaration* fd) llvm::Function* func = fd->ir.irFunc->func; - // sanity check - assert(mustDefineSymbol(fd)); - // set module owner fd->ir.DModule = gIR->dmodule; @@ -972,6 +963,8 @@ void DtoDefineFunction(FuncDeclaration* fd) if (fd->isMain()) gIR->emitMain = true; + func->setLinkage(DtoLinkage(fd)); + // On x86_64, always set 'uwtable' for System V ABI compatibility. // TODO: Find a better place for this. if (global.params.targetTriple.getArch() == llvm::Triple::x86_64) diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index aec891d7..14cf1f8d 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1005,8 +1005,86 @@ void DtoResolveDsymbol(Dsymbol* dsym) else if (TypeInfoDeclaration* fd = dsym->isTypeInfoDeclaration()) { DtoResolveTypeInfo(fd); } - else { - llvm_unreachable("Unsupported DSymbol for DtoResolveDsymbol."); + else if (VarDeclaration* vd = dsym->isVarDeclaration()) { + DtoResolveVariable(vd); + } +} + +void DtoResolveVariable(VarDeclaration* vd) +{ + if (vd->isTypeInfoDeclaration()) + return DtoResolveTypeInfo(static_cast(vd)); + + IF_LOG Logger::println("DtoResolveVariable(%s)", vd->toPrettyChars()); + LOG_SCOPE; + + // just forward aliases + // TODO: Is this required here or is the check in VarDeclaration::codegen + // sufficient? + if (vd->aliassym) + { + Logger::println("alias sym"); + DtoResolveDsymbol(vd->aliassym); + return; + } + + if (AggregateDeclaration* ad = vd->isMember()) + DtoResolveDsymbol(ad); + + // global variable + if (vd->isDataseg() || (vd->storage_class & (STCconst | STCimmutable) && vd->init)) + { + Logger::println("data segment"); + + #if 0 // TODO: + assert(!(storage_class & STCmanifest) && + "manifest constant being codegen'd!"); + #endif + + // don't duplicate work + if (vd->ir.resolved) return; + vd->ir.resolved = true; + vd->ir.declared = true; + + vd->ir.irGlobal = new IrGlobal(vd); + + IF_LOG { + if (vd->parent) + Logger::println("parent: %s (%s)", vd->parent->toChars(), vd->parent->kind()); + else + Logger::println("parent: null"); + } + + const bool isLLConst = vd->isConst() && vd->init; + + assert(!vd->ir.initialized); + vd->ir.initialized = gIR->dmodule; + std::string llName(vd->mangle()); + + // Since the type of a global must exactly match the type of its + // initializer, we cannot know the type until after we have emitted the + // latter (e.g. in case of unions, …). However, it is legal for the + // initializer to refer to the address of the variable. Thus, we first + // create a global with the generic type (note the assignment to + // vd->ir.irGlobal->value!), and in case we also do an initializer + // with a different type later, swap it out and replace any existing + // uses with bitcasts to the previous type. + // + // We always start out with external linkage; any other type is set + // when actually defining it in VarDeclaration::codegen. + llvm::GlobalVariable* gvar = getOrCreateGlobal(vd->loc, *gIR->module, + i1ToI8(DtoType(vd->type)), isLLConst, llvm::GlobalValue::ExternalLinkage, + 0, llName, vd->isThreadlocal()); + vd->ir.irGlobal->value = gvar; + + // Set the alignment (it is important not to use type->alignsize because + // VarDeclarations can have an align() attribute independent of the type + // as well). + if (vd->alignment != STRUCTALIGN_DEFAULT) + gvar->setAlignment(vd->alignment); + + if (Logger::enabled()) + Logger::cout() << *gvar << '\n'; } } @@ -1293,7 +1371,7 @@ LLConstant* DtoConstInitializer(Loc loc, Type* type, Initializer* init) else if (StructInitializer* si = init->isStructInitializer()) { Logger::println("const struct initializer"); - si->ad->codegen(Type::sir); + DtoResolveDsymbol(si->ad); return si->ad->ir.irAggr->createStructInitializer(si); } else if (ArrayInitializer* ai = init->isArrayInitializer()) @@ -1502,98 +1580,6 @@ void DtoOverloadedIntrinsicName(TemplateInstance* ti, TemplateDeclaration* td, s ////////////////////////////////////////////////////////////////////////////////////////// -bool mustDefineSymbol(Dsymbol* s) -{ - if (FuncDeclaration* fd = s->isFuncDeclaration()) - { - // we can't (and probably shouldn't?) define functions - // that weren't semantic3'ed - if (fd->semanticRun < PASSsemantic3) - return false; - - // If a function has no body, we cannot possibly emit it (and so it - // cannot be available_externally either). - if (!fd->fbody) - return false; - - if (fd->isArrayOp == 1) - return true; - - if (global.inExtraInliningSemantic && fd->availableExternally) { - // Emit extra functions if we're inlining. - // These will get available_externally linkage, - // so they shouldn't end up in object code. - - assert(fd->type->ty == Tfunction); - // * If we define extra static constructors, static destructors - // and unittests they'll get registered to run, and we won't - // be calling them directly anyway. - // * If it's a large function, don't emit it unnecessarily. - // Use DMD's canInline() to determine whether it's large. - // inlineCost() members have been changed to pay less attention - // to DMDs limitations, but still have some issues. The most glaring - // offenders are any kind of control flow statements other than - // 'if' and 'return'. - if ( !fd->isStaticCtorDeclaration() - && !fd->isStaticDtorDeclaration() - && !fd->isUnitTestDeclaration() - && fd->canInline(true, false, false)) - { - return true; - } - - // This was only semantic'ed for inlining checks. - // We won't be inlining this, so we only need to emit a declaration. - return false; - } - } - - if (VarDeclaration* vd = s->isVarDeclaration()) - { - // Never define 'extern' variables. - if (vd->storage_class & STCextern) - return false; - } - - // Inlining checks may create some variable and class declarations - // we don't need to emit. - if (global.inExtraInliningSemantic) - { - if (VarDeclaration* vd = s->isVarDeclaration()) - if (vd->availableExternally) - return false; - - if (ClassDeclaration* cd = s->isClassDeclaration()) - if (cd->availableExternally) - return false; - } - - TemplateInstance* tinst = DtoIsTemplateInstance(s, true); - if (tinst) - { - if (!global.params.singleObj) - return true; - - if (!tinst->emittedInModule) - { - gIR->seenTemplateInstances.insert(tinst); - tinst->emittedInModule = gIR->dmodule; - } - return tinst->emittedInModule == gIR->dmodule; - } - - return s->getModule() == gIR->dmodule; -} - -////////////////////////////////////////////////////////////////////////////////////////// - -bool needsTemplateLinkage(Dsymbol* s) -{ - return DtoIsTemplateInstance(s) && mustDefineSymbol(s); -} - -////////////////////////////////////////////////////////////////////////////////////////// - bool hasUnalignedFields(Type* t) { t = t->toBasetype(); @@ -1734,7 +1720,7 @@ void callPostblit(Loc &loc, Expression *exp, LLValue *val) FuncDeclaration *fd = sd->postblit; if (fd->storage_class & STCdisable) fd->toParent()->error(loc, "is not copyable because it is annotated with @disable"); - fd->codegen(Type::sir); + DtoResolveFunction(fd); Expressions args; DFuncValue dfn(fd, fd->ir.irFunc->func, val); DtoCallFunction(loc, Type::basic[Tvoid], &dfn, &args); @@ -1867,14 +1853,14 @@ DValue* DtoSymbolAddress(const Loc& loc, Type* type, Declaration* decl) else if (ClassInfoDeclaration* cid = vd->isClassInfoDeclaration()) { Logger::println("ClassInfoDeclaration: %s", cid->cd->toChars()); - cid->cd->codegen(Type::sir);; + DtoResolveClass(cid->cd); return new DVarValue(type, vd, cid->cd->ir.irAggr->getClassInfoSymbol()); } // typeinfo else if (TypeInfoDeclaration* tid = vd->isTypeInfoDeclaration()) { Logger::println("TypeInfoDeclaration"); - tid->codegen(Type::sir); + DtoResolveTypeInfo(tid); assert(tid->ir.getIrValue()); LLType* vartype = DtoType(type); LLValue* m = tid->ir.getIrValue(); @@ -1923,7 +1909,7 @@ DValue* DtoSymbolAddress(const Loc& loc, Type* type, Declaration* decl) // take care of forward references of global variables const bool isGlobal = vd->isDataseg() || (vd->storage_class & STCextern); if (isGlobal) - vd->codegen(Type::sir); + DtoResolveDsymbol(vd); assert(vd->ir.isSet() && "Variable not resolved."); @@ -1952,19 +1938,15 @@ DValue* DtoSymbolAddress(const Loc& loc, Type* type, Declaration* decl) if (FuncDeclaration* fdecl = decl->isFuncDeclaration()) { Logger::println("FuncDeclaration"); - LLValue* func = 0; fdecl = fdecl->toAliasFunc(); if (fdecl->llvmInternal == LLVMinline_asm) { + // TODO: Is this needed? If so, what about other intrinsics? error("special ldc inline asm is not a normal function"); fatal(); } - else if (fdecl->llvmInternal != LLVMva_arg) - { - fdecl->codegen(Type::sir); - func = fdecl->ir.irFunc->func; - } - return new DFuncValue(fdecl, func); + DtoResolveFunction(fdecl); + return new DFuncValue(fdecl, fdecl->ir.irFunc->func); } if (SymbolDeclaration* sdecl = decl->isSymbolDeclaration()) @@ -1975,7 +1957,7 @@ DValue* DtoSymbolAddress(const Loc& loc, Type* type, Declaration* decl) assert(sdecltype->ty == Tstruct); TypeStruct* ts = static_cast(sdecltype); assert(ts->sym); - ts->sym->codegen(Type::sir); + DtoResolveStruct(ts->sym); LLValue* initsym = ts->sym->ir.irAggr->getInitSymbol(); initsym = DtoBitCast(initsym, DtoType(ts->pointerTo())); @@ -2011,7 +1993,7 @@ llvm::Constant* DtoConstSymbolAddress(const Loc& loc, Declaration* decl) return NULL; } - vd->codegen(Type::sir); + DtoResolveVariable(vd); LLConstant* llc = llvm::dyn_cast(vd->ir.getIrValue()); assert(llc); return llc; @@ -2019,7 +2001,7 @@ llvm::Constant* DtoConstSymbolAddress(const Loc& loc, Declaration* decl) // static function else if (FuncDeclaration* fd = decl->isFuncDeclaration()) { - fd->codegen(Type::sir); + DtoResolveFunction(fd); IrFunction* irfunc = fd->ir.irFunc; return irfunc->func; } diff --git a/gen/llvmhelpers.h b/gen/llvmhelpers.h index 14a15678..14d3adf6 100644 --- a/gen/llvmhelpers.h +++ b/gen/llvmhelpers.h @@ -102,9 +102,15 @@ DValue* DtoPaintType(Loc& loc, DValue* val, Type* to); // is template instance check, returns module where instantiated TemplateInstance* DtoIsTemplateInstance(Dsymbol* s, bool checkLiteralOwner = false); -/// Generate code for the symbol. -/// Dispatches as appropriate. +/// Makes sure the declarations corresponding to the given D symbol have been +/// emitted to the currently processed LLVM module. +/// +/// This means that dsym->ir can be expected to set to reasonable values. +/// +/// This function does *not* emit any (function, variable) *definitions*; this +/// is done by Dsymbol::codegen. void DtoResolveDsymbol(Dsymbol* dsym); +void DtoResolveVariable(VarDeclaration* var); // declaration inside a declarationexp void DtoVarDeclaration(VarDeclaration* var); @@ -135,12 +141,6 @@ void findDefaultTarget(); /// Fixup an overloaded intrinsic name string. void DtoOverloadedIntrinsicName(TemplateInstance* ti, TemplateDeclaration* td, std::string& name); -/// Returns true if the symbol should be defined in the current module, not just declared. -bool mustDefineSymbol(Dsymbol* s); - -/// Returns true if the symbol needs template linkage, or just external. -bool needsTemplateLinkage(Dsymbol* s); - /// Returns true if there is any unaligned type inside the aggregate. bool hasUnalignedFields(Type* t); diff --git a/gen/module.cpp b/gen/module.cpp index ebd447d0..e894912b 100644 --- a/gen/module.cpp +++ b/gen/module.cpp @@ -398,9 +398,6 @@ llvm::Module* Module::genLLVMModule(llvm::LLVMContext& context, Ir* sir) dsym->codegen(sir); } - // emit function bodies - sir->emitFunctionBodies(); - // for singleobj-compilation, fully emit all seen template instances if (global.params.singleObj) { @@ -410,9 +407,6 @@ llvm::Module* Module::genLLVMModule(llvm::LLVMContext& context, Ir* sir) for (it = ir.seenTemplateInstances.begin(); it != end; ++it) (*it)->codegen(sir); ir.seenTemplateInstances.clear(); - - // emit any newly added function bodies - sir->emitFunctionBodies(); } } @@ -532,8 +526,8 @@ void Module::genmoduleinfo() std::vector classInits; for (size_t i = 0; i < aclasses.dim; i++) { - ClassDeclaration* cd = static_cast(aclasses.data[i]); - cd->codegen(Type::sir); + ClassDeclaration* cd = aclasses[i]; + DtoResolveClass(cd); if (cd->isInterfaceDeclaration()) { @@ -638,6 +632,7 @@ void Module::genmoduleinfo() // create and set initializer LLGlobalVariable *moduleInfoSym = moduleInfoSymbol(); b.finalize(moduleInfoSym->getType()->getPointerElementType(), moduleInfoSym); + moduleInfoSym->setLinkage(llvm::GlobalValue::ExternalLinkage); // build the modulereference and ctor for registering it LLFunction* mictor = build_module_reference_and_ctor(moduleInfoSym); diff --git a/gen/naked.cpp b/gen/naked.cpp index 5e6f5d12..7850dc6e 100644 --- a/gen/naked.cpp +++ b/gen/naked.cpp @@ -85,6 +85,7 @@ void ExpStatement::toNakedIR(IRState *p) // enum decls should always be safe // make sure the symbols gets processed + // TODO: codegen() here is likely incorrect d->declaration->codegen(Type::sir); } diff --git a/gen/rttibuilder.cpp b/gen/rttibuilder.cpp index c1711d70..1a2cc847 100644 --- a/gen/rttibuilder.cpp +++ b/gen/rttibuilder.cpp @@ -20,8 +20,7 @@ RTTIBuilder::RTTIBuilder(AggregateDeclaration* base_class) { - // make sure the base typeinfo class has been processed - base_class->codegen(Type::sir); + DtoResolveDsymbol(base_class); base = base_class; basetype = static_cast(base->type); @@ -136,7 +135,7 @@ void RTTIBuilder::push_funcptr(FuncDeclaration* fd, Type* castto) { if (fd) { - fd->codegen(Type::sir); + DtoResolveDsymbol(fd); LLConstant* F = fd->ir.irFunc->func; if (castto) F = DtoBitCast(F, DtoType(castto)); @@ -177,7 +176,9 @@ void RTTIBuilder::finalize(LLType* type, LLValue* value) LLConstant* tiInit = LLConstantStruct::get(st, inits); // set the initializer - isaGlobalVar(value)->setInitializer(tiInit); + llvm::GlobalVariable* gvar = llvm::cast(value); + gvar->setInitializer(tiInit); + gvar->setLinkage(TYPEINFO_LINKAGE_TYPE); } LLConstant* RTTIBuilder::get_constant(LLStructType *initType) diff --git a/gen/structs.cpp b/gen/structs.cpp index 19055036..ed2171c9 100644 --- a/gen/structs.cpp +++ b/gen/structs.cpp @@ -55,32 +55,6 @@ void DtoResolveStruct(StructDeclaration* sd) assert(!vd->ir.irField); (void)new IrField(vd); } - - // perform definition - bool emitGlobalData = mustDefineSymbol(sd); - if (emitGlobalData) - { - // emit the initZ symbol - LLGlobalVariable* initZ = iraggr->getInitSymbol(); - - // set initZ initializer - initZ->setInitializer(iraggr->getDefaultInit()); - } - - // emit members - if (sd->members) - { - for (ArrayIter it(sd->members); !it.done(); it.next()) - { - it.get()->codegen(Type::sir); - } - } - - if (emitGlobalData) - { - // emit typeinfo - DtoTypeInfoOf(sd->type); - } } ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/gen/toir.cpp b/gen/toir.cpp index 2f794e13..2c613612 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -13,6 +13,7 @@ #include "id.h" #include "init.h" #include "mtype.h" +#include "module.h" #include "port.h" #include "rmem.h" #include "template.h" @@ -200,8 +201,7 @@ LLConstant* VarExp::toConstElem(IRState* p) Logger::print("Sym: type=%s\n", sdecltype->toChars()); assert(sdecltype->ty == Tstruct); TypeStruct* ts = static_cast(sdecltype); - ts->sym->codegen(Type::sir); - + DtoResolveStruct(ts->sym); return ts->sym->ir.irAggr->getDefaultInit(); } @@ -1186,7 +1186,7 @@ LLConstant* CastExp::toConstElem(IRState* p) else if (tb->ty == Tpointer && e1->op == TOKvar) { VarDeclaration *vd = static_cast(e1)->var->isVarDeclaration(); assert(vd); - vd->codegen(Type::sir); + DtoResolveVariable(vd); LLConstant *value = vd->ir.irGlobal ? isaConstant(vd->ir.irGlobal->value) : 0; if (!value) goto Lerr; @@ -1355,7 +1355,7 @@ DValue* AddrExp::toElem(IRState* p) //Logger::println("FuncDeclaration"); FuncDeclaration* fd = fv->func; assert(fd); - fd->codegen(Type::sir); + DtoResolveFunction(fd); return new DFuncValue(fd, fd->ir.irFunc->func); } else if (v->isIm()) { @@ -1407,7 +1407,7 @@ LLConstant* AddrExp::toConstElem(IRState* p) VarDeclaration* vd = vexp->var->isVarDeclaration(); assert(vd); assert(vd->type->toBasetype()->ty == Tsarray); - vd->codegen(Type::sir); + DtoResolveVariable(vd); assert(vd->ir.irGlobal); // get index @@ -1632,7 +1632,6 @@ DValue* DotVarExp::toElem(IRState* p) } else { - fdecl->codegen(Type::sir); funcval = fdecl->ir.irFunc->func; } assert(funcval); @@ -2123,7 +2122,7 @@ DValue* NewExp::toElem(IRState* p) if (allocator) { // custom allocator - allocator->codegen(Type::sir); + DtoResolveDsymbol(allocator); DFuncValue dfn(allocator, allocator->ir.irFunc->func); DValue* res = DtoCallFunction(loc, NULL, &dfn, newargs); mem = DtoBitCast(res->getRVal(), DtoType(ntype->pointerTo()), ".newstruct_custom"); @@ -2139,7 +2138,7 @@ DValue* NewExp::toElem(IRState* p) } else { assert(ts->sym); - ts->sym->codegen(Type::sir); + DtoResolveStruct(ts->sym); DtoAggrCopy(mem, ts->sym->ir.irAggr->getInitSymbol()); } if (ts->sym->isNested() && ts->sym->vthis) @@ -2150,7 +2149,7 @@ DValue* NewExp::toElem(IRState* p) { Logger::println("Calling constructor"); assert(arguments != NULL); - member->codegen(Type::sir); + DtoResolveDsymbol(member); DFuncValue dfn(member, member->ir.irFunc->func, mem); DtoCallFunction(loc, ts, &dfn, arguments); } @@ -2313,7 +2312,7 @@ DValue* AssertExp::toElem(IRState* p) (invdecl = static_cast(condty->nextOf())->sym->inv) != NULL) { Logger::print("calling struct invariant"); - static_cast(condty->nextOf())->sym->codegen(Type::sir); + DtoResolveFunction(invdecl); DFuncValue invfunc(invdecl, invdecl->ir.irFunc->func, cond->getRVal()); DtoCallFunction(loc, NULL, &invfunc, NULL); } @@ -2541,7 +2540,21 @@ DValue* DelegateExp::toElem(IRState* p) llvm_unreachable("Delegate to interface method not implemented."); else { - func->codegen(Type::sir); + DtoResolveFunction(func); + + // We need to actually codegen the function here, as literals are not + // added to the module member list. + if (func->semanticRun == PASSsemantic3done) + { + Dsymbol *owner = func->toParent(); + while (!owner->isTemplateInstance() && owner->toParent()) + owner = owner->toParent(); + if (owner->isTemplateInstance() || owner == p->dmodule) + { + func->codegen(Type::sir); + } + } + castfptr = func->ir.irFunc->func; } @@ -2785,6 +2798,8 @@ DValue* FuncExp::toElem(IRState* p) if (fd->isNested()) Logger::println("nested"); Logger::println("kind = %s", fd->kind()); + // We need to actually codegen the function here, as literals are not added + // to the module member list. fd->codegen(Type::sir); assert(fd->ir.irFunc->func); @@ -2852,6 +2867,8 @@ LLConstant* FuncExp::toConstElem(IRState* p) return 0; } + // We need to actually codegen the function here, as literals are not added + // to the module member list. fd->codegen(Type::sir); assert(fd->ir.irFunc->func); @@ -2987,7 +3004,7 @@ DValue* StructLiteralExp::toElem(IRState* p) assert(sdecltype->ty == Tstruct); TypeStruct* ts = static_cast(sdecltype); assert(ts->sym); - ts->sym->codegen(Type::sir); + DtoResolveStruct(ts->sym); LLValue* initsym = ts->sym->ir.irAggr->getInitSymbol(); initsym = DtoBitCast(initsym, DtoType(ts->pointerTo())); @@ -2997,7 +3014,7 @@ DValue* StructLiteralExp::toElem(IRState* p) if (inProgressMemory) return new DVarValue(type, inProgressMemory); // make sure the struct is fully resolved - sd->codegen(Type::sir); + DtoResolveStruct(sd); // alloca a stack slot inProgressMemory = DtoRawAlloca(DtoType(type), 0, ".structliteral"); @@ -3101,13 +3118,13 @@ LLConstant* StructLiteralExp::toConstElem(IRState* p) Logger::print("Sym: type=%s\n", sdecltype->toChars()); assert(sdecltype->ty == Tstruct); TypeStruct* ts = static_cast(sdecltype); - ts->sym->codegen(Type::sir); + DtoResolveStruct(ts->sym); return ts->sym->ir.irAggr->getDefaultInit(); } // make sure the struct is resolved - sd->codegen(Type::sir); + DtoResolveStruct(sd); std::map varInits; const size_t nexprs = elements->dim; @@ -3129,8 +3146,7 @@ llvm::Constant* ClassReferenceExp::toConstElem(IRState *p) LOG_SCOPE; ClassDeclaration* origClass = originalClass(); - - origClass->codegen(Type::sir); + DtoResolveClass(origClass); if (value->globalVar) { diff --git a/gen/tollvm.cpp b/gen/tollvm.cpp index a23aad11..9bbaceaf 100644 --- a/gen/tollvm.cpp +++ b/gen/tollvm.cpp @@ -294,22 +294,17 @@ LLValue* DtoDelegateEquals(TOK op, LLValue* lhs, LLValue* rhs) LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym) { - const bool mustDefine = mustDefineSymbol(sym); - // global/static variable if (VarDeclaration* vd = sym->isVarDeclaration()) { - if (mustDefine) - { - IF_LOG Logger::println("Variable %savailable externally: %s", - (vd->availableExternally ? "" : "not "), vd->toChars()); - } + IF_LOG Logger::println("Variable %savailable externally: %s", + (vd->availableExternally ? "" : "not "), vd->toChars()); // generated by inlining semantics run - if (vd->availableExternally && mustDefine) + if (vd->availableExternally) return llvm::GlobalValue::AvailableExternallyLinkage; // template - if (needsTemplateLinkage(sym)) + if (DtoIsTemplateInstance(sym)) return templateLinkage; // Currently, we have to consider all variables, even function-local @@ -330,11 +325,8 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym) } else if (FuncDeclaration* fdecl = sym->isFuncDeclaration()) { - if (mustDefine) - { - IF_LOG Logger::println("Function %savailable externally: %s", - (fdecl->availableExternally ? "" : "not "), fdecl->toChars()); - } + IF_LOG Logger::println("Function %savailable externally: %s", + (fdecl->availableExternally ? "" : "not "), fdecl->toChars()); assert(fdecl->type->ty == Tfunction); TypeFunction* ft = static_cast(fdecl->type); @@ -347,7 +339,7 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym) // available_externally. Naked functions are turned into module-level // inline asm and are thus declaration-only as far as the LLVM IR level // is concerned. - if (fdecl->availableExternally && mustDefine && !fdecl->naked) + if (fdecl->availableExternally && !fdecl->naked) return llvm::GlobalValue::AvailableExternallyLinkage; // array operations are always template linkage @@ -357,7 +349,7 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym) // template instances should have weak linkage // but only if there's a body, and it's not naked // otherwise we make it external - if (needsTemplateLinkage(fdecl) && fdecl->fbody && !fdecl->naked) + if (DtoIsTemplateInstance(fdecl) && fdecl->fbody && !fdecl->naked) return templateLinkage; // extern(C) functions are always external @@ -375,16 +367,14 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym) // class else if (ClassDeclaration* cd = sym->isClassDeclaration()) { - if (mustDefine) - { - IF_LOG Logger::println("Class %savailable externally: %s", - (cd->availableExternally ? "" : "not "), vd->toChars()); - } + IF_LOG Logger::println("Class %savailable externally: %s", + (cd->availableExternally ? "" : "not "), vd->toChars()); + // generated by inlining semantics run - if (cd->availableExternally && mustDefine) + if (cd->availableExternally) return llvm::GlobalValue::AvailableExternallyLinkage; // template - if (needsTemplateLinkage(cd)) + if (DtoIsTemplateInstance(cd)) return templateLinkage; } else @@ -392,10 +382,8 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym) llvm_unreachable("not global/function"); } - // If the function needs to be defined in the current module, check if it - // is a nested function and we can declare it as internal. - bool canInternalize = mustDefine; - + // Check if sym is a nested function and we can declare it as internal. + // // Nested naked functions and the implicitly generated __require/__ensure // functions for in/out contracts cannot be internalized. The reason // for the latter is that contract functions, despite being nested, can be @@ -403,39 +391,28 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym) // interface methods (where __require/__ensure are emitted to the module // where the interface is declared, but an actual interface implementation // can be in a completely different place). - if (canInternalize) - { - if (FuncDeclaration* fd = sym->isFuncDeclaration()) - { - if ((fd->naked != 0) || - (fd->ident == Id::require) || (fd->ident == Id::ensure)) - { - canInternalize = false; - } - } - } - - // Any symbol nested in a function that cannot be inlined can't be - // referenced directly from outside that function, so we can give - // such symbols internal linkage. This holds even if nested indirectly, - // such as member functions of aggregates nested in functions. - // - // Note: This must be checked after things like template member-ness or - // symbols nested in templates would get duplicated for each module, - // breaking things like - // --- - // int counter(T)() { static int i; return i++; }" - // --- - // if instances get emitted in multiple object files because they'd use - // different instances of 'i'. - // TODO: Check if we are giving away too much inlining potential due to - // canInline being overly conservative here. - if (canInternalize) + FuncDeclaration* fd = sym->isFuncDeclaration(); + if (!fd || (!fd->naked && fd->ident != Id::require && fd->ident != Id::ensure)) { + // Any symbol nested in a function that cannot be inlined can't be + // referenced directly from outside that function, so we can give + // such symbols internal linkage. This holds even if nested indirectly, + // such as member functions of aggregates nested in functions. + // + // Note: This must be checked after things like template member-ness or + // symbols nested in templates would get duplicated for each module, + // breaking things like + // --- + // int counter(T)() { static int i; return i++; }" + // --- + // if instances get emitted in multiple object files because they'd use + // different instances of 'i'. + // TODO: Check if we are giving away too much inlining potential due to + // canInline being overly conservative here. for (Dsymbol* parent = sym->parent; parent ; parent = parent->parent) { - FuncDeclaration *fd = parent->isFuncDeclaration(); - if (fd && !fd->canInline(fd->needThis(), false, false)) + FuncDeclaration *parentFd = parent->isFuncDeclaration(); + if (parentFd && !parentFd->canInline(parentFd->needThis(), false, false)) { // We also cannot internalize nested functions which are // leaked to the outside via a templated return type, because @@ -444,8 +421,8 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym) // Since we can't easily determine if this is really the case // here, just don't internalize it if the parent returns a // template at all, to be safe. - TypeFunction* tf = static_cast(fd->type); - if (!DtoIsTemplateInstance(tf->next->toDsymbol(fd->scope))) + TypeFunction* tf = static_cast(parentFd->type); + if (!DtoIsTemplateInstance(tf->next->toDsymbol(parentFd->scope))) return llvm::GlobalValue::InternalLinkage; } } @@ -468,8 +445,8 @@ static bool isAvailableExternally(Dsymbol* sym) llvm::GlobalValue::LinkageTypes DtoInternalLinkage(Dsymbol* sym) { - if (needsTemplateLinkage(sym)) { - if (isAvailableExternally(sym) && mustDefineSymbol(sym)) + if (DtoIsTemplateInstance(sym)) { + if (isAvailableExternally(sym)) return llvm::GlobalValue::AvailableExternallyLinkage; return templateLinkage; } @@ -479,9 +456,9 @@ llvm::GlobalValue::LinkageTypes DtoInternalLinkage(Dsymbol* sym) llvm::GlobalValue::LinkageTypes DtoExternalLinkage(Dsymbol* sym) { - if (needsTemplateLinkage(sym)) + if (DtoIsTemplateInstance(sym)) return templateLinkage; - else if (isAvailableExternally(sym) && mustDefineSymbol(sym)) + else if (isAvailableExternally(sym)) return llvm::GlobalValue::AvailableExternallyLinkage; else return llvm::GlobalValue::ExternalLinkage; diff --git a/gen/typeinf.h b/gen/typeinf.h index 7a77ad5b..e2d37b6b 100644 --- a/gen/typeinf.h +++ b/gen/typeinf.h @@ -17,7 +17,6 @@ struct TypeInfoDeclaration; void DtoResolveTypeInfo(TypeInfoDeclaration* tid); -void DtoDeclareTypeInfo(TypeInfoDeclaration* tid); void DtoConstInitTypeInfo(TypeInfoDeclaration* tid); #endif diff --git a/gen/typinf.cpp b/gen/typinf.cpp index 5df51507..bb99c1ce 100644 --- a/gen/typinf.cpp +++ b/gen/typinf.cpp @@ -282,40 +282,8 @@ int TypeClass::builtinTypeInfo() // (wut?) ////////////////////////////////////////////////////////////////////////////// -void DtoResolveTypeInfo(TypeInfoDeclaration* tid); -void DtoDeclareTypeInfo(TypeInfoDeclaration* tid); - -void TypeInfoDeclaration::codegen(Ir*) +static void emitTypeMetadata(TypeInfoDeclaration *tid) { - 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->isClass()->getMemoryLLType(); - 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; - // We don't want to generate metadata for non-concrete types (such as tuple // types, slice types, typeof(expr), etc.), void and function types (without // an indirection), as there must be a valid LLVM undef value of that type. @@ -324,13 +292,14 @@ void DtoResolveTypeInfo(TypeInfoDeclaration* tid) Type* t = tid->tinfo->toBasetype(); if (t->ty < Terror && t->ty != Tvoid && t->ty != Tfunction && t->ty != Tident) { // Add some metadata for use by optimization passes. - std::string metaname = std::string(TD_PREFIX) + mangle; + std::string metaname(TD_PREFIX); + metaname += tid->mangle(); llvm::NamedMDNode* meta = gIR->module->getNamedMetadata(metaname); if (!meta) { // Construct the fields MDNodeField* mdVals[TD_NumFields]; - mdVals[TD_TypeInfo] = llvm::cast(irg->value); + mdVals[TD_TypeInfo] = llvm::cast(tid->ir.irGlobal->value); mdVals[TD_Type] = llvm::UndefValue::get(DtoType(tid->tinfo)); // Construct the metadata and insert it into the module. @@ -339,39 +308,59 @@ void DtoResolveTypeInfo(TypeInfoDeclaration* tid) llvm::makeArrayRef(mdVals, TD_NumFields))); } } - - DtoDeclareTypeInfo(tid); } -void DtoDeclareTypeInfo(TypeInfoDeclaration* tid) +void DtoResolveTypeInfo(TypeInfoDeclaration* tid) { - DtoResolveTypeInfo(tid); + if (tid->ir.resolved) return; + tid->ir.resolved = true; - if (tid->ir.declared) return; - tid->ir.declared = true; + // TypeInfo instances (except ClassInfo ones) are always emitted as weak + // symbols when they are used. + tid->codegen(Type::sir); +} - Logger::println("DtoDeclareTypeInfo(%s)", tid->toChars()); +void TypeInfoDeclaration::codegen(Ir*) +{ + Logger::println("TypeInfoDeclaration::codegen(%s)", toPrettyChars()); LOG_SCOPE; + if (ir.defined) return; + ir.defined = true; + + std::string mangled(mangle()); if (Logger::enabled()) { - std::string mangled(tid->mangle()); - Logger::println("type = '%s'", tid->tinfo->toChars()); + Logger::println("type = '%s'", tinfo->toChars()); Logger::println("typeinfo mangle: %s", mangled.c_str()); } - IrGlobal* irg = tid->ir.irGlobal; - assert(irg->value != NULL); + IrGlobal* irg = new IrGlobal(this); + ir.irGlobal = irg; + irg->value = gIR->module->getGlobalVariable(mangled); + if (irg->value) { + irg->type = irg->value->getType()->getContainedType(0); + assert(irg->type->isStructTy()); + } else { + if (tinfo->builtinTypeInfo()) // this is a declaration of a builtin __initZ var + irg->type = Type::typeinfo->type->irtype->isClass()->getMemoryLLType(); + else + irg->type = LLStructType::create(gIR->context(), toPrettyChars()); + irg->value = new llvm::GlobalVariable(*gIR->module, irg->type, true, + llvm::GlobalValue::ExternalLinkage, NULL, mangled); + } + + emitTypeMetadata(this); // this is a declaration of a builtin __initZ var - if (tid->tinfo->builtinTypeInfo()) { + if (tinfo->builtinTypeInfo()) { LLGlobalVariable* g = isaGlobalVar(irg->value); g->setLinkage(llvm::GlobalValue::ExternalLinkage); return; } // define custom typedef - tid->llvmDefine(); + llvmDefine(); } /* ========================================================================= */ @@ -613,7 +602,7 @@ void TypeInfoStructDeclaration::llvmDefine() fatal(); } - sd->codegen(Type::sir); + DtoResolveStruct(sd); IrAggr* iraggr = sd->ir.irAggr; RTTIBuilder b(Type::typeinfostruct); @@ -739,20 +728,31 @@ void TypeInfoStructDeclaration::llvmDefine() /* ========================================================================= */ -void TypeInfoClassDeclaration::codegen(Ir*i) +void TypeInfoClassDeclaration::codegen(Ir* p) { - - IrGlobal* irg = new IrGlobal(this); + // For classes, the TypeInfo is in fact a ClassInfo instance and emitted + // as a __ClassZ symbol. For interfaces, the __InterfaceZ symbol is + // referenced as "info" member in a (normal) TypeInfo_Interface instance. + 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 + DtoResolveClass(tc->sym); + irg->value = tc->sym->ir.irAggr->getClassInfoSymbol(); + irg->type = irg->value->getType()->getContainedType(0); + + if (!tc->sym->isInterfaceDeclaration()) + { + emitTypeMetadata(this); + } } void TypeInfoClassDeclaration::llvmDefine() { - llvm_unreachable("TypeInfoClassDeclaration should not be called for D2"); + llvm_unreachable("TypeInfoClassDeclaration::llvmDefine() should not be called, " + "as a custom Dsymbol::codegen() override is used"); } /* ========================================================================= */ @@ -765,7 +765,7 @@ void TypeInfoInterfaceDeclaration::llvmDefine() // make sure interface is resolved assert(tinfo->ty == Tclass); TypeClass *tc = static_cast(tinfo); - tc->sym->codegen(Type::sir); + DtoResolveClass(tc->sym); RTTIBuilder b(Type::typeinfointerface); diff --git a/ir/ir.cpp b/ir/ir.cpp index 156c209c..8cf64d92 100644 --- a/ir/ir.cpp +++ b/ir/ir.cpp @@ -47,18 +47,3 @@ Ir::Ir() : irs(NULL) { } - -void Ir::addFunctionBody(IrFunction * f) -{ - functionbodies.push_back(f); -} - -void Ir::emitFunctionBodies() -{ - while (!functionbodies.empty()) - { - IrFunction* irf = functionbodies.front(); - functionbodies.pop_front(); - DtoDefineFunction(irf->decl); - } -} diff --git a/ir/ir.h b/ir/ir.h index fa20b998..505b23de 100644 --- a/ir/ir.h +++ b/ir/ir.h @@ -31,9 +31,6 @@ public: void setState(IRState* p) { irs = p; } IRState* getState() { return irs; } - void addFunctionBody(IrFunction* f); - void emitFunctionBodies(); - private: IRState* irs; diff --git a/ir/iraggr.cpp b/ir/iraggr.cpp index 35733b79..a065df66 100644 --- a/ir/iraggr.cpp +++ b/ir/iraggr.cpp @@ -61,10 +61,8 @@ LLGlobalVariable * IrAggr::getInitSymbol() initname.append(aggrdecl->mangle()); initname.append("6__initZ"); - llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); - init = getOrCreateGlobal(aggrdecl->loc, - *gIR->module, init_type, true, _linkage, NULL, initname); + *gIR->module, init_type, true, llvm::GlobalValue::ExternalLinkage, NULL, initname); // set alignment init->setAlignment(type->alignsize()); diff --git a/ir/iraggr.h b/ir/iraggr.h index 04621c28..87e53764 100644 --- a/ir/iraggr.h +++ b/ir/iraggr.h @@ -57,9 +57,9 @@ struct IrAggr /// Builds the __vtblZ initializer constant lazily. LLConstant* getVtblInit(); - /// Create the __ClassZ symbol lazily. + /// Create the __ClassZ/__InterfaceZ symbol lazily. LLGlobalVariable* getClassInfoSymbol(); - /// Builds the __ClassZ initializer constant lazily. + /// Builds the __ClassZ/__InterfaceZ initializer constant lazily. LLConstant* getClassInfoInit(); /// Create the __interfaceInfos symbol lazily. diff --git a/ir/irclass.cpp b/ir/irclass.cpp index c651397e..a9618298 100644 --- a/ir/irclass.cpp +++ b/ir/irclass.cpp @@ -53,12 +53,10 @@ LLGlobalVariable * IrAggr::getVtblSymbol() initname.append(aggrdecl->mangle()); initname.append("6__vtblZ"); - llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); - LLType* vtblTy = stripModifiers(type)->irtype->isClass()->getVtbl(); vtbl = getOrCreateGlobal(aggrdecl->loc, - *gIR->module, vtblTy, true, _linkage, NULL, initname); + *gIR->module, vtblTy, true, llvm::GlobalValue::ExternalLinkage, NULL, initname); return vtbl; } @@ -79,8 +77,9 @@ LLGlobalVariable * IrAggr::getClassInfoSymbol() else initname.append("7__ClassZ"); - llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); - + // The type is also ClassInfo for interfaces – the actual TypeInfo for them + // is a TypeInfo_Interface instance that references __ClassZ in its "base" + // member. ClassDeclaration* cinfo = ClassDeclaration::classinfo; DtoType(cinfo->type); IrTypeClass* tc = stripModifiers(cinfo->type)->irtype->isClass(); @@ -88,7 +87,8 @@ LLGlobalVariable * IrAggr::getClassInfoSymbol() // classinfos cannot be constants since they're used as locks for synchronized classInfo = getOrCreateGlobal(aggrdecl->loc, - *gIR->module, tc->getMemoryLLType(), false, _linkage, NULL, initname); + *gIR->module, tc->getMemoryLLType(), false, + llvm::GlobalValue::ExternalLinkage, NULL, initname); // Generate some metadata on this ClassInfo if it's for a class. ClassDeclaration* classdecl = aggrdecl->isClassDeclaration(); @@ -138,9 +138,8 @@ LLGlobalVariable * IrAggr::getInterfaceArraySymbol() name.append(cd->mangle()); name.append("16__interfaceInfosZ"); - llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); classInterfacesArray = getOrCreateGlobal(cd->loc, *gIR->module, - array_type, true, _linkage, NULL, name); + array_type, true, llvm::GlobalValue::ExternalLinkage, NULL, name); return classInterfacesArray; } @@ -182,7 +181,7 @@ LLConstant * IrAggr::getVtblInit() } else { - fd->codegen(Type::sir); + DtoResolveFunction(fd); assert(fd->ir.irFunc && "invalid vtbl function"); c = fd->ir.irFunc->func; if (cd->isFuncHidden(fd)) @@ -320,7 +319,7 @@ llvm::GlobalVariable * IrAggr::getInterfaceVtbl(BaseClass * b, bool new_instance assert((!fd->isAbstract() || fd->fbody) && "null symbol in interface implementation vtable"); - fd->codegen(Type::sir); + DtoResolveFunction(fd); assert(fd->ir.irFunc && "invalid vtbl function"); LLFunction *fn = fd->ir.irFunc->func; @@ -380,9 +379,6 @@ llvm::GlobalVariable * IrAggr::getInterfaceVtbl(BaseClass * b, bool new_instance // build the vtbl constant llvm::Constant* vtbl_constant = LLConstantStruct::getAnon(gIR->context(), constants, false); - // create the global variable to hold it - llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); - std::string mangle("_D"); mangle.append(cd->mangle()); mangle.append("11__interface"); @@ -393,7 +389,7 @@ llvm::GlobalVariable * IrAggr::getInterfaceVtbl(BaseClass * b, bool new_instance *gIR->module, vtbl_constant->getType(), true, - _linkage, + llvm::GlobalValue::ExternalLinkage, vtbl_constant, mangle ); diff --git a/ir/irlandingpad.cpp b/ir/irlandingpad.cpp index 69a1e96f..ac3f6077 100644 --- a/ir/irlandingpad.cpp +++ b/ir/irlandingpad.cpp @@ -34,7 +34,7 @@ IRLandingPadCatchInfo::IRLandingPadCatchInfo(Catch* catchstmt_, llvm::BasicBlock assert(catchStmt->type); catchType = catchStmt->type->toBasetype()->isClassHandle(); assert(catchType); - catchType->codegen(Type::sir); + DtoResolveClass(catchType); if (catchStmt->var) { if (!catchStmt->var->nestedrefs.dim) {