diff --git a/dmd2/declaration.h b/dmd2/declaration.h index 8b73bad9e75..a503a20d41e 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 81121c657b3..db81f48e42a 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 db90c9a47ee..399509e96ba 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 c7af9b7dfdb..8dc9a9e692d 100644 --- a/gen/classes.cpp +++ b/gen/classes.cpp @@ -35,24 +35,21 @@ void DtoResolveClass(ClassDeclaration* cd) { + 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(); - if (bc) - { - bc->base->codegen(Type::sir); - } + DtoResolveClass(bc->base); 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 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 aea69157be7..e9bff5c8d55 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 7e0122a11d4..74bae086732 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 aec891d786e..14cf1f8de28 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 14a15678bb9..14d3adf6fc7 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 ebd447d0932..e894912b71f 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 5e6f5d1255d..7850dc6e020 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 c1711d70378..1a2cc847acf 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 190550369c2..ed2171c97c0 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 2f794e13e7c..2c613612683 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 a23aad11ce0..9bbaceafc29 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 7a77ad5bfa3..e2d37b6bb1f 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 5df51507fa0..bb99c1cea9d 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*) -{ - DtoResolveTypeInfo(this); -} - -void DtoResolveTypeInfo(TypeInfoDeclaration* tid) +static void emitTypeMetadata(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 156c209c84e..8cf64d92577 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 fa20b998483..505b23dee8b 100644 --- a/ir/ir.h +++ b/ir/ir.h @@ -31,9 +31,6 @@ class Ir 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 35733b798ac..a065df6683b 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 04621c28432..87e53764151 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 c651397e923..a96182989fd 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 69a1e96f127..ac3f60779c7 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) {