diff --git a/gen/dibuilder.cpp b/gen/dibuilder.cpp index ab2e1dccf8..fee76581cb 100644 --- a/gen/dibuilder.cpp +++ b/gen/dibuilder.cpp @@ -650,7 +650,7 @@ ldc::DISubprogram ldc::DIBuilder::EmitSubProgram(FuncDeclaration *fd) { CreateFunctionType(static_cast(fd->type)); // FIXME: duplicates? - return DBuilder.createFunction( + auto SP = DBuilder.createFunction( CU, // context fd->toPrettyChars(), // name getIrFunc(fd)->func->getName(), // linkage name @@ -667,6 +667,12 @@ ldc::DISubprogram ldc::DIBuilder::EmitSubProgram(FuncDeclaration *fd) { getIrFunc(fd)->func #endif ); +#if LDC_LLVM_VER >= 308 + if (fd->fbody) { + getIrFunc(fd)->func->setSubprogram(SP); + } +#endif + return SP; } ldc::DISubprogram ldc::DIBuilder::EmitThunk(llvm::Function *Thunk, @@ -695,7 +701,7 @@ ldc::DISubprogram ldc::DIBuilder::EmitThunk(llvm::Function *Thunk, name.append(".__thunk"); // FIXME: duplicates? - return DBuilder.createFunction( + auto SP = DBuilder.createFunction( CU, // context name, // name Thunk->getName(), // linkage name @@ -712,6 +718,12 @@ ldc::DISubprogram ldc::DIBuilder::EmitThunk(llvm::Function *Thunk, getIrFunc(fd)->func #endif ); +#if LDC_LLVM_VER >= 308 + if (fd->fbody) { + getIrFunc(fd)->func->setSubprogram(SP); + } +#endif + return SP; } ldc::DISubprogram ldc::DIBuilder::EmitModuleCTor(llvm::Function *Fn, @@ -756,7 +768,7 @@ ldc::DISubprogram ldc::DIBuilder::EmitModuleCTor(llvm::Function *Fn, #endif // FIXME: duplicates? - return DBuilder.createFunction( + auto SP = DBuilder.createFunction( CU, // context prettyname, // name Fn->getName(), // linkage name @@ -773,6 +785,10 @@ ldc::DISubprogram ldc::DIBuilder::EmitModuleCTor(llvm::Function *Fn, Fn #endif ); +#if LDC_LLVM_VER >= 308 + Fn->setSubprogram(SP); +#endif + return SP; } void ldc::DIBuilder::EmitFuncStart(FuncDeclaration *fd) { @@ -858,6 +874,11 @@ void ldc::DIBuilder::EmitStopPoint(Loc &loc) { LOG_SCOPE; IR->ir->SetCurrentDebugLocation( llvm::DebugLoc::get(loc.linnum, charnum, GetCurrentScope())); + currentLoc = loc; +} + +Loc ldc::DIBuilder::GetCurrentLoc() const { + return currentLoc; } void ldc::DIBuilder::EmitValue(llvm::Value *val, VarDeclaration *vd) { @@ -884,7 +905,7 @@ void ldc::DIBuilder::EmitValue(llvm::Value *val, VarDeclaration *vd) { } void ldc::DIBuilder::EmitLocalVariable(llvm::Value *ll, VarDeclaration *vd, - Type *type, bool isThisPtr, + Type *type, bool isThisPtr, bool fromNested, #if LDC_LLVM_VER >= 306 llvm::ArrayRef addr #else @@ -919,7 +940,7 @@ void ldc::DIBuilder::EmitLocalVariable(llvm::Value *ll, VarDeclaration *vd, #if LDC_LLVM_VER < 308 unsigned tag; - if (vd->isParameter()) { + if (!fromNested && vd->isParameter()) { tag = llvm::dwarf::DW_TAG_arg_variable; } else { tag = llvm::dwarf::DW_TAG_auto_variable; @@ -963,7 +984,7 @@ void ldc::DIBuilder::EmitLocalVariable(llvm::Value *ll, VarDeclaration *vd, Flags // flags ); #else - if (vd->isParameter()) { + if (!fromNested && vd->isParameter()) { FuncDeclaration *fd = vd->parent->isFuncDeclaration(); assert(fd); size_t argNo = 0; diff --git a/gen/dibuilder.h b/gen/dibuilder.h index 73d27d3e60..2285c13186 100644 --- a/gen/dibuilder.h +++ b/gen/dibuilder.h @@ -87,6 +87,8 @@ class DIBuilder { #endif } + Loc currentLoc; + public: explicit DIBuilder(IRState *const IR); @@ -127,6 +129,8 @@ public: /// \brief Emits debug info for block end void EmitBlockEnd(); + Loc GetCurrentLoc() const; + void EmitStopPoint(Loc &loc); void EmitValue(llvm::Value *val, VarDeclaration *vd); @@ -137,10 +141,11 @@ public: /// \param vd Variable declaration to emit debug info for. /// \param type Type of parameter if diferent from vd->type /// \param isThisPtr Parameter is hidden this pointer + /// \param fromNested Is a closure variable accessed through nest_arg /// \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 fromNested = false, #if LDC_LLVM_VER >= 306 llvm::ArrayRef addr = llvm::ArrayRef() #else diff --git a/gen/nested.cpp b/gen/nested.cpp index 688e51ef1b..2076c7d600 100644 --- a/gen/nested.cpp +++ b/gen/nested.cpp @@ -154,7 +154,7 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd, } if (dwarfValue && global.params.symdebug) { - gIR->DBuilder.EmitLocalVariable(dwarfValue, vd, nullptr, false, dwarfAddr); + gIR->DBuilder.EmitLocalVariable(dwarfValue, vd, nullptr, false, /*fromNested=*/ true, dwarfAddr); } return makeVarDValue(astype, vd, val); @@ -508,7 +508,7 @@ void DtoCreateNestedContext(FuncDeclaration *fd) { LLSmallVector addr; #endif gIR->DBuilder.OpOffset(addr, frameType, irLocal->nestedIndex); - gIR->DBuilder.EmitLocalVariable(gep, vd, nullptr, false, addr); + gIR->DBuilder.EmitLocalVariable(frame, vd, nullptr, false, false, addr); } } } diff --git a/gen/statements.cpp b/gen/statements.cpp index f5a64c76a1..1ca740b19d 100644 --- a/gen/statements.cpp +++ b/gen/statements.cpp @@ -837,6 +837,8 @@ public: exnObj = DtoAlloca(var->type, "exnObj"); } irs->scope() = save; + irs->DBuilder.EmitStopPoint(ctch->loc); // re-set debug loc after the + // SetInsertPoint(allocaInst) call } else if (ctch->type) { // catch without var exnObj = DtoAlloca(ctch->type, "exnObj"); diff --git a/ir/irfunction.cpp b/ir/irfunction.cpp index ed9e929a47..4fb4c0a787 100644 --- a/ir/irfunction.cpp +++ b/ir/irfunction.cpp @@ -283,21 +283,30 @@ llvm::BasicBlock *ScopeStack::runCleanupPad(CleanupCursor scope, // can place an exception frame (but not done here) auto frame = getNullPtr(getVoidPtrType()); + auto savedInsertBlock = irs->ir->GetInsertBlock(); + auto savedInsertPoint = irs->ir->GetInsertPoint(); + auto savedDbgLoc = irs->DBuilder.GetCurrentLoc(); + auto endFn = getRuntimeFunction(Loc(), irs->module, "_d_leave_cleanup"); - llvm::CallInst::Create(endFn, frame, - {llvm::OperandBundleDef("funclet", cleanuppad)}, "", - cleanupret); + irs->ir->SetInsertPoint(cleanupret); + irs->DBuilder.EmitStopPoint(irs->func()->decl->loc); + irs->ir->CreateCall(endFn, frame, + {llvm::OperandBundleDef("funclet", cleanuppad)}, ""); llvm::CleanupReturnInst::Create(cleanuppad, unwindTo, cleanupret); auto copybb = executeCleanupCopying(irs, cleanupScopes[scope], cleanupbb, cleanupret, unwindTo, cleanuppad); auto beginFn = getRuntimeFunction(Loc(), irs->module, "_d_enter_cleanup"); - auto exec = llvm::CallInst::Create( - beginFn, frame, {llvm::OperandBundleDef("funclet", cleanuppad)}, "", - cleanupbb); + irs->ir->SetInsertPoint(cleanupbb); + irs->DBuilder.EmitStopPoint(irs->func()->decl->loc); + auto exec = irs->ir->CreateCall( + beginFn, frame, {llvm::OperandBundleDef("funclet", cleanuppad)}, ""); llvm::BranchInst::Create(copybb, cleanupret, exec, cleanupbb); + irs->ir->SetInsertPoint(savedInsertBlock, savedInsertPoint); + irs->DBuilder.EmitStopPoint(savedDbgLoc); + return cleanupbb; } #endif diff --git a/tests/debuginfo/msvc_eh.d b/tests/debuginfo/msvc_eh.d new file mode 100755 index 0000000000..8de87a6cb4 --- /dev/null +++ b/tests/debuginfo/msvc_eh.d @@ -0,0 +1,34 @@ +// Checks that !dbg is being attached to MSVC EH/cleanup runtime calls. +// REQUIRES: atleast_llvm308 +// REQUIRES: Windows +// RUN: %ldc -g -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll + +struct WithDtor +{ + int z; + ~this() { z = -1; } +} + +void throwSome() +{ + throw new Exception("!"); +} + +// CHECK: define {{.*}} @{{.*}}foo_msvc +// CHECK-SAME: !dbg +void foo_msvc() +{ + try + { + WithDtor swd_1; + swd_1.z = 24; + throwSome(); + } + catch(Throwable t) + { + WithDtor swd_2 = { 48 }; + } + // CHECK-DAG: call {{.*}}@_d_eh_enter_catch{{.*}} !dbg + // CHECK-DAG: call {{.*}}@_d_enter_cleanup{{.*}} !dbg + // CHECK-DAG: call {{.*}}@_d_leave_cleanup{{.*}} !dbg +} diff --git a/tests/debuginfo/nested.d b/tests/debuginfo/nested.d new file mode 100644 index 0000000000..d601941e3d --- /dev/null +++ b/tests/debuginfo/nested.d @@ -0,0 +1,28 @@ +// Tests debug info generation for nested functions +// REQUIRES: atleast_llvm308 +// RUN: %ldc -g -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll + +// CHECK: define {{.*}} @{{.*}}encloser +// CHECK-SAME: !dbg +void encloser(int arg0, int arg1) +{ + // CHECK: @llvm.dbg.declare{{.*}}%.frame{{.*}}enc_n + int enc_n; + + // CHECK-LABEL: define {{.*}}encloser{{.*}}nested + void nested(int nes_i) + { + // CHECK: @llvm.dbg.declare{{.*}}%nestedFrame{{.*}}arg1 + arg0 = arg1 = enc_n = nes_i; // accessing arg0, arg1 and enc_n from a nested function turns them into closure variables + + // nes_i and arg1 have the same parameter index in the generated IR, if both get declared as + // function parameters this triggers off an assert in LLVM >=3.8 (see Github PR #1598) + } +} + +// CHECK-LABEL: !DISubprogram(name:{{.*}}"{{.*}}encloser.nested" +// CHECK: !DILocalVariable{{.*}}nes_i +// CHECK-SAME: arg: 2 +// CHECK: !DILocalVariable{{.*}}arg1 +// CHECK-NOT: arg: +// CHECK-SAME: ){{$}} diff --git a/tests/debuginfo/nested_llvm306.d b/tests/debuginfo/nested_llvm306.d new file mode 100644 index 0000000000..063c54ef51 --- /dev/null +++ b/tests/debuginfo/nested_llvm306.d @@ -0,0 +1,22 @@ +// Tests debug info generation for nested functions +// REQUIRES: atmost_llvm306 +// RUN: %ldc -g -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll + +// CHECK-LABEL: define {{.*}} @_D{{.*}}8encloserFiiZv +void encloser(int arg0, int arg1) +{ + // CHECK: @llvm.dbg.declare{{.*}}%.frame{{.*}}enc_n + int enc_n; + + // CHECK-LABEL: define {{.*}} @_D{{.*}}encloser{{.*}}nested + void nested(int nes_i) + { + // CHECK: @llvm.dbg.declare{{.*}}%nestedFrame{{.*}}arg1 + arg0 = arg1 = enc_n = nes_i; // accessing arg0, arg1 and enc_n from a nested function turns them into closure variables + } +} + +// CHECK: @_D{{.*}}8encloserFiiZv{{.*}}DW_TAG_subprogram +// CHECK: @_D{{.*}}8encloserFiiZ6nestedMFiZv{{.*}}DW_TAG_subprogram +// CHECK: nes_i{{.*}}DW_TAG_arg_variable +// CHECK: arg1{{.*}}DW_TAG_auto_variable diff --git a/tests/debuginfo/nested_llvm307.d b/tests/debuginfo/nested_llvm307.d new file mode 100644 index 0000000000..3a3b5b16a4 --- /dev/null +++ b/tests/debuginfo/nested_llvm307.d @@ -0,0 +1,23 @@ +// Tests debug info generation for nested functions +// REQUIRES: llvm307 +// RUN: %ldc -g -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll + +// CHECK-LABEL: define {{.*}} @_D{{.*}}8encloser +void encloser(int arg0, int arg1) +{ + // CHECK: @llvm.dbg.declare{{.*}}%.frame{{.*}}enc_n + int enc_n; + + // CHECK-LABEL: define {{.*}} @_D{{.*}}8encloser{{.*}}nested + void nested(int nes_i) + { + // CHECK: @llvm.dbg.declare{{.*}}%nestedFrame{{.*}}arg1 + arg0 = arg1 = enc_n = nes_i; // accessing arg0, arg1 and enc_n from a nested function turns them into closure variables + } +} + +// CHECK: !DISubprogram(name:{{.*}}"{{.*}}.encloser" +// CHECK-SAME: function: void {{.*}} @_D{{.*}}8encloserFiiZv +// CHECK-LABEL: !DISubprogram(name:{{.*}}"{{.*}}.encloser.nested" +// CHECK: !DILocalVariable{{.*}}DW_TAG_arg_variable{{.*}}nes_i +// CHECK: !DILocalVariable{{.*}}DW_TAG_auto_variable{{.*}}arg1 diff --git a/tests/lit.site.cfg.in b/tests/lit.site.cfg.in index 68ba1ca646..d89befa850 100644 --- a/tests/lit.site.cfg.in +++ b/tests/lit.site.cfg.in @@ -43,6 +43,8 @@ if not config.with_PGO: config.available_features.add("llvm%d" % config.llvm_version) for version in range(305, config.llvm_version+1): config.available_features.add("atleast_llvm%d" % version) +for version in range(config.llvm_version, 310): + config.available_features.add("atmost_llvm%d" % version) # Define OS as available feature (Windows, Darwin, Linux) config.available_features.add(platform.system())