// Copyright (c) 1999-2004 by Digital Mars // All Rights Reserved // written by Walter Bright // www.digitalmars.com // License for redistribution is by either the Artistic License // in artistic.txt, or the GNU General Public License in gnu.txt. // See the included readme.txt for details. #include #include #include #include "gen/llvm.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/Target/SubtargetFeature.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetMachineRegistry.h" #include "llvm/Module.h" #include "llvm/ModuleProvider.h" #include "llvm/PassManager.h" #include "llvm/LinkAllPasses.h" #include "llvm/System/Program.h" #include "llvm/System/Path.h" #include "llvm/Support/raw_ostream.h" #include "mars.h" #include "module.h" #include "mtype.h" #include "declaration.h" #include "statement.h" #include "enum.h" #include "aggregate.h" #include "init.h" #include "attrib.h" #include "id.h" #include "import.h" #include "template.h" #include "scope.h" #include "gen/irstate.h" #include "gen/logger.h" #include "gen/tollvm.h" #include "gen/llvmhelpers.h" #include "gen/arrays.h" #include "gen/structs.h" #include "gen/classes.h" #include "gen/functions.h" #include "gen/todebug.h" #include "gen/runtime.h" #include "ir/irvar.h" #include "ir/irmodule.h" ////////////////////////////////////////////////////////////////////////////////////////// // in gen/optimize.cpp void ldc_optimize_module(llvm::Module* m, char lvl, bool doinline); // fwd decl void write_asm_to_file(llvm::TargetMachine &Target, llvm::Module& m, llvm::raw_fd_ostream& Out); void assemble(const llvm::sys::Path& asmpath, const llvm::sys::Path& objpath); ////////////////////////////////////////////////////////////////////////////////////////// void Module::genobjfile(int multiobj) { bool logenabled = Logger::enabled(); if (llvmForceLogging && !logenabled) { Logger::enable(); } Logger::println("Generating module: %s\n", (md ? md->toChars() : toChars())); LOG_SCOPE; //printf("codegen: %s\n", srcfile->toChars()); assert(!global.errors); // start by deleting the old object file deleteObjFile(); // name the module std::string mname(toChars()); if (md != 0) mname = md->toChars(); // create a new ir state // TODO look at making the instance static and moving most functionality into IrModule where it belongs IRState ir(new llvm::Module(mname)); gIR = &ir; ir.dmodule = this; // reset all IR data stored in Dsymbols and Types IrDsymbol::resetAll(); IrType::resetAll(); // module ir state // might already exist via import, just overwrite since // the global created for the filename must belong to the right llvm module // FIXME: but shouldn't this always get reset between modules? like other IrSymbols this->ir.irModule = new IrModule(this, srcfile->toChars()); // set target stuff ir.module->setTargetTriple(global.params.targetTriple); ir.module->setDataLayout(global.params.dataLayout); // get the target machine const llvm::TargetMachineRegistry::entry* MArch; std::string Err; MArch = llvm::TargetMachineRegistry::getClosestStaticTargetForModule(*ir.module, Err); if (MArch == 0) { error("error auto-selecting target for module '%s'", Err.c_str()); fatal(); } llvm::SubtargetFeatures Features; //TODO: Features? // Features.setCPU(MCPU); // for (unsigned i = 0; i != MAttrs.size(); ++i) // Features.AddFeature(MAttrs[i]); // only generate PIC code when -fPIC switch is used if (global.params.pic) llvm::TargetMachine::setRelocationModel(llvm::Reloc::PIC_); // allocate the target machine std::auto_ptr target(MArch->CtorFn(*ir.module, Features.getString())); assert(target.get() && "Could not allocate target machine!"); llvm::TargetMachine &Target = *target.get(); gTargetData = Target.getTargetData(); // set final data layout std::string datalayout = gTargetData->getStringRepresentation(); ir.module->setDataLayout(datalayout); if (Logger::enabled()) Logger::cout() << "Final data layout: " << datalayout << '\n'; assert(memcmp(global.params.dataLayout, datalayout.c_str(), 9) == 0); // "E-p:xx:xx" // debug info if (global.params.symdebug) { RegisterDwarfSymbols(ir.module); DtoDwarfCompileUnit(this); } // handle invalid 'objectø module if (!ClassDeclaration::object) { error("is missing 'class Object'"); fatal(); } if (!ClassDeclaration::classinfo) { error("is missing 'class ClassInfo'"); fatal(); } // process module members for (int k=0; k < members->dim; k++) { Dsymbol* dsym = (Dsymbol*)(members->data[k]); assert(dsym); dsym->toObjFile(multiobj); } // main driver loop DtoEmptyAllLists(); // generate ModuleInfo genmoduleinfo(); // do this again as moduleinfo might have pulled something in! DtoEmptyAllLists(); // emit usedArray if (!ir.usedArray.empty()) { const LLArrayType* usedTy = LLArrayType::get(getVoidPtrType(), ir.usedArray.size()); LLConstant* usedInit = LLConstantArray::get(usedTy, ir.usedArray); LLGlobalVariable* usedArray = new LLGlobalVariable(usedTy, true, LLGlobalValue::AppendingLinkage, usedInit, "llvm.used", ir.module); usedArray->setSection("llvm.metadata"); } // verify the llvm if (!global.params.novalidate) { std::string verifyErr; Logger::println("Verifying module..."); LOG_SCOPE; if (llvm::verifyModule(*ir.module,llvm::ReturnStatusAction,&verifyErr)) { error("%s", verifyErr.c_str()); fatal(); } else { Logger::println("Verification passed!"); } } // always run this pass to eliminate dead code that breaks debug info llvm::PassManager pm; pm.add(new llvm::TargetData(ir.module)); pm.add(llvm::createCFGSimplificationPass()); pm.run(*ir.module); // run optimizer ldc_optimize_module(ir.module, global.params.optimizeLevel, global.params.llvmInline); // verify the llvm if (!global.params.novalidate && (global.params.optimizeLevel >= 0 || global.params.llvmInline)) { std::string verifyErr; Logger::println("Verifying module... again..."); LOG_SCOPE; if (llvm::verifyModule(*ir.module,llvm::ReturnStatusAction,&verifyErr)) { error("%s", verifyErr.c_str()); fatal(); } else { Logger::println("Verification passed!"); } } // eventually do our own path stuff, dmd's is a bit strange. typedef llvm::sys::Path LLPath; // write LLVM bitcode if (global.params.output_bc) { LLPath bcpath = LLPath(objfile->name->toChars()); bcpath.eraseSuffix(); bcpath.appendSuffix(std::string(global.bc_ext)); Logger::println("Writing LLVM bitcode to: %s\n", bcpath.c_str()); std::ofstream bos(bcpath.c_str(), std::ios::binary); llvm::WriteBitcodeToFile(ir.module, bos); } // write LLVM IR if (global.params.output_ll) { LLPath llpath = LLPath(objfile->name->toChars()); llpath.eraseSuffix(); llpath.appendSuffix(std::string(global.ll_ext)); Logger::println("Writing LLVM asm to: %s\n", llpath.c_str()); std::ofstream aos(llpath.c_str()); ir.module->print(aos, NULL); } // write native assembly if (global.params.output_s || global.params.output_o) { LLPath spath = LLPath(objfile->name->toChars()); spath.eraseSuffix(); spath.appendSuffix(std::string(global.s_ext)); if (!global.params.output_s) { spath.createTemporaryFileOnDisk(); } Logger::println("Writing native asm to: %s\n", spath.c_str()); std::string err; { llvm::raw_fd_ostream out(spath.c_str(), false, err); write_asm_to_file(Target, *ir.module, out); } // call gcc to convert assembly to object file if (global.params.output_o) { LLPath objpath = LLPath(objfile->name->toChars()); assemble(spath, objpath); } if (!global.params.output_s) { spath.eraseFromDisk(); } } delete ir.module; gTargetData = 0; gIR = NULL; if (llvmForceLogging && !logenabled) { Logger::disable(); } } /* ================================================================== */ // based on llc code, University of Illinois Open Source License void write_asm_to_file(llvm::TargetMachine &Target, llvm::Module& m, llvm::raw_fd_ostream& out) { using namespace llvm; // Build up all of the passes that we want to do to the module. ExistingModuleProvider Provider(&m); FunctionPassManager Passes(&Provider); Passes.add(new TargetData(*Target.getTargetData())); // Ask the target to add backend passes as necessary. MachineCodeEmitter *MCE = 0; //TODO: May want to switch it on for -O0? bool Fast = false; FileModel::Model mod = Target.addPassesToEmitFile(Passes, out, TargetMachine::AssemblyFile, Fast); assert(mod == FileModel::AsmFile); bool err = Target.addPassesToEmitFileFinish(Passes, MCE, Fast); assert(!err); Passes.doInitialization(); // Run our queue of passes all at once now, efficiently. for (llvm::Module::iterator I = m.begin(), E = m.end(); I != E; ++I) if (!I->isDeclaration()) Passes.run(*I); Passes.doFinalization(); // release module from module provider so we can delete it ourselves std::string Err; llvm::Module* rmod = Provider.releaseModule(&Err); assert(rmod); } /* ================================================================== */ // uses gcc to make an obj out of an assembly file // based on llvm-ld code, University of Illinois Open Source License void assemble(const llvm::sys::Path& asmpath, const llvm::sys::Path& objpath) { using namespace llvm; const char *cc; #if !_WIN32 cc = getenv("CC"); if (!cc) #endif cc = "gcc"; sys::Path gcc = llvm::sys::Program::FindProgramByName(cc); if (gcc.empty()) { error("failed to locate gcc"); fatal(); } // Run GCC to assemble and link the program into native code. // // Note: // We can't just assemble and link the file with the system assembler // and linker because we don't know where to put the _start symbol. // GCC mysteriously knows how to do it. std::vector args; args.push_back(gcc.toString()); args.push_back("-fno-strict-aliasing"); args.push_back("-O3"); args.push_back("-c"); args.push_back("-xassembler"); args.push_back(asmpath.toString()); args.push_back("-o"); args.push_back(objpath.toString()); //FIXME: only use this if needed? args.push_back("-fpic"); //FIXME: enforce 64 bit if (global.params.is64bit) args.push_back("-m64"); // Now that "args" owns all the std::strings for the arguments, call the c_str // method to get the underlying string array. We do this game so that the // std::string array is guaranteed to outlive the const char* array. std::vector Args; for (unsigned i = 0, e = args.size(); i != e; ++i) Args.push_back(args[i].c_str()); Args.push_back(0); Logger::println("Assembling with: "); std::vector::const_iterator I = Args.begin(), E = Args.end(); std::ostream& logstr = Logger::cout(); for (; I != E; ++I) if (*I) logstr << "'" << *I << "'" << " "; logstr << "\n" << std::flush; // Run the compiler to assembly the program. std::string ErrMsg; int R = sys::Program::ExecuteAndWait( gcc, &Args[0], 0, 0, 0, 0, &ErrMsg); if (R) { error("failed to invoke gcc"); fatal(); } } /* ================================================================== */ // the following code generates functions and needs to output // debug info. these macros are useful for that #define DBG_TYPE ( getPtrToType(llvm::StructType::get(NULL,NULL)) ) #define DBG_CAST(X) ( llvm::ConstantExpr::getBitCast(X, DBG_TYPE) ) // build module ctor llvm::Function* build_module_ctor() { if (gIR->ctors.empty()) return NULL; size_t n = gIR->ctors.size(); if (n == 1) return gIR->ctors[0]->ir.irFunc->func; std::string name("_D"); name.append(gIR->dmodule->mangle()); name.append("6__ctorZ"); std::vector argsTy; const llvm::FunctionType* fnTy = llvm::FunctionType::get(LLType::VoidTy,argsTy,false); assert(gIR->module->getFunction(name) == NULL); llvm::Function* fn = llvm::Function::Create(fnTy, llvm::GlobalValue::InternalLinkage, name, gIR->module); fn->setCallingConv(DtoCallingConv(0, LINKd)); llvm::BasicBlock* bb = llvm::BasicBlock::Create("entry", fn); IRBuilder<> builder(bb); // debug info LLGlobalVariable* subprog; if(global.params.symdebug) { subprog = DtoDwarfSubProgramInternal(name.c_str(), name.c_str()).getGV(); builder.CreateCall(gIR->module->getFunction("llvm.dbg.func.start"), DBG_CAST(subprog)); } for (size_t i=0; ictors[i]->ir.irFunc->func; llvm::CallInst* call = builder.CreateCall(f,""); call->setCallingConv(DtoCallingConv(0, LINKd)); } // debug info end if(global.params.symdebug) builder.CreateCall(gIR->module->getFunction("llvm.dbg.region.end"), DBG_CAST(subprog)); builder.CreateRetVoid(); return fn; } // build module dtor static llvm::Function* build_module_dtor() { if (gIR->dtors.empty()) return NULL; size_t n = gIR->dtors.size(); if (n == 1) return gIR->dtors[0]->ir.irFunc->func; std::string name("_D"); name.append(gIR->dmodule->mangle()); name.append("6__dtorZ"); std::vector argsTy; const llvm::FunctionType* fnTy = llvm::FunctionType::get(LLType::VoidTy,argsTy,false); assert(gIR->module->getFunction(name) == NULL); llvm::Function* fn = llvm::Function::Create(fnTy, llvm::GlobalValue::InternalLinkage, name, gIR->module); fn->setCallingConv(DtoCallingConv(0, LINKd)); llvm::BasicBlock* bb = llvm::BasicBlock::Create("entry", fn); IRBuilder<> builder(bb); // debug info LLGlobalVariable* subprog; if(global.params.symdebug) { subprog = DtoDwarfSubProgramInternal(name.c_str(), name.c_str()).getGV(); builder.CreateCall(gIR->module->getFunction("llvm.dbg.func.start"), DBG_CAST(subprog)); } for (size_t i=0; idtors[i]->ir.irFunc->func; llvm::CallInst* call = builder.CreateCall(f,""); call->setCallingConv(DtoCallingConv(0, LINKd)); } // debug info end if(global.params.symdebug) builder.CreateCall(gIR->module->getFunction("llvm.dbg.region.end"), DBG_CAST(subprog)); builder.CreateRetVoid(); return fn; } // build module unittest static llvm::Function* build_module_unittest() { if (gIR->unitTests.empty()) return NULL; size_t n = gIR->unitTests.size(); if (n == 1) return gIR->unitTests[0]->ir.irFunc->func; std::string name("_D"); name.append(gIR->dmodule->mangle()); name.append("10__unittestZ"); std::vector argsTy; const llvm::FunctionType* fnTy = llvm::FunctionType::get(LLType::VoidTy,argsTy,false); assert(gIR->module->getFunction(name) == NULL); llvm::Function* fn = llvm::Function::Create(fnTy, llvm::GlobalValue::InternalLinkage, name, gIR->module); fn->setCallingConv(DtoCallingConv(0, LINKd)); llvm::BasicBlock* bb = llvm::BasicBlock::Create("entry", fn); IRBuilder<> builder(bb); // debug info LLGlobalVariable* subprog; if(global.params.symdebug) { subprog = DtoDwarfSubProgramInternal(name.c_str(), name.c_str()).getGV(); builder.CreateCall(gIR->module->getFunction("llvm.dbg.func.start"), DBG_CAST(subprog)); } for (size_t i=0; iunitTests[i]->ir.irFunc->func; llvm::CallInst* call = builder.CreateCall(f,""); call->setCallingConv(DtoCallingConv(0, LINKd)); } // debug info end if(global.params.symdebug) builder.CreateCall(gIR->module->getFunction("llvm.dbg.region.end"), DBG_CAST(subprog)); builder.CreateRetVoid(); return fn; } // build ModuleReference and register function, to register the module info in the global linked list static LLFunction* build_module_reference_and_ctor(LLConstant* moduleinfo) { // build ctor type const LLFunctionType* fty = LLFunctionType::get(LLType::VoidTy, std::vector(), false); // build ctor name std::string fname = "_D"; fname += gIR->dmodule->mangle(); fname += "16__moduleinfoCtorZ"; // build a function that registers the moduleinfo in the global moduleinfo linked list LLFunction* ctor = LLFunction::Create(fty, LLGlobalValue::InternalLinkage, fname, gIR->module); // provide the default initializer const LLStructType* modulerefTy = DtoModuleReferenceType(); std::vector mrefvalues; mrefvalues.push_back(LLConstant::getNullValue(modulerefTy->getContainedType(0))); mrefvalues.push_back(llvm::ConstantExpr::getBitCast(moduleinfo, modulerefTy->getContainedType(1))); LLConstant* thismrefinit = LLConstantStruct::get(modulerefTy, mrefvalues); // create the ModuleReference node for this module std::string thismrefname = "_D"; thismrefname += gIR->dmodule->mangle(); thismrefname += "11__moduleRefZ"; LLGlobalVariable* thismref = new LLGlobalVariable(modulerefTy, false, LLGlobalValue::InternalLinkage, thismrefinit, thismrefname, gIR->module); // make sure _Dmodule_ref is declared LLGlobalVariable* mref = gIR->module->getNamedGlobal("_Dmodule_ref"); if (!mref) mref = new LLGlobalVariable(getPtrToType(modulerefTy), false, LLGlobalValue::ExternalLinkage, NULL, "_Dmodule_ref", gIR->module); // make the function insert this moduleinfo as the beginning of the _Dmodule_ref linked list llvm::BasicBlock* bb = llvm::BasicBlock::Create("moduleinfoCtorEntry", ctor); IRBuilder<> builder(bb); // debug info LLGlobalVariable* subprog; if(global.params.symdebug) { subprog = DtoDwarfSubProgramInternal(fname.c_str(), fname.c_str()).getGV(); builder.CreateCall(gIR->module->getFunction("llvm.dbg.func.start"), DBG_CAST(subprog)); } // get current beginning LLValue* curbeg = builder.CreateLoad(mref, "current"); // put current beginning as the next of this one LLValue* gep = builder.CreateStructGEP(thismref, 0, "next"); builder.CreateStore(curbeg, gep); // replace beginning builder.CreateStore(thismref, mref); // debug info end if(global.params.symdebug) builder.CreateCall(gIR->module->getFunction("llvm.dbg.region.end"), DBG_CAST(subprog)); // return builder.CreateRetVoid(); return ctor; } // Put out instance of ModuleInfo for this Module void Module::genmoduleinfo() { // The layout is: // { // char[] name; // ModuleInfo[] importedModules; // ClassInfo[] localClasses; // uint flags; // // void function() ctor; // void function() dtor; // void function() unitTest; // // void* xgetMembers; // void function() ictor; // } // resolve ModuleInfo if (!moduleinfo) { error("object.d is missing the ModuleInfo class"); fatal(); } DtoForceConstInitDsymbol(moduleinfo); // check for patch if (moduleinfo->fields.dim != 9) { error("object.d ModuleInfo class is incorrect"); fatal(); } // moduleinfo llvm struct type const llvm::StructType* moduleinfoTy = isaStruct(moduleinfo->type->ir.type->get()); // classinfo llvm struct type const llvm::StructType* classinfoTy = isaStruct(ClassDeclaration::classinfo->type->ir.type->get()); // initializer vector std::vector initVec; LLConstant* c = 0; // vtable c = moduleinfo->ir.irStruct->vtbl; initVec.push_back(c); // monitor c = getNullPtr(getPtrToType(LLType::Int8Ty)); initVec.push_back(c); // name char *name = toPrettyChars(); c = DtoConstString(name); initVec.push_back(c); // importedModules[] int aimports_dim = aimports.dim; std::vector importInits; for (size_t i = 0; i < aimports.dim; i++) { Module *m = (Module *)aimports.data[i]; if (!m->needModuleInfo() || m == this) continue; // declare the imported module info std::string m_name("_D"); m_name.append(m->mangle()); m_name.append("8__ModuleZ"); llvm::GlobalVariable* m_gvar = gIR->module->getGlobalVariable(m_name); if (!m_gvar) m_gvar = new llvm::GlobalVariable(moduleinfoTy, false, llvm::GlobalValue::ExternalLinkage, NULL, m_name, gIR->module); importInits.push_back(m_gvar); } // has import array? if (!importInits.empty()) { const llvm::ArrayType* importArrTy = llvm::ArrayType::get(getPtrToType(moduleinfoTy), importInits.size()); c = llvm::ConstantArray::get(importArrTy, importInits); std::string m_name("_D"); m_name.append(mangle()); m_name.append("9__importsZ"); llvm::GlobalVariable* m_gvar = gIR->module->getGlobalVariable(m_name); if (!m_gvar) m_gvar = new llvm::GlobalVariable(importArrTy, true, llvm::GlobalValue::InternalLinkage, c, m_name, gIR->module); c = llvm::ConstantExpr::getBitCast(m_gvar, getPtrToType(importArrTy->getElementType())); c = DtoConstSlice(DtoConstSize_t(importInits.size()), c); } else c = DtoConstSlice( DtoConstSize_t(0), getNullValue(getPtrToType(moduleinfoTy)) ); initVec.push_back(c); // localClasses[] ClassDeclarations aclasses; //printf("members->dim = %d\n", members->dim); for (size_t i = 0; i < members->dim; i++) { Dsymbol *member; member = (Dsymbol *)members->data[i]; //printf("\tmember '%s'\n", member->toChars()); member->addLocalClass(&aclasses); } // fill inits std::vector classInits; for (size_t i = 0; i < aclasses.dim; i++) { ClassDeclaration* cd = (ClassDeclaration*)aclasses.data[i]; if (cd->isInterfaceDeclaration()) { Logger::println("skipping interface '%s' in moduleinfo", cd->toPrettyChars()); continue; } else if (cd->sizeok != 1) { Logger::println("skipping opaque class declaration '%s' in moduleinfo", cd->toPrettyChars()); continue; } Logger::println("class: %s", cd->toPrettyChars()); assert(cd->ir.irStruct->classInfo); c = DtoBitCast(cd->ir.irStruct->classInfo, getPtrToType(classinfoTy)); classInits.push_back(c); } // has class array? if (!classInits.empty()) { const llvm::ArrayType* classArrTy = llvm::ArrayType::get(getPtrToType(classinfoTy), classInits.size()); c = llvm::ConstantArray::get(classArrTy, classInits); std::string m_name("_D"); m_name.append(mangle()); m_name.append("9__classesZ"); assert(gIR->module->getGlobalVariable(m_name) == NULL); llvm::GlobalVariable* m_gvar = new llvm::GlobalVariable(classArrTy, true, llvm::GlobalValue::InternalLinkage, c, m_name, gIR->module); c = DtoBitCast(m_gvar, getPtrToType(classinfoTy)); c = DtoConstSlice(DtoConstSize_t(classInits.size()), c); } else c = DtoConstSlice( DtoConstSize_t(0), getNullValue(getPtrToType(classinfoTy)) ); initVec.push_back(c); // flags c = DtoConstUint(0); if (!needmoduleinfo) c = DtoConstUint(4); // flags (4 means MIstandalone) initVec.push_back(c); // function pointer type for next three fields const LLType* fnptrTy = getPtrToType(LLFunctionType::get(LLType::VoidTy, std::vector(), false)); // ctor llvm::Function* fctor = build_module_ctor(); c = fctor ? fctor : getNullValue(fnptrTy); initVec.push_back(c); // dtor llvm::Function* fdtor = build_module_dtor(); c = fdtor ? fdtor : getNullValue(fnptrTy); initVec.push_back(c); // unitTest llvm::Function* unittest = build_module_unittest(); c = unittest ? unittest : getNullValue(fnptrTy); initVec.push_back(c); // xgetMembers c = getNullValue(getVoidPtrType()); initVec.push_back(c); // ictor c = getNullValue(fnptrTy); initVec.push_back(c); /*Logger::println("MODULE INFO INITIALIZERS"); for (size_t i=0; igetType() != moduleinfoTy->getElementType(i)) assert(0); }*/ // create initializer LLConstant* constMI = llvm::ConstantStruct::get(initVec); // create name std::string MIname("_D"); MIname.append(mangle()); MIname.append("8__ModuleZ"); // declare global // flags will be modified at runtime so can't make it constant // it makes no sense that the our own module info already exists! assert(!gIR->module->getGlobalVariable(MIname)); llvm::GlobalVariable* gvar = new llvm::GlobalVariable(constMI->getType(), false, llvm::GlobalValue::ExternalLinkage, constMI, MIname, gIR->module); // build the modulereference and ctor for registering it LLFunction* mictor = build_module_reference_and_ctor(gvar); // register this ctor in the magic llvm.global_ctors appending array const LLFunctionType* magicfty = LLFunctionType::get(LLType::VoidTy, std::vector(), false); std::vector magictypes; magictypes.push_back(LLType::Int32Ty); magictypes.push_back(getPtrToType(magicfty)); const LLStructType* magicsty = LLStructType::get(magictypes); // make the constant element std::vector magicconstants; magicconstants.push_back(DtoConstUint(65535)); magicconstants.push_back(mictor); LLConstant* magicinit = LLConstantStruct::get(magicsty, magicconstants); // declare the appending array const llvm::ArrayType* appendArrTy = llvm::ArrayType::get(magicsty, 1); std::vector appendInits(1, magicinit); LLConstant* appendInit = llvm::ConstantArray::get(appendArrTy, appendInits); std::string appendName("llvm.global_ctors"); llvm::GlobalVariable* appendVar = new llvm::GlobalVariable(appendArrTy, true, llvm::GlobalValue::AppendingLinkage, appendInit, appendName, gIR->module); } /* ================================================================== */ void Dsymbol::toObjFile(int multiobj) { Logger::println("Ignoring Dsymbol::toObjFile for %s", toChars()); } /* ================================================================== */ void Declaration::toObjFile(int unused) { Logger::println("Ignoring Declaration::toObjFile for %s", toChars()); } /* ================================================================== */ void InterfaceDeclaration::toObjFile(int multiobj) { //Logger::println("Ignoring InterfaceDeclaration::toObjFile for %s", toChars()); gIR->resolveList.push_back(this); } /* ================================================================== */ void StructDeclaration::toObjFile(int multiobj) { gIR->resolveList.push_back(this); } /* ================================================================== */ void ClassDeclaration::toObjFile(int multiobj) { gIR->resolveList.push_back(this); } /****************************************** * Get offset of base class's vtbl[] initializer from start of csym. * Returns ~0 if not this csym. */ unsigned ClassDeclaration::baseVtblOffset(BaseClass *bc) { return ~0; } /* ================================================================== */ void TupleDeclaration::toObjFile(int multiobj) { Logger::println("TupleDeclaration::toObjFile(): %s", toChars()); assert(isexp); assert(objects); int n = objects->dim; for (int i=0; i < n; ++i) { DsymbolExp* exp = (DsymbolExp*)objects->data[i]; assert(exp->op == TOKdsymbol); exp->s->toObjFile(multiobj); } } /* ================================================================== */ void VarDeclaration::toObjFile(int multiobj) { Logger::print("VarDeclaration::toObjFile(): %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; if (aliassym) { Logger::println("alias sym"); toAlias()->toObjFile(multiobj); return; } // global variable or magic if (isDataseg()) { Logger::println("data segment"); #if DMDV2 if (storage_class & STCmanifest) { assert(0 && "manifest constant being codegened!!!"); } #endif // don't duplicate work if (this->ir.resolved) return; this->ir.resolved = true; this->ir.declared = true; this->ir.irGlobal = new IrGlobal(this); Logger::println("parent: %s (%s)", parent->toChars(), parent->kind()); #if DMDV2 // not sure why this is only needed for d2 bool _isconst = isConst() && init; #else bool _isconst = isConst(); #endif Logger::println("Creating global variable"); const LLType* _type = this->ir.irGlobal->type.get(); llvm::GlobalValue::LinkageTypes _linkage = DtoLinkage(this); std::string _name(mangle()); llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_type,_isconst,_linkage,NULL,_name,gIR->module); this->ir.irGlobal->value = gvar; if (Logger::enabled()) Logger::cout() << *gvar << '\n'; // if this global is used from a nested function, this is necessary or // optimization could potentially remove the global (if it's the only use) if (nakedUse) gIR->usedArray.push_back(DtoBitCast(gvar, getVoidPtrType())); gIR->constInitList.push_back(this); } else { // might already have its irField, as classes derive each other without getting copies of the VarDeclaration if (!ir.irField) { assert(!ir.isSet()); ir.irField = new IrField(this); } IrStruct* irstruct = gIR->topstruct(); irstruct->addVar(this); Logger::println("added offset %u", offset); } } /* ================================================================== */ void TypedefDeclaration::toObjFile(int multiobj) { static int tdi = 0; Logger::print("TypedefDeclaration::toObjFile(%d): %s\n", tdi++, toChars()); LOG_SCOPE; // generate typeinfo DtoTypeInfoOf(type, false); } /* ================================================================== */ void EnumDeclaration::toObjFile(int multiobj) { Logger::println("Ignoring EnumDeclaration::toObjFile for %s", toChars()); } /* ================================================================== */ void FuncDeclaration::toObjFile(int multiobj) { gIR->resolveList.push_back(this); } /* ================================================================== */ void AnonDeclaration::toObjFile(int multiobj) { Array *d = include(NULL, NULL); if (d) { // get real aggregate parent IrStruct* irstruct = gIR->topstruct(); // push a block on the stack irstruct->pushAnon(isunion); // go over children for (unsigned i = 0; i < d->dim; i++) { Dsymbol *s = (Dsymbol *)d->data[i]; s->toObjFile(multiobj); } // finish irstruct->popAnon(); } }