From 6ed3ce435845e72ce8c88d39c0f7d3fb950ef54e Mon Sep 17 00:00:00 2001 From: Johan Engelen Date: Mon, 18 Sep 2017 23:11:32 +0200 Subject: [PATCH] Backport PR #2315. The change is to fix debuginfo build errors with Phobos and LLVM5.0. This PR is mostly copy-pasting from master and fixing compile errors, so not much checking whether things make sense or not for LTS. --- gen/dibuilder.cpp | 104 ++++++++++++++++++++++++++++++++++++++++++++---------- gen/dibuilder.h | 13 +++++-- gen/functions.cpp | 11 +++--- gen/nested.cpp | 103 ++++++++++++++++++++++++++++------------------------- 4 files changed, 159 insertions(+), 72 deletions(-) diff --git a/gen/dibuilder.cpp b/gen/dibuilder.cpp index f322811ea..1bc9c47c2 100644 --- a/gen/dibuilder.cpp +++ b/gen/dibuilder.cpp @@ -62,7 +62,9 @@ Module *ldc::DIBuilder::getDefinedModule(Dsymbol *s) { //////////////////////////////////////////////////////////////////////////////// ldc::DIBuilder::DIBuilder(IRState *const IR) - : IR(IR), DBuilder(IR->module), CUNode(nullptr) {} + : IR(IR), DBuilder(IR->module), CUNode(nullptr), + isTargetMSVCx64(global.params.targetTriple.isWindowsMSVCEnvironment() && + global.params.targetTriple.isArch64Bit()) {} llvm::LLVMContext &ldc::DIBuilder::getContext() { return IR->context(); } @@ -75,7 +77,7 @@ ldc::DIScope ldc::DIBuilder::GetCurrentScope() { return fn->diLexicalBlocks.top(); } -void ldc::DIBuilder::Declare(const Loc &loc, llvm::Value *var, +void ldc::DIBuilder::Declare(const Loc &loc, llvm::Value *storage, ldc::DILocalVariable divar #if LDC_LLVM_VER >= 306 , @@ -83,19 +85,42 @@ void ldc::DIBuilder::Declare(const Loc &loc, llvm::Value *var, #endif ) { unsigned charnum = (loc.linnum ? loc.charnum : 0); + auto debugLoc = llvm::DebugLoc::get(loc.linnum, charnum, GetCurrentScope()); #if LDC_LLVM_VER < 307 - llvm::Instruction *instr = DBuilder.insertDeclare(var, divar, + llvm::Instruction *instr = DBuilder.insertDeclare(storage, divar, #if LDC_LLVM_VER >= 306 diexpr, #endif IR->scopebb()); - instr->setDebugLoc( - llvm::DebugLoc::get(loc.linnum, charnum, GetCurrentScope())); + instr->setDebugLoc(debugLoc); +#else // if LLVM >= 3.7 + DBuilder.insertDeclare(storage, divar, diexpr, debugLoc, IR->scopebb()); +#endif +} + +// Sets the (current) value for a debuginfo variable. +void ldc::DIBuilder::SetValue(const Loc &loc, llvm::Value *value, + ldc::DILocalVariable divar +#if LDC_LLVM_VER >= 306 + , + ldc::DIExpression diexpr +#endif + ) { + unsigned charnum = (loc.linnum ? loc.charnum : 0); + auto debugLoc = llvm::DebugLoc::get(loc.linnum, charnum, GetCurrentScope()); +#if LDC_LLVM_VER < 307 + llvm::Instruction *instr = DBuilder.insertDbgValueIntrinsic(value, divar, +#if LDC_LLVM_VER >= 306 + diexpr, +#endif + IR->scopebb()); + instr->setDebugLoc(debugLoc); #else // if LLVM >= 3.7 - DBuilder.insertDeclare( - var, divar, diexpr, - llvm::DebugLoc::get(loc.linnum, charnum, GetCurrentScope()), - IR->scopebb()); + DBuilder.insertDbgValueIntrinsic(value, +#if LDC_LLVM_VER < 600 + 0, +#endif + divar, diexpr, debugLoc, IR->scopebb()); #endif } @@ -852,6 +877,7 @@ void ldc::DIBuilder::EmitValue(llvm::Value *val, VarDeclaration *vd) { void ldc::DIBuilder::EmitLocalVariable(llvm::Value *ll, VarDeclaration *vd, Type *type, bool isThisPtr, + bool forceAsLocal, bool isRefRVal, #if LDC_LLVM_VER >= 306 llvm::ArrayRef addr #else @@ -872,13 +898,46 @@ void ldc::DIBuilder::EmitLocalVariable(llvm::Value *ll, VarDeclaration *vd, } // get type description - ldc::DIType TD = CreateTypeDescription(type ? type : vd->type, true); + if (!type) + type = vd->type; + ldc::DIType TD = CreateTypeDescription(type, true); if (static_cast(TD) == nullptr) { return; // unsupported } - if (vd->storage_class & (STCref | STCout)) { + const bool isRefOrOut = vd->isRef() || vd->isOut(); // incl. special-ref vars + + // For MSVC x64 targets, declare params rewritten by ExplicitByvalRewrite as + // DI references, as if they were ref parameters. + const bool isPassedExplicitlyByval = + isTargetMSVCx64 && !isRefOrOut && isaArgument(ll) && addr.empty(); + + bool useDbgValueIntrinsic = false; + if (isRefOrOut || isPassedExplicitlyByval) { + // With the exception of special-ref loop variables, the reference/pointer + // itself is constant. So we don't have to attach the debug information to a + // memory location and can use llvm.dbg.value to set the constant pointer + // for the DI reference. + useDbgValueIntrinsic = + isPassedExplicitlyByval || (!isSpecialRefVar(vd) && isRefRVal); +#if LDC_LLVM_VER >= 308 + // Note: createReferenceType expects the size to be the size of a pointer, + // not the size of the type the reference refers to. + TD = DBuilder.createReferenceType( + llvm::dwarf::DW_TAG_reference_type, TD, + gDataLayout->getPointerSizeInBits(), // size (bits) + DtoAlignment(type) * 8); // align (bits) +#else TD = DBuilder.createReferenceType(llvm::dwarf::DW_TAG_reference_type, TD); +#endif + } else { + // FIXME: For MSVC x64 targets, declare dynamic array and vector parameters + // as DI locals to work around garbage for both cdb and VS debuggers. + if (isTargetMSVCx64) { + TY ty = type->toBasetype()->ty; + if (ty == Tarray || ty == Tvector) + forceAsLocal = true; + } } // get variable description @@ -886,7 +945,7 @@ void ldc::DIBuilder::EmitLocalVariable(llvm::Value *ll, VarDeclaration *vd, #if LDC_LLVM_VER < 308 unsigned tag; - if (vd->isParameter()) { + if (!forceAsLocal && vd->isParameter()) { tag = llvm::dwarf::DW_TAG_arg_variable; } else { tag = llvm::dwarf::DW_TAG_auto_variable; @@ -930,7 +989,7 @@ void ldc::DIBuilder::EmitLocalVariable(llvm::Value *ll, VarDeclaration *vd, Flags // flags ); #else - if (vd->isParameter()) { + if (!forceAsLocal && vd->isParameter()) { FuncDeclaration *fd = vd->parent->isFuncDeclaration(); assert(fd); size_t argNo = 0; @@ -970,14 +1029,23 @@ void ldc::DIBuilder::EmitLocalVariable(llvm::Value *ll, VarDeclaration *vd, #endif variableMap[vd] = debugVariable; -// declare + if (useDbgValueIntrinsic) { #if LDC_LLVM_VER >= 306 - Declare(vd->loc, ll, debugVariable, addr.empty() - ? DBuilder.createExpression() - : DBuilder.createExpression(addr)); + SetValue(vd->loc, ll, debugVariable, + addr.empty() ? DBuilder.createExpression() + : DBuilder.createExpression(addr)); #else - Declare(vd->loc, ll, debugVariable); + SetValue(vd->loc, ll, debugVariable); #endif + } else { +#if LDC_LLVM_VER >= 306 + Declare(vd->loc, ll, debugVariable, + addr.empty() ? DBuilder.createExpression() + : DBuilder.createExpression(addr)); +#else + Declare(vd->loc, ll, debugVariable); +#endif + } } void diff --git a/gen/dibuilder.h b/gen/dibuilder.h index fbfa830da..8fc5dea6c 100644 --- a/gen/dibuilder.h +++ b/gen/dibuilder.h @@ -79,6 +79,8 @@ class DIBuilder { const llvm::MDNode *CUNode; #endif + const bool isTargetMSVCx64; + DICompileUnit GetCU() { #if LDC_LLVM_VER >= 307 return CUNode; @@ -133,7 +135,8 @@ class DIBuilder { /// \param addr An array of complex address operations. void EmitLocalVariable(llvm::Value *ll, VarDeclaration *vd, Type *type = nullptr, - bool isThisPtr = false, + bool isThisPtr = false, bool forceAsLocal = false, + bool isRefRVal = false, #if LDC_LLVM_VER >= 306 llvm::ArrayRef addr = llvm::ArrayRef() #else @@ -155,12 +158,18 @@ class DIBuilder { llvm::LLVMContext &getContext(); Module *getDefinedModule(Dsymbol *s); DIScope GetCurrentScope(); - void Declare(const Loc &loc, llvm::Value *var, ldc::DILocalVariable divar + void Declare(const Loc &loc, llvm::Value *storage, ldc::DILocalVariable divar #if LDC_LLVM_VER >= 306 , ldc::DIExpression diexpr #endif ); + void SetValue(const Loc &loc, llvm::Value *value, ldc::DILocalVariable divar +#if LDC_LLVM_VER >= 306 + , + ldc::DIExpression diexpr +#endif + ); void AddBaseFields(ClassDeclaration *sd, ldc::DIFile file, #if LDC_LLVM_VER >= 306 std::vector &elems diff --git a/gen/functions.cpp b/gen/functions.cpp index 796124db4..107779ecd 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -861,10 +861,13 @@ void DtoDefineFunction(FuncDeclaration *fd) { ++llArgIdx; } - if (global.params.symdebug && - !(isaArgument(irparam->value) && - isaArgument(irparam->value)->hasByValAttr())) { - gIR->DBuilder.EmitLocalVariable(irparam->value, vd, debugInfoType); + // The debuginfos for captured params are handled later by + // DtoCreateNestedContext(). + if (global.params.symdebug && vd->nestedrefs.dim == 0) { + // Reference (ref/out) parameters have no storage themselves as they are + // constant pointers, so pass the reference rvalue to EmitLocalVariable(). + gIR->DBuilder.EmitLocalVariable(irparam->value, vd, debugInfoType, + false, false, /*isRefRVal=*/true); } } } diff --git a/gen/nested.cpp b/gen/nested.cpp index 2a13a1aa6..2b72f9873 100644 --- a/gen/nested.cpp +++ b/gen/nested.cpp @@ -58,14 +58,13 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd, // Check whether we can access the needed frame FuncDeclaration *fd = irfunc->decl; - while (fd != vdparent) { - if (fd->isStatic()) { - error(loc, "function %s cannot access frame of function %s", - irfunc->decl->toPrettyChars(), vdparent->toPrettyChars()); - return new DVarValue(astype, llvm::UndefValue::get(DtoPtrToType(astype))); - } + while (fd && fd != vdparent) { fd = getParentFunc(fd, false); - assert(fd); + } + if (!fd) { + error(loc, "function %s cannot access frame of function %s", + irfunc->decl->toPrettyChars(), vdparent->toPrettyChars()); + return new DVarValue(astype, llvm::UndefValue::get(DtoPtrToType(astype))); } // is the nested variable in this scope? @@ -73,38 +72,32 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd, return makeVarDValue(astype, vd); } - LLValue *dwarfValue = nullptr; -#if LDC_LLVM_VER >= 306 - std::vector dwarfAddr; -#else - std::vector dwarfAddr; -#endif - // get the nested context LLValue *ctx = nullptr; - if (irfunc->nestedVar) { - // If this function has its own nested context struct, always load it. - ctx = irfunc->nestedVar; - dwarfValue = ctx; + bool skipDIDeclaration = false; + auto currentCtx = irfunc->nestedVar; + if (currentCtx) { + Logger::println("Using own nested context of current function"); + ctx = currentCtx; } else if (irfunc->decl->isMember2()) { - // If this is a member function of a nested class without its own - // context, load the vthis member. + Logger::println( + "Current function is member of nested class, loading vthis"); + AggregateDeclaration *cd = irfunc->decl->isMember2(); LLValue *val = irfunc->thisArg; if (cd->isClassDeclaration()) { val = DtoLoad(val); } ctx = DtoLoad(DtoGEPi(val, 0, getVthisIdx(cd), ".vthis")); + skipDIDeclaration = true; } else { - // Otherwise, this is a simple nested function, load from the context - // argument. + Logger::println("Regular nested function, loading context arg"); + ctx = DtoLoad(irfunc->nestArg); - dwarfValue = irfunc->nestArg; - if (global.params.symdebug) { - gIR->DBuilder.OpDeref(dwarfAddr); - } } + assert(ctx); + IF_LOG { Logger::cout() << "Context: " << *ctx << '\n'; } DtoCreateNestedContextType(vdparent->isFuncDeclaration()); assert(isIrLocalCreated(vd)); @@ -112,11 +105,9 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd, //////////////////////////////////// // Extract variable from nested context - LLValue *val = DtoBitCast(ctx, LLPointerType::getUnqual(irfunc->frameType)); - IF_LOG { - Logger::cout() << "Context: " << *val << '\n'; - Logger::cout() << "of type: " << *irfunc->frameType << '\n'; - } + const auto frameType = LLPointerType::getUnqual(irfunc->frameType); + IF_LOG { Logger::cout() << "casting to: " << *irfunc->frameType << '\n'; } + LLValue *val = DtoBitCast(ctx, frameType); IrLocal *const irLocal = getIrLocal(vd); const auto vardepth = irLocal->nestedDepth; @@ -135,10 +126,6 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd, IF_LOG Logger::println("Same depth"); } else { // Load frame pointer and index that... - if (dwarfValue && global.params.symdebug) { - gIR->DBuilder.OpOffset(dwarfAddr, val, vardepth); - gIR->DBuilder.OpDeref(dwarfAddr); - } IF_LOG Logger::println("Lower depth"); val = DtoGEPi(val, 0, vardepth); IF_LOG Logger::cout() << "Frame index: " << *val << '\n'; @@ -150,27 +137,42 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd, const auto idx = irLocal->nestedIndex; assert(idx != -1 && "Nested context not yet resolved for variable."); - if (dwarfValue && global.params.symdebug) { - gIR->DBuilder.OpOffset(dwarfAddr, val, idx); - } +#if LDC_LLVM_VER >= 306 + std::vector dwarfAddrOps; +#else + std::vector dwarfAddrOps; +#endif - val = DtoGEPi(val, 0, idx, vd->toChars()); + LLValue *gep = DtoGEPi(val, 0, idx, vd->toChars()); + val = gep; IF_LOG { Logger::cout() << "Addr: " << *val << '\n'; Logger::cout() << "of type: " << *val->getType() << '\n'; } - if (byref || (vd->isParameter() && getIrParameter(vd)->arg && - getIrParameter(vd)->arg->byref)) { + const bool isRefOrOut = vd->isRef() || vd->isOut(); + if (isSpecialRefVar(vd)) { + // Handled appropriately by makeVarDValue() and EmitLocalVariable(), pass + // storage of pointer (reference lvalue). + } else if (byref || isRefOrOut) { val = DtoAlignedLoad(val); - // dwarfOpDeref(dwarfAddr); + // ref/out variables get a reference-debuginfo-type in EmitLocalVariable(); + // pass the GEP as reference lvalue in that case. + if (!isRefOrOut) + gIR->DBuilder.OpDeref(dwarfAddrOps); IF_LOG { Logger::cout() << "Was byref, now: " << *irLocal->value << '\n'; Logger::cout() << "of type: " << *irLocal->value->getType() << '\n'; } } - if (dwarfValue && global.params.symdebug) { - gIR->DBuilder.EmitLocalVariable(dwarfValue, vd, nullptr, false, dwarfAddr); + if (!skipDIDeclaration && global.params.symdebug) { +#if LDC_LLVM_VER < 500 + // Because we are passing a GEP instead of an alloca to + // llvm.dbg.declare, we have to make the address dereference explicit. + gIR->DBuilder.OpDeref(dwarfAddrOps); +#endif + gIR->DBuilder.EmitLocalVariable(gep, vd, nullptr, false, + /*forceAsLocal=*/true, false, dwarfAddrOps); } return makeVarDValue(astype, vd, val); @@ -532,12 +534,17 @@ void DtoCreateNestedContext(FuncDeclaration *fd) { if (global.params.symdebug) { #if LDC_LLVM_VER >= 306 - LLSmallVector addr; + LLSmallVector dwarfAddrOps; #else - LLSmallVector addr; + LLSmallVector dwarfAddrOps; +#endif +#if LDC_LLVM_VER < 500 + // Because we are passing a GEP instead of an alloca to + // llvm.dbg.declare, we have to make the address dereference explicit. + gIR->DBuilder.OpDeref(dwarfAddrOps); #endif - gIR->DBuilder.OpOffset(addr, frameType, irLocal->nestedIndex); - gIR->DBuilder.EmitLocalVariable(gep, vd, nullptr, false, addr); + gIR->DBuilder.EmitLocalVariable(gep, vd, nullptr, false, false, false, + dwarfAddrOps); } } }