Mercurial > projects > ldc
view gen/todebug.cpp @ 650:aa6a0b7968f7
Added test case for bug #100
Removed dubious check for not emitting static private global in other modules without access. This should be handled properly somewhere else, it's causing unresolved global errors for stuff that should work (in MiniD)
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Sun, 05 Oct 2008 17:28:15 +0200 |
parents | 83ca663ecc20 |
children | 6aaa3d3c1183 |
line wrap: on
line source
#include "gen/llvm.h" #include "llvm/Support/Dwarf.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/System/Path.h" #include "declaration.h" #include "module.h" #include "mars.h" #include "gen/todebug.h" #include "gen/irstate.h" #include "gen/tollvm.h" #include "gen/logger.h" #include "ir/irmodule.h" using namespace llvm::dwarf; #define DBG_NULL ( LLConstant::getNullValue(DBG_TYPE) ) #define DBG_TYPE ( getPtrToType(llvm::StructType::get(NULL,NULL)) ) #define DBG_CAST(X) ( llvm::ConstantExpr::getBitCast(X, DBG_TYPE) ) #define DBG_TAG(X) ( llvm::ConstantExpr::getAdd( DtoConstUint( X ), DtoConstUint( llvm::LLVMDebugVersion ) ) ) ////////////////////////////////////////////////////////////////////////////////////////////////// /** * Emits a global variable, LLVM Dwarf style. * @param type Type of variable. * @param values Initializers. * @param name Name. * @return The global variable. */ static LLGlobalVariable* emitDwarfGlobal(const LLStructType* type, const std::vector<LLConstant*> values, const char* name, bool linkonce=false) { LLConstant* c = llvm::ConstantStruct::get(type, values); LLGlobalValue::LinkageTypes linkage = linkonce ? LLGlobalValue::LinkOnceLinkage : LLGlobalValue::InternalLinkage; LLGlobalVariable* gv = new LLGlobalVariable(type, true, linkage, c, name, gIR->module); gv->setSection("llvm.metadata"); return gv; } /** * Emits a global variable, LLVM Dwarf style, only declares. * @param type Type of variable. * @param name Name. * @return The global variable. */ static LLGlobalVariable* emitDwarfGlobalDecl(const LLStructType* type, const char* name, bool linkonce=false) { LLGlobalValue::LinkageTypes linkage = linkonce ? LLGlobalValue::LinkOnceLinkage : LLGlobalValue::InternalLinkage; LLGlobalVariable* gv = new LLGlobalVariable(type, true, linkage, NULL, name, gIR->module); gv->setSection("llvm.metadata"); return gv; } ////////////////////////////////////////////////////////////////////////////////////////////////// /** * Emits the Dwarf anchors that are used repeatedly by LLVM debug info. */ static void emitDwarfAnchors() { const llvm::StructType* anchorTy = isaStruct(gIR->module->getTypeByName("llvm.dbg.anchor.type")); std::vector<LLConstant*> vals(2); vals[0] = DtoConstUint(llvm::LLVMDebugVersion); vals[1] = DtoConstUint(DW_TAG_compile_unit); gIR->dwarfCUs = emitDwarfGlobal(anchorTy, vals, "llvm.dbg.compile_units", true); vals[0] = DtoConstUint(llvm::LLVMDebugVersion); vals[1] = DtoConstUint(DW_TAG_variable); gIR->dwarfGVs = emitDwarfGlobal(anchorTy, vals, "llvm.dbg.global_variables", true); vals[0] = DtoConstUint(llvm::LLVMDebugVersion); vals[1] = DtoConstUint(DW_TAG_subprogram); gIR->dwarfSPs = emitDwarfGlobal(anchorTy, vals, "llvm.dbg.subprograms", true); } ////////////////////////////////////////////////////////////////////////////////////////////////// static LLConstant* getDwarfAnchor(dwarf_constants c) { if (!gIR->dwarfCUs) emitDwarfAnchors(); switch (c) { case DW_TAG_compile_unit: return gIR->dwarfCUs; case DW_TAG_variable: return gIR->dwarfGVs; case DW_TAG_subprogram: return gIR->dwarfSPs; default: assert(0); } } ////////////////////////////////////////////////////////////////////////////////////////////////// static const llvm::StructType* getDwarfCompileUnitType() { return isaStruct(gIR->module->getTypeByName("llvm.dbg.compile_unit.type")); } static const llvm::StructType* getDwarfSubProgramType() { return isaStruct(gIR->module->getTypeByName("llvm.dbg.subprogram.type")); } static const llvm::StructType* getDwarfVariableType() { return isaStruct(gIR->module->getTypeByName("llvm.dbg.variable.type")); } static const llvm::StructType* getDwarfDerivedTypeType() { return isaStruct(gIR->module->getTypeByName("llvm.dbg.derivedtype.type")); } static const llvm::StructType* getDwarfBasicTypeType() { return isaStruct(gIR->module->getTypeByName("llvm.dbg.basictype.type")); } static const llvm::StructType* getDwarfCompositeTypeType() { return isaStruct(gIR->module->getTypeByName("llvm.dbg.compositetype.type")); } static const llvm::StructType* getDwarfGlobalVariableType() { return isaStruct(gIR->module->getTypeByName("llvm.dbg.global_variable.type")); } ////////////////////////////////////////////////////////////////////////////////////////////////// static LLGlobalVariable* dwarfCompileUnit(Module* m) { std::vector<LLConstant*> vals(6); vals[0] = DBG_TAG(DW_TAG_compile_unit); vals[1] = DBG_CAST(getDwarfAnchor(DW_TAG_compile_unit)); vals[2] = DtoConstUint(DW_LANG_C);// _D)); // doesn't seem to work vals[3] = DtoConstStringPtr(m->srcfile->name->toChars(), "llvm.metadata"); std::string srcpath(FileName::path(m->srcfile->name->toChars())); if (srcpath.empty()) srcpath = llvm::sys::Path::GetCurrentDirectory().toString(); vals[4] = DtoConstStringPtr(srcpath.c_str(), "llvm.metadata"); vals[5] = DtoConstStringPtr("LLVMDC (http://www.dsource.org/projects/llvmdc)", "llvm.metadata"); LLGlobalVariable* gv = emitDwarfGlobal(getDwarfCompileUnitType(), vals, "llvm.dbg.compile_unit"); m->ir.irModule->dwarfCompileUnit = gv; return gv; } ////////////////////////////////////////////////////////////////////////////////////////////////// static LLGlobalVariable* dwarfSubProgram(FuncDeclaration* fd, llvm::GlobalVariable* compileUnit) { std::vector<LLConstant*> vals(11); vals[0] = DBG_TAG(DW_TAG_subprogram); vals[1] = DBG_CAST(getDwarfAnchor(DW_TAG_subprogram)); vals[2] = DBG_CAST(compileUnit); vals[3] = DtoConstStringPtr(fd->toPrettyChars(), "llvm.metadata"); vals[4] = vals[3]; vals[5] = DtoConstStringPtr(fd->mangle(), "llvm.metadata"); vals[6] = DBG_CAST( DtoDwarfCompileUnit(fd->getModule()) ); vals[7] = DtoConstUint(fd->loc.linnum); vals[8] = DBG_NULL; vals[9] = DtoConstBool(fd->protection == PROTprivate); vals[10] = DtoConstBool(fd->getModule() == gIR->dmodule); Logger::println("emitting subprogram global"); return emitDwarfGlobal(getDwarfSubProgramType(), vals, "llvm.dbg.subprogram"); } ////////////////////////////////////////////////////////////////////////////////////////////////// static LLGlobalVariable* dwarfTypeDescription_impl(Type* type, LLGlobalVariable* cu, const char* c_name); static LLGlobalVariable* dwarfTypeDescription(Type* type, LLGlobalVariable* cu, const char* c_name); ////////////////////////////////////////////////////////////////////////////////////////////////// static LLGlobalVariable* dwarfBasicType(Type* type, llvm::GlobalVariable* compileUnit) { Type* t = type->toBasetype(); const LLType* T = DtoType(type); std::vector<LLConstant*> vals(10); // tag vals[0] = DBG_TAG(DW_TAG_base_type); // context vals[1] = DBG_CAST(compileUnit); // name vals[2] = DtoConstStringPtr(type->toChars(), "llvm.metadata"); // compile unit where defined vals[3] = DBG_NULL; // line number where defined vals[4] = DtoConstInt(0); // size in bits vals[5] = LLConstantInt::get(LLType::Int64Ty, getTypeBitSize(T), false); // alignment in bits vals[6] = LLConstantInt::get(LLType::Int64Ty, getABITypeAlign(T)*8, false); // offset in bits vals[7] = LLConstantInt::get(LLType::Int64Ty, 0, false); // FIXME: dont know what this is vals[8] = DtoConstUint(0); // dwarf type unsigned id; if (t->isintegral()) { if (type->isunsigned()) id = DW_ATE_unsigned; else id = DW_ATE_signed; } else if (t->isfloating()) { id = DW_ATE_float; } else { assert(0 && "unsupported basictype for debug info"); } vals[9] = DtoConstUint(id); return emitDwarfGlobal(getDwarfBasicTypeType(), vals, "llvm.dbg.basictype"); } ////////////////////////////////////////////////////////////////////////////////////////////////// static LLGlobalVariable* dwarfDerivedType(Type* type, llvm::GlobalVariable* compileUnit) { const LLType* T = DtoType(type); Type* t = type->toBasetype(); // defaults LLConstant* name = getNullPtr(getVoidPtrType()); // find tag unsigned tag; if (t->ty == Tpointer) { tag = DW_TAG_pointer_type; } else { assert(0 && "unsupported derivedtype for debug info"); } std::vector<LLConstant*> vals(10); // tag vals[0] = DBG_TAG(tag); // context vals[1] = DBG_CAST(compileUnit); // name vals[2] = name; // compile unit where defined vals[3] = DBG_NULL; // line number where defined vals[4] = DtoConstInt(0); // size in bits vals[5] = LLConstantInt::get(LLType::Int64Ty, getTypeBitSize(T), false); // alignment in bits vals[6] = LLConstantInt::get(LLType::Int64Ty, getABITypeAlign(T)*8, false); // offset in bits vals[7] = LLConstantInt::get(LLType::Int64Ty, 0, false); // FIXME: dont know what this is vals[8] = DtoConstUint(0); // base type Type* nt = t->nextOf(); LLGlobalVariable* nTD = dwarfTypeDescription_impl(nt, compileUnit, NULL); if (nt->ty == Tvoid || !nTD) vals[9] = DBG_NULL; else vals[9] = DBG_CAST(nTD); return emitDwarfGlobal(getDwarfDerivedTypeType(), vals, "llvm.dbg.derivedtype"); } ////////////////////////////////////////////////////////////////////////////////////////////////// static LLGlobalVariable* dwarfMemberType(unsigned linnum, Type* type, LLGlobalVariable* compileUnit, LLGlobalVariable* definedCU, const char* c_name, unsigned offset) { const LLType* T = DtoType(type); Type* t = type->toBasetype(); // defaults LLConstant* name; if (c_name) name = DtoConstStringPtr(c_name, "llvm.metadata"); else name = getNullPtr(getVoidPtrType()); std::vector<LLConstant*> vals(10); // tag vals[0] = DBG_TAG(DW_TAG_member); // context vals[1] = DBG_CAST(compileUnit); // name vals[2] = name; // compile unit where defined if (definedCU) vals[3] = DBG_CAST(definedCU); else vals[3] = DBG_NULL; // line number where defined vals[4] = DtoConstInt(linnum); // size in bits vals[5] = LLConstantInt::get(LLType::Int64Ty, getTypeBitSize(T), false); // alignment in bits vals[6] = LLConstantInt::get(LLType::Int64Ty, getABITypeAlign(T)*8, false); // offset in bits vals[7] = LLConstantInt::get(LLType::Int64Ty, offset*8, false); // FIXME: dont know what this is vals[8] = DtoConstUint(0); // base type LLGlobalVariable* nTD = dwarfTypeDescription(t, compileUnit, NULL); if (t->ty == Tvoid || !nTD) vals[9] = DBG_NULL; else vals[9] = DBG_CAST(nTD); return emitDwarfGlobal(getDwarfDerivedTypeType(), vals, "llvm.dbg.derivedtype"); } ////////////////////////////////////////////////////////////////////////////////////////////////// static LLGlobalVariable* dwarfCompositeType(Type* type, llvm::GlobalVariable* compileUnit) { const LLType* T = DtoType(type); Type* t = type->toBasetype(); // defaults LLConstant* name = getNullPtr(getVoidPtrType()); LLGlobalVariable* members = NULL; unsigned linnum = 0; LLGlobalVariable* definedCU = NULL; // prepare tag and members unsigned tag; // declare final global variable LLGlobalVariable* gv = NULL; // dynamic array if (t->ty == Tarray) { tag = DW_TAG_structure_type; LLGlobalVariable* len = dwarfMemberType(0, Type::tsize_t, compileUnit, NULL, "length", 0); assert(len); LLGlobalVariable* ptr = dwarfMemberType(0, t->nextOf()->pointerTo(), compileUnit, NULL, "ptr", global.params.is64bit?8:4); assert(ptr); const LLArrayType* at = LLArrayType::get(DBG_TYPE, 2); std::vector<LLConstant*> elems(2); elems[0] = DBG_CAST(len); elems[1] = DBG_CAST(ptr); LLConstant* ca = LLConstantArray::get(at, elems); members = new LLGlobalVariable(ca->getType(), true, LLGlobalValue::InternalLinkage, ca, ".array", gIR->module); members->setSection("llvm.metadata"); name = DtoConstStringPtr(t->toChars(), "llvm.metadata"); } // struct/class else if (t->ty == Tstruct || t->ty == Tclass) { AggregateDeclaration* sd; if (t->ty == Tstruct) { TypeStruct* ts = (TypeStruct*)t; sd = ts->sym; } else { TypeClass* tc = (TypeClass*)t; sd = tc->sym; } assert(sd); IrStruct* ir = sd->ir.irStruct; assert(ir); if (ir->dwarfComposite) return ir->dwarfComposite; // set to handle recursive types properly gv = emitDwarfGlobalDecl(getDwarfCompositeTypeType(), "llvm.dbg.compositetype"); ir->dwarfComposite = gv; tag = DW_TAG_structure_type; name = DtoConstStringPtr(sd->toChars(), "llvm.metadata"); linnum = sd->loc.linnum; definedCU = DtoDwarfCompileUnit(sd->getModule()); std::vector<LLConstant*> elems; elems.reserve(ir->offsets.size()); for (IrStruct::OffsetMap::iterator i=ir->offsets.begin(); i!=ir->offsets.end(); ++i) { unsigned offset = i->first; IrStruct::Offset& o = i->second; LLGlobalVariable* ptr = dwarfMemberType(o.var->loc.linnum, o.var->type, compileUnit, definedCU, o.var->toChars(), offset); elems.push_back(DBG_CAST(ptr)); } const LLArrayType* at = LLArrayType::get(DBG_TYPE, elems.size()); LLConstant* ca = LLConstantArray::get(at, elems); members = new LLGlobalVariable(ca->getType(), true, LLGlobalValue::InternalLinkage, ca, ".array", gIR->module); members->setSection("llvm.metadata"); } // unsupported composite type else { assert(0 && "unsupported compositetype for debug info"); } std::vector<LLConstant*> vals(11); // tag vals[0] = DBG_TAG(tag); // context vals[1] = DBG_CAST(compileUnit); // name vals[2] = name; // compile unit where defined if (definedCU) vals[3] = DBG_CAST(definedCU); else vals[3] = DBG_NULL; // line number where defined vals[4] = DtoConstInt(linnum); // size in bits vals[5] = LLConstantInt::get(LLType::Int64Ty, getTypeBitSize(T), false); // alignment in bits vals[6] = LLConstantInt::get(LLType::Int64Ty, getABITypeAlign(T)*8, false); // offset in bits vals[7] = LLConstantInt::get(LLType::Int64Ty, 0, false); // FIXME: dont know what this is vals[8] = DtoConstUint(0); // FIXME: ditto vals[9] = DBG_NULL; // members array if (members) vals[10] = DBG_CAST(members); else vals[10] = DBG_NULL; // set initializer if (!gv) gv = emitDwarfGlobalDecl(getDwarfCompositeTypeType(), "llvm.dbg.compositetype"); LLConstant* initia = LLConstantStruct::get(getDwarfCompositeTypeType(), vals); gv->setInitializer(initia); return gv; } ////////////////////////////////////////////////////////////////////////////////////////////////// static LLGlobalVariable* dwarfGlobalVariable(LLGlobalVariable* ll, VarDeclaration* vd) { assert(vd->isDataseg()); LLGlobalVariable* compileUnit = DtoDwarfCompileUnit(gIR->dmodule); std::vector<LLConstant*> vals(12); vals[0] = DBG_TAG(DW_TAG_variable); vals[1] = DBG_CAST(getDwarfAnchor(DW_TAG_variable)); vals[2] = DBG_CAST(compileUnit); vals[3] = DtoConstStringPtr(vd->mangle(), "llvm.metadata"); vals[4] = DtoConstStringPtr(vd->toPrettyChars(), "llvm.metadata"); vals[5] = DtoConstStringPtr(vd->toChars(), "llvm.metadata"); vals[6] = DBG_CAST(DtoDwarfCompileUnit(vd->getModule())); vals[7] = DtoConstUint(vd->loc.linnum); LLGlobalVariable* TY = dwarfTypeDescription_impl(vd->type, compileUnit, NULL); vals[8] = TY ? DBG_CAST(TY) : DBG_NULL; vals[9] = DtoConstBool(vd->protection == PROTprivate); vals[10] = DtoConstBool(vd->getModule() == gIR->dmodule); vals[11] = DBG_CAST(ll); return emitDwarfGlobal(getDwarfGlobalVariableType(), vals, "llvm.dbg.global_variable"); } ////////////////////////////////////////////////////////////////////////////////////////////////// static LLGlobalVariable* dwarfVariable(VarDeclaration* vd, LLGlobalVariable* typeDescr) { assert(!vd->isDataseg() && "static variable"); unsigned tag; if (vd->isParameter()) tag = DW_TAG_arg_variable; else tag = DW_TAG_auto_variable; std::vector<LLConstant*> vals(6); // tag vals[0] = DBG_TAG(tag); // context vals[1] = DBG_CAST(gIR->func()->dwarfSubProg); // name vals[2] = DtoConstStringPtr(vd->toChars(), "llvm.metadata"); // compile unit where defined vals[3] = DBG_CAST(DtoDwarfCompileUnit(vd->getModule())); // line number where defined vals[4] = DtoConstUint(vd->loc.linnum); // type descriptor vals[5] = DBG_CAST(typeDescr); return emitDwarfGlobal(getDwarfVariableType(), vals, "llvm.dbg.variable"); } ////////////////////////////////////////////////////////////////////////////////////////////////// static void dwarfDeclare(LLValue* var, LLGlobalVariable* varDescr) { LLSmallVector<LLValue*,2> args(2); args[0] = DtoBitCast(var, DBG_TYPE); args[1] = DBG_CAST(varDescr); gIR->ir->CreateCall(gIR->module->getFunction("llvm.dbg.declare"), args.begin(), args.end()); } ////////////////////////////////////////////////////////////////////////////////////////////////// static LLGlobalVariable* dwarfTypeDescription_impl(Type* type, LLGlobalVariable* cu, const char* c_name) { Type* t = type->toBasetype(); if (t->ty == Tvoid) return NULL; else if (t->isintegral() || t->isfloating()) return dwarfBasicType(type, cu); else if (t->ty == Tpointer) return dwarfDerivedType(type, cu); else if (t->ty == Tarray || t->ty == Tstruct || t->ty == Tclass) return dwarfCompositeType(type, cu); return NULL; } static LLGlobalVariable* dwarfTypeDescription(Type* type, LLGlobalVariable* cu, const char* c_name) { Type* t = type->toBasetype(); if (t->ty == Tclass) return dwarfTypeDescription_impl(type->pointerTo(), cu, c_name); else return dwarfTypeDescription_impl(type, cu, c_name); } ////////////////////////////////////////////////////////////////////////////////////////////////// void DtoDwarfLocalVariable(LLValue* ll, VarDeclaration* vd) { Logger::println("D to dwarf local variable"); LOG_SCOPE; // get compile units LLGlobalVariable* thisCU = DtoDwarfCompileUnit(gIR->dmodule); LLGlobalVariable* varCU = thisCU; if (vd->getModule() != gIR->dmodule) varCU = DtoDwarfCompileUnit(vd->getModule()); // get type description Type* t = vd->type->toBasetype(); LLGlobalVariable* TD = dwarfTypeDescription(vd->type, thisCU, NULL); if (TD == NULL) return; // unsupported // get variable description LLGlobalVariable* VD; VD = dwarfVariable(vd, TD); // declare dwarfDeclare(ll, VD); } ////////////////////////////////////////////////////////////////////////////////////////////////// LLGlobalVariable* DtoDwarfCompileUnit(Module* m) { Logger::println("D to dwarf compile_unit"); LOG_SCOPE; // we might be generating for an import if (!m->ir.irModule) m->ir.irModule = new IrModule(m); else if (m->ir.irModule->dwarfCompileUnit) { if (m->ir.irModule->dwarfCompileUnit->getParent() == gIR->module) return m->ir.irModule->dwarfCompileUnit; } LLGlobalVariable* gv = dwarfCompileUnit(m); m->ir.irModule->dwarfCompileUnit = gv; return gv; } ////////////////////////////////////////////////////////////////////////////////////////////////// LLGlobalVariable* DtoDwarfSubProgram(FuncDeclaration* fd) { Logger::println("D to dwarf subprogram"); LOG_SCOPE; // FIXME: duplicates ? return dwarfSubProgram(fd, DtoDwarfCompileUnit(gIR->dmodule)); } ////////////////////////////////////////////////////////////////////////////////////////////////// LLGlobalVariable* DtoDwarfGlobalVariable(LLGlobalVariable* ll, VarDeclaration* vd) { Logger::println("D to dwarf global_variable"); LOG_SCOPE; // FIXME: duplicates ? return dwarfGlobalVariable(ll, vd); } ////////////////////////////////////////////////////////////////////////////////////////////////// void DtoDwarfFuncStart(FuncDeclaration* fd) { Logger::println("D to dwarf funcstart"); LOG_SCOPE; assert(fd->ir.irFunc->dwarfSubProg); gIR->ir->CreateCall(gIR->module->getFunction("llvm.dbg.func.start"), DBG_CAST(fd->ir.irFunc->dwarfSubProg)); } ////////////////////////////////////////////////////////////////////////////////////////////////// void DtoDwarfFuncEnd(FuncDeclaration* fd) { Logger::println("D to dwarf funcend"); LOG_SCOPE; assert(fd->ir.irFunc->dwarfSubProg); gIR->ir->CreateCall(gIR->module->getFunction("llvm.dbg.region.end"), DBG_CAST(fd->ir.irFunc->dwarfSubProg)); } ////////////////////////////////////////////////////////////////////////////////////////////////// void DtoDwarfStopPoint(unsigned ln) { Logger::println("D to dwarf stoppoint at line %u", ln); LOG_SCOPE; LLSmallVector<LLValue*,3> args(3); args[0] = DtoConstUint(ln); args[1] = DtoConstUint(0); FuncDeclaration* fd = gIR->func()->decl; args[2] = DBG_CAST(DtoDwarfCompileUnit(fd->getModule())); gIR->ir->CreateCall(gIR->module->getFunction("llvm.dbg.stoppoint"), args.begin(), args.end()); }