diff --git a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h index 1b094d9d9fe77..5454df02914af 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h @@ -204,6 +204,27 @@ class IRTranslator : public MachineFunctionPass { /// \return true if the materialization succeeded. bool translate(const Constant &C, Register Reg); + /// Examine any debug-info attached to the instruction (in the form of + /// DPValues) and translate it. + void translateDbgInfo(const Instruction &Inst, + MachineIRBuilder &MIRBuilder); + + /// Translate a debug-info record of a dbg.value into a DBG_* instruction. + /// Pass in all the contents of the record, rather than relying on how it's + /// stored. + void translateDbgValueRecord(Value *V, bool HasArgList, + const DILocalVariable *Variable, + const DIExpression *Expression, const DebugLoc &DL, + MachineIRBuilder &MIRBuilder); + + /// Translate a debug-info record of a dbg.declare into an indirect DBG_* + /// instruction. Pass in all the contents of the record, rather than relying + /// on how it's stored. + void translateDbgDeclareRecord(Value *Address, bool HasArgList, + const DILocalVariable *Variable, + const DIExpression *Expression, const DebugLoc &DL, + MachineIRBuilder &MIRBuilder); + // Translate U as a copy of V. bool translateCopy(const User &U, const Value &V, MachineIRBuilder &MIRBuilder); @@ -250,14 +271,14 @@ class IRTranslator : public MachineFunctionPass { /// possible. std::optional getArgPhysReg(Argument &Arg); - /// If DebugInst targets an Argument and its expression is an EntryValue, - /// lower it as an entry in the MF debug table. - bool translateIfEntryValueArgument(const DbgDeclareInst &DebugInst); - - /// If DebugInst targets an Argument and its expression is an EntryValue, - /// lower as a DBG_VALUE targeting the corresponding livein register for that - /// Argument. - bool translateIfEntryValueArgument(const DbgValueInst &DebugInst, + /// If debug-info targets an Argument and its expression is an EntryValue, + /// lower it as either an entry in the MF debug table (dbg.declare), or a + /// DBG_VALUE targeting the corresponding livein register for that Argument + /// (dbg.value). + bool translateIfEntryValueArgument(bool isDeclare, Value *Arg, + const DILocalVariable *Var, + const DIExpression *Expr, + const DebugLoc &DL, MachineIRBuilder &MIRBuilder); bool translateInlineAsm(const CallBase &CB, MachineIRBuilder &MIRBuilder); diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index 662de0f3fe0e5..1a71c1232c706 100644 --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -162,7 +162,8 @@ class DILocationVerifier : public GISelChangeObserver { // they could have originated from constants, and we don't want a jumpy // debug experience. assert((CurrInst->getDebugLoc() == MI.getDebugLoc() || - (MI.getParent()->isEntryBlock() && !MI.getDebugLoc())) && + (MI.getParent()->isEntryBlock() && !MI.getDebugLoc()) || + (MI.isDebugInstr())) && "Line info was not transferred to all instructions"); } }; @@ -2006,47 +2007,35 @@ std::optional IRTranslator::getArgPhysReg(Argument &Arg) { return VRegDef->getOperand(1).getReg().asMCReg(); } -bool IRTranslator::translateIfEntryValueArgument(const DbgValueInst &DebugInst, +bool IRTranslator::translateIfEntryValueArgument(bool isDeclare, Value *Val, + const DILocalVariable *Var, + const DIExpression *Expr, + const DebugLoc &DL, MachineIRBuilder &MIRBuilder) { - auto *Arg = dyn_cast(DebugInst.getValue()); + auto *Arg = dyn_cast(Val); if (!Arg) return false; - const DIExpression *Expr = DebugInst.getExpression(); if (!Expr->isEntryValue()) return false; std::optional PhysReg = getArgPhysReg(*Arg); if (!PhysReg) { - LLVM_DEBUG(dbgs() << "Dropping dbg.value: expression is entry_value but " - "couldn't find a physical register\n" - << DebugInst << "\n"); + LLVM_DEBUG(dbgs() << "Dropping dbg." << (isDeclare ? "declare" : "value") + << ": expression is entry_value but " + << "couldn't find a physical register\n"); + LLVM_DEBUG(dbgs() << *Var << "\n"); return true; } - MIRBuilder.buildDirectDbgValue(*PhysReg, DebugInst.getVariable(), - DebugInst.getExpression()); - return true; -} - -bool IRTranslator::translateIfEntryValueArgument( - const DbgDeclareInst &DebugInst) { - auto *Arg = dyn_cast(DebugInst.getAddress()); - if (!Arg) - return false; - - const DIExpression *Expr = DebugInst.getExpression(); - if (!Expr->isEntryValue()) - return false; - - std::optional PhysReg = getArgPhysReg(*Arg); - if (!PhysReg) - return false; + if (isDeclare) { + // Append an op deref to account for the fact that this is a dbg_declare. + Expr = DIExpression::append(Expr, dwarf::DW_OP_deref); + MF->setVariableDbgInfo(Var, Expr, *PhysReg, DL); + } else { + MIRBuilder.buildDirectDbgValue(*PhysReg, Var, Expr); + } - // Append an op deref to account for the fact that this is a dbg_declare. - Expr = DIExpression::append(Expr, dwarf::DW_OP_deref); - MF->setVariableDbgInfo(DebugInst.getVariable(), Expr, *PhysReg, - DebugInst.getDebugLoc()); return true; } @@ -2100,32 +2089,8 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID, case Intrinsic::dbg_declare: { const DbgDeclareInst &DI = cast(CI); assert(DI.getVariable() && "Missing variable"); - - const Value *Address = DI.getAddress(); - if (!Address || isa(Address)) { - LLVM_DEBUG(dbgs() << "Dropping debug info for " << DI << "\n"); - return true; - } - - assert(DI.getVariable()->isValidLocationForIntrinsic( - MIRBuilder.getDebugLoc()) && - "Expected inlined-at fields to agree"); - auto AI = dyn_cast(Address); - if (AI && AI->isStaticAlloca()) { - // Static allocas are tracked at the MF level, no need for DBG_VALUE - // instructions (in fact, they get ignored if they *do* exist). - MF->setVariableDbgInfo(DI.getVariable(), DI.getExpression(), - getOrCreateFrameIndex(*AI), DI.getDebugLoc()); - return true; - } - - if (translateIfEntryValueArgument(DI)) - return true; - - // A dbg.declare describes the address of a source variable, so lower it - // into an indirect DBG_VALUE. - MIRBuilder.buildIndirectDbgValue(getOrCreateVReg(*Address), - DI.getVariable(), DI.getExpression()); + translateDbgDeclareRecord(DI.getAddress(), DI.hasArgList(), DI.getVariable(), + DI.getExpression(), DI.getDebugLoc(), MIRBuilder); return true; } case Intrinsic::dbg_label: { @@ -2158,41 +2123,8 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID, case Intrinsic::dbg_value: { // This form of DBG_VALUE is target-independent. const DbgValueInst &DI = cast(CI); - const Value *V = DI.getValue(); - assert(DI.getVariable()->isValidLocationForIntrinsic( - MIRBuilder.getDebugLoc()) && - "Expected inlined-at fields to agree"); - if (!V || DI.hasArgList()) { - // DI cannot produce a valid DBG_VALUE, so produce an undef DBG_VALUE to - // terminate any prior location. - MIRBuilder.buildIndirectDbgValue(0, DI.getVariable(), DI.getExpression()); - return true; - } - if (const auto *CI = dyn_cast(V)) { - MIRBuilder.buildConstDbgValue(*CI, DI.getVariable(), DI.getExpression()); - return true; - } - if (auto *AI = dyn_cast(V); - AI && AI->isStaticAlloca() && DI.getExpression()->startsWithDeref()) { - // If the value is an alloca and the expression starts with a - // dereference, track a stack slot instead of a register, as registers - // may be clobbered. - auto ExprOperands = DI.getExpression()->getElements(); - auto *ExprDerefRemoved = - DIExpression::get(AI->getContext(), ExprOperands.drop_front()); - MIRBuilder.buildFIDbgValue(getOrCreateFrameIndex(*AI), DI.getVariable(), - ExprDerefRemoved); - return true; - } - if (translateIfEntryValueArgument(DI, MIRBuilder)) - return true; - for (Register Reg : getOrCreateVRegs(*V)) { - // FIXME: This does not handle register-indirect values at offset 0. The - // direct/indirect thing shouldn't really be handled by something as - // implicit as reg+noreg vs reg+imm in the first place, but it seems - // pretty baked in right now. - MIRBuilder.buildDirectDbgValue(Reg, DI.getVariable(), DI.getExpression()); - } + translateDbgValueRecord(DI.getValue(), DI.hasArgList(), DI.getVariable(), + DI.getExpression(), DI.getDebugLoc(), MIRBuilder); return true; } case Intrinsic::uadd_with_overflow: @@ -3250,6 +3182,102 @@ void IRTranslator::finishPendingPhis() { } } +void IRTranslator::translateDbgValueRecord(Value *V, bool HasArgList, + const DILocalVariable *Variable, + const DIExpression *Expression, + const DebugLoc &DL, + MachineIRBuilder &MIRBuilder) { + assert(Variable->isValidLocationForIntrinsic(DL) && + "Expected inlined-at fields to agree"); + // Act as if we're handling a debug intrinsic. + MIRBuilder.setDebugLoc(DL); + + if (!V || HasArgList) { + // DI cannot produce a valid DBG_VALUE, so produce an undef DBG_VALUE to + // terminate any prior location. + MIRBuilder.buildIndirectDbgValue(0, Variable, Expression); + return; + } + + if (const auto *CI = dyn_cast(V)) { + MIRBuilder.buildConstDbgValue(*CI, Variable, Expression); + return; + } + + if (auto *AI = dyn_cast(V); + AI && AI->isStaticAlloca() && Expression->startsWithDeref()) { + // If the value is an alloca and the expression starts with a + // dereference, track a stack slot instead of a register, as registers + // may be clobbered. + auto ExprOperands = Expression->getElements(); + auto *ExprDerefRemoved = + DIExpression::get(AI->getContext(), ExprOperands.drop_front()); + MIRBuilder.buildFIDbgValue(getOrCreateFrameIndex(*AI), Variable, + ExprDerefRemoved); + return; + } + if (translateIfEntryValueArgument(false, V, Variable, Expression, DL, + MIRBuilder)) + return; + for (Register Reg : getOrCreateVRegs(*V)) { + // FIXME: This does not handle register-indirect values at offset 0. The + // direct/indirect thing shouldn't really be handled by something as + // implicit as reg+noreg vs reg+imm in the first place, but it seems + // pretty baked in right now. + MIRBuilder.buildDirectDbgValue(Reg, Variable, Expression); + } + return; +} + +void IRTranslator::translateDbgDeclareRecord(Value *Address, bool HasArgList, + const DILocalVariable *Variable, + const DIExpression *Expression, + const DebugLoc &DL, + MachineIRBuilder &MIRBuilder) { + if (!Address || isa(Address)) { + LLVM_DEBUG(dbgs() << "Dropping debug info for " << *Variable << "\n"); + return; + } + + assert(Variable->isValidLocationForIntrinsic(DL) && + "Expected inlined-at fields to agree"); + auto AI = dyn_cast(Address); + if (AI && AI->isStaticAlloca()) { + // Static allocas are tracked at the MF level, no need for DBG_VALUE + // instructions (in fact, they get ignored if they *do* exist). + MF->setVariableDbgInfo(Variable, Expression, + getOrCreateFrameIndex(*AI), DL); + return; + } + + if (translateIfEntryValueArgument(true, Address, Variable, + Expression, DL, + MIRBuilder)) + return; + + // A dbg.declare describes the address of a source variable, so lower it + // into an indirect DBG_VALUE. + MIRBuilder.setDebugLoc(DL); + MIRBuilder.buildIndirectDbgValue(getOrCreateVReg(*Address), + Variable, Expression); + return; +} + +void IRTranslator::translateDbgInfo(const Instruction &Inst, + MachineIRBuilder &MIRBuilder) { + for (DPValue &DPV : Inst.getDbgValueRange()) { + const DILocalVariable *Variable = DPV.getVariable(); + const DIExpression *Expression = DPV.getExpression(); + Value *V = DPV.getVariableLocationOp(0); + if (DPV.isDbgDeclare()) + translateDbgDeclareRecord(V, DPV.hasArgList(), Variable, + Expression, DPV.getDebugLoc(), MIRBuilder); + else + translateDbgValueRecord(V, DPV.hasArgList(), Variable, + Expression, DPV.getDebugLoc(), MIRBuilder); + } +} + bool IRTranslator::translate(const Instruction &Inst) { CurBuilder->setDebugLoc(Inst.getDebugLoc()); CurBuilder->setPCSections(Inst.getMetadata(LLVMContext::MD_pcsections)); @@ -3760,6 +3788,10 @@ bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) { #ifndef NDEBUG Verifier.setCurrentInst(&Inst); #endif // ifndef NDEBUG + + // Translate any debug-info attached to the instruction. + translateDbgInfo(Inst, *CurBuilder.get()); + if (translate(Inst)) continue; diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-shift-of-shifted-dbg-value-fallback.ll b/llvm/test/CodeGen/AArch64/GlobalISel/combine-shift-of-shifted-dbg-value-fallback.ll index adaf54cbc9620..930d39dfa298b 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-shift-of-shifted-dbg-value-fallback.ll +++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-shift-of-shifted-dbg-value-fallback.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -global-isel -mtriple=arm64-linux-gnu -global-isel-abort=1 | FileCheck %s +; RUN: llc < %s -global-isel -mtriple=arm64-linux-gnu -global-isel-abort=1 --try-experimental-debuginfo-iterators | FileCheck %s target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" target triple = "arm64-apple-ios9.0.0" diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/debug-cpp.ll b/llvm/test/CodeGen/AArch64/GlobalISel/debug-cpp.ll index cb4a01cbcf092..485ab18ec7db9 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/debug-cpp.ll +++ b/llvm/test/CodeGen/AArch64/GlobalISel/debug-cpp.ll @@ -1,5 +1,7 @@ ; RUN: llc -global-isel -mtriple=aarch64 %s -stop-after=irtranslator -o - | FileCheck %s ; RUN: llc -mtriple=aarch64 -global-isel --global-isel-abort=0 -o /dev/null +; RUN: llc -global-isel -mtriple=aarch64 %s -stop-after=irtranslator -o - --try-experimental-debuginfo-iterators | FileCheck %s +; RUN: llc -mtriple=aarch64 -global-isel --global-isel-abort=0 -o /dev/null --try-experimental-debuginfo-iterators ; struct NTCopy { ; NTCopy(); diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/debug-insts.ll b/llvm/test/CodeGen/AArch64/GlobalISel/debug-insts.ll index 47ddca8fd0577..960ea4e5b9f42 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/debug-insts.ll +++ b/llvm/test/CodeGen/AArch64/GlobalISel/debug-insts.ll @@ -2,6 +2,10 @@ ; RUN: llc -global-isel -mtriple=aarch64 %s -stop-after=irtranslator -o - | FileCheck %s ; RUN: llc -mtriple=aarch64 -global-isel --global-isel-abort=0 %s -o /dev/null ; RUN: llc -mtriple=aarch64 -global-isel --global-isel-abort=0 %s -o /dev/null -debug +; +; RUN: llc -global-isel -mtriple=aarch64 %s -stop-after=irtranslator -o - --try-experimental-debuginfo-iterators | FileCheck %s +; RUN: llc -mtriple=aarch64 -global-isel --global-isel-abort=0 %s -o /dev/null --try-experimental-debuginfo-iterators +; RUN: llc -mtriple=aarch64 -global-isel --global-isel-abort=0 %s -o /dev/null -debug --try-experimental-debuginfo-iterators ; CHECK-LABEL: name: debug_declare ; CHECK: stack: diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-dilocation.ll b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-dilocation.ll index a8fc761a3a533..fc17a62a4d704 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-dilocation.ll +++ b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-dilocation.ll @@ -1,16 +1,18 @@ ; RUN: llc -O0 -mtriple=aarch64-apple-ios -global-isel -debug-only=irtranslator \ ; RUN: -stop-after=irtranslator %s -o - 2>&1 | FileCheck %s +; RUN: llc -O0 -mtriple=aarch64-apple-ios -global-isel -debug-only=irtranslator \ +; RUN: -stop-after=irtranslator %s -o - 2>&1 --try-experimental-debuginfo-iterators | FileCheck %s ; REQUIRES: asserts -; CHECK: Checking DILocation from %retval = alloca i32, align 4 was copied to G_FRAME_INDEX -; CHECK: Checking DILocation from %rv = alloca i32, align 4 was copied to G_FRAME_INDEX -; CHECK: Checking DILocation from store i32 0, ptr %retval, align 4 was copied to G_CONSTANT -; CHECK: Checking DILocation from store i32 0, ptr %retval, align 4 was copied to G_STORE -; CHECK: Checking DILocation from store i32 0, ptr %rv, align 4, !dbg !12 was copied to G_STORE debug-location !12; t.cpp:2:5 -; CHECK: Checking DILocation from %0 = load i32, ptr %rv, align 4, !dbg !13 was copied to G_LOAD debug-location !13; t.cpp:3:8 -; CHECK: Checking DILocation from ret i32 %0, !dbg !14 was copied to COPY debug-location !14; t.cpp:3:1 -; CHECK: Checking DILocation from ret i32 %0, !dbg !14 was copied to RET_ReallyLR implicit $w0, debug-location !14; t.cpp:3:1 +; CHECK: Checking DILocation from %retval = alloca i32, align 4{{.*}} was copied to G_FRAME_INDEX +; CHECK: Checking DILocation from %rv = alloca i32, align 4{{.*}} was copied to G_FRAME_INDEX +; CHECK: Checking DILocation from store i32 0, ptr %retval, align 4{{.*}} was copied to G_CONSTANT +; CHECK: Checking DILocation from store i32 0, ptr %retval, align 4{{.*}} was copied to G_STORE +; CHECK: Checking DILocation from store i32 0, ptr %rv, align 4, !dbg !12{{.*}} was copied to G_STORE debug-location !12; t.cpp:2:5 +; CHECK: Checking DILocation from %0 = load i32, ptr %rv, align 4, !dbg !13{{.*}} was copied to G_LOAD debug-location !13; t.cpp:3:8 +; CHECK: Checking DILocation from ret i32 %0, !dbg !14{{.*}} was copied to COPY debug-location !14; t.cpp:3:1 +; CHECK: Checking DILocation from ret i32 %0, !dbg !14{{.*}} was copied to RET_ReallyLR implicit $w0, debug-location !14; t.cpp:3:1 source_filename = "t.cpp" target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-extract-used-by-dbg.ll b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-extract-used-by-dbg.ll index 9f398b4a9d3b1..1304747789f2a 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-extract-used-by-dbg.ll +++ b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-extract-used-by-dbg.ll @@ -1,4 +1,5 @@ ; RUN: llc -O0 -stop-after=irtranslator -global-isel -verify-machineinstrs %s -o - 2>&1 | FileCheck %s +; RUN: llc -O0 -stop-after=irtranslator -global-isel -verify-machineinstrs %s -o - 2>&1 --try-experimental-debuginfo-iterators | FileCheck %s target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" target triple = "aarch64-unknown-fuchsia" diff --git a/llvm/test/CodeGen/X86/GlobalISel/x86-calllowering-dbg-trunc.ll b/llvm/test/CodeGen/X86/GlobalISel/x86-calllowering-dbg-trunc.ll index 90c9290a83bbd..f9c34d3b0bb27 100644 --- a/llvm/test/CodeGen/X86/GlobalISel/x86-calllowering-dbg-trunc.ll +++ b/llvm/test/CodeGen/X86/GlobalISel/x86-calllowering-dbg-trunc.ll @@ -1,4 +1,5 @@ ; RUN: llc -mtriple=i386-linux-gnu -global-isel -verify-machineinstrs < %s -o - | FileCheck %s --check-prefix=ALL +; RUN: llc -mtriple=i386-linux-gnu -global-isel -verify-machineinstrs < %s -o - --try-experimental-debuginfo-iterators | FileCheck %s --check-prefix=ALL ; This file is the output of clang -g -O2 ; int test_dbg_trunc(unsigned long long a) { return a; }