diff options
author | Orlando Cazalet-Hyams <orlando.hyams@sony.com> | 2024-01-05 15:11:47 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-05 15:11:47 +0000 |
commit | 10b03e66629aedad79a804e22d23b575077303b3 (patch) | |
tree | b8e0b0c28bb2841e837583d9680c3c53de6cc4d0 /llvm/lib/CodeGen/SelectionDAG/FastISel.cpp | |
parent | 736cc0cbf0107f6a1678a5495e1931733ab57393 (diff) | |
download | llvm-10b03e66629aedad79a804e22d23b575077303b3.zip llvm-10b03e66629aedad79a804e22d23b575077303b3.tar.gz llvm-10b03e66629aedad79a804e22d23b575077303b3.tar.bz2 |
[RemoveDIs] Handle DPValues in FastISel (#76952)
The change is fairly mechanical:
1. Factor code from `FastISel::selectIntrinsicCall`, which converts
debug intrinsics into debug instructions, into functions (NFC).
2. Call those functions for DPValues attached to instructions too.
The test updates look the same as other RemoveDIs changes: re-run the
tests with `--try-experimental-debuginfo-iterators`, which checks the
output is identical using the new debug info format (if it has been
enabled in the cmake configuration).
Depends on #76941 (otherwise some modified tests spuriously fail).
Diffstat (limited to 'llvm/lib/CodeGen/SelectionDAG/FastISel.cpp')
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/FastISel.cpp | 323 |
1 files changed, 188 insertions, 135 deletions
diff --git a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp index 09e2603..6d80b28 100644 --- a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -1180,6 +1180,184 @@ bool FastISel::selectCall(const User *I) { return lowerCall(Call); } +void FastISel::handleDbgInfo(const Instruction *II) { + if (!II->hasDbgValues()) + return; + + // Clear any metadata. + MIMD = MIMetadata(); + + // Reverse order of debug records, because fast-isel walks through backwards. + for (DPValue &DPV : llvm::reverse(II->getDbgValueRange())) { + flushLocalValueMap(); + recomputeInsertPt(); + + Value *V = nullptr; + if (!DPV.hasArgList()) + V = DPV.getVariableLocationOp(0); + + bool Res = false; + if (DPV.getType() == DPValue::LocationType::Value) { + Res = lowerDbgValue(V, DPV.getExpression(), DPV.getVariable(), + DPV.getDebugLoc()); + } else { + assert(DPV.getType() == DPValue::LocationType::Declare); + if (FuncInfo.PreprocessedDPVDeclares.contains(&DPV)) + continue; + Res = lowerDbgDeclare(V, DPV.getExpression(), DPV.getVariable(), + DPV.getDebugLoc()); + } + + if (!Res) + LLVM_DEBUG(dbgs() << "Dropping debug-info for " << DPV << "\n";); + } +} + +bool FastISel::lowerDbgValue(const Value *V, DIExpression *Expr, + DILocalVariable *Var, const DebugLoc &DL) { + // This form of DBG_VALUE is target-independent. + const MCInstrDesc &II = TII.get(TargetOpcode::DBG_VALUE); + if (!V || isa<UndefValue>(V)) { + // DI is either undef or cannot produce a valid DBG_VALUE, so produce an + // undef DBG_VALUE to terminate any prior location. + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, false, 0U, Var, Expr); + return true; + } + if (const auto *CI = dyn_cast<ConstantInt>(V)) { + // See if there's an expression to constant-fold. + if (Expr) + std::tie(Expr, CI) = Expr->constantFold(CI); + if (CI->getBitWidth() > 64) + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II) + .addCImm(CI) + .addImm(0U) + .addMetadata(Var) + .addMetadata(Expr); + else + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II) + .addImm(CI->getZExtValue()) + .addImm(0U) + .addMetadata(Var) + .addMetadata(Expr); + return true; + } + if (const auto *CF = dyn_cast<ConstantFP>(V)) { + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II) + .addFPImm(CF) + .addImm(0U) + .addMetadata(Var) + .addMetadata(Expr); + return true; + } + if (const auto *Arg = dyn_cast<Argument>(V); + Arg && Expr && Expr->isEntryValue()) { + // As per the Verifier, this case is only valid for swift async Args. + assert(Arg->hasAttribute(Attribute::AttrKind::SwiftAsync)); + + Register Reg = getRegForValue(Arg); + for (auto [PhysReg, VirtReg] : FuncInfo.RegInfo->liveins()) + if (Reg == VirtReg || Reg == PhysReg) { + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, false /*IsIndirect*/, + PhysReg, Var, Expr); + return true; + } + + LLVM_DEBUG(dbgs() << "Dropping dbg.value: expression is entry_value but " + "couldn't find a physical register\n"); + return false; + } + if (auto SI = FuncInfo.StaticAllocaMap.find(dyn_cast<AllocaInst>(V)); + SI != FuncInfo.StaticAllocaMap.end()) { + MachineOperand FrameIndexOp = MachineOperand::CreateFI(SI->second); + bool IsIndirect = false; + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, IsIndirect, FrameIndexOp, + Var, Expr); + return true; + } + if (Register Reg = lookUpRegForValue(V)) { + // FIXME: This does not handle register-indirect values at offset 0. + if (!FuncInfo.MF->useDebugInstrRef()) { + bool IsIndirect = false; + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, IsIndirect, Reg, Var, + Expr); + return true; + } + // If using instruction referencing, produce this as a DBG_INSTR_REF, + // to be later patched up by finalizeDebugInstrRefs. + SmallVector<MachineOperand, 1> MOs({MachineOperand::CreateReg( + /* Reg */ Reg, /* isDef */ false, /* isImp */ false, + /* isKill */ false, /* isDead */ false, + /* isUndef */ false, /* isEarlyClobber */ false, + /* SubReg */ 0, /* isDebug */ true)}); + SmallVector<uint64_t, 2> Ops({dwarf::DW_OP_LLVM_arg, 0}); + auto *NewExpr = DIExpression::prependOpcodes(Expr, Ops); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(TargetOpcode::DBG_INSTR_REF), /*IsIndirect*/ false, MOs, + Var, NewExpr); + return true; + } + return false; +} + +bool FastISel::lowerDbgDeclare(const Value *Address, DIExpression *Expr, + DILocalVariable *Var, const DebugLoc &DL) { + if (!Address || isa<UndefValue>(Address)) { + LLVM_DEBUG(dbgs() << "Dropping debug info (bad/undef address)\n"); + return false; + } + + std::optional<MachineOperand> Op; + if (Register Reg = lookUpRegForValue(Address)) + Op = MachineOperand::CreateReg(Reg, false); + + // If we have a VLA that has a "use" in a metadata node that's then used + // here but it has no other uses, then we have a problem. E.g., + // + // int foo (const int *x) { + // char a[*x]; + // return 0; + // } + // + // If we assign 'a' a vreg and fast isel later on has to use the selection + // DAG isel, it will want to copy the value to the vreg. However, there are + // no uses, which goes counter to what selection DAG isel expects. + if (!Op && !Address->use_empty() && isa<Instruction>(Address) && + (!isa<AllocaInst>(Address) || + !FuncInfo.StaticAllocaMap.count(cast<AllocaInst>(Address)))) + Op = MachineOperand::CreateReg(FuncInfo.InitializeRegForValue(Address), + false); + + if (Op) { + assert(Var->isValidLocationForIntrinsic(DL) && + "Expected inlined-at fields to agree"); + if (FuncInfo.MF->useDebugInstrRef() && Op->isReg()) { + // If using instruction referencing, produce this as a DBG_INSTR_REF, + // to be later patched up by finalizeDebugInstrRefs. Tack a deref onto + // the expression, we don't have an "indirect" flag in DBG_INSTR_REF. + SmallVector<uint64_t, 3> Ops( + {dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_deref}); + auto *NewExpr = DIExpression::prependOpcodes(Expr, Ops); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(TargetOpcode::DBG_INSTR_REF), /*IsIndirect*/ false, *Op, + Var, NewExpr); + return true; + } + + // A dbg.declare describes the address of a source variable, so lower it + // into an indirect DBG_VALUE. + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(TargetOpcode::DBG_VALUE), /*IsIndirect*/ true, *Op, Var, + Expr); + return true; + } + + // We can't yet handle anything else here because it would require + // generating code, thus altering codegen because of debug info. + LLVM_DEBUG( + dbgs() << "Dropping debug info (no materialized reg for address)\n"); + return false; +} + bool FastISel::selectIntrinsicCall(const IntrinsicInst *II) { switch (II->getIntrinsicID()) { default: @@ -1209,153 +1387,28 @@ bool FastISel::selectIntrinsicCall(const IntrinsicInst *II) { return true; const Value *Address = DI->getAddress(); - if (!Address || isa<UndefValue>(Address)) { - LLVM_DEBUG(dbgs() << "Dropping debug info for " << *DI - << " (bad/undef address)\n"); - return true; - } + if (!lowerDbgDeclare(Address, DI->getExpression(), DI->getVariable(), + MIMD.getDL())) + LLVM_DEBUG(dbgs() << "Dropping debug info for " << *DI); - std::optional<MachineOperand> Op; - if (Register Reg = lookUpRegForValue(Address)) - Op = MachineOperand::CreateReg(Reg, false); - - // If we have a VLA that has a "use" in a metadata node that's then used - // here but it has no other uses, then we have a problem. E.g., - // - // int foo (const int *x) { - // char a[*x]; - // return 0; - // } - // - // If we assign 'a' a vreg and fast isel later on has to use the selection - // DAG isel, it will want to copy the value to the vreg. However, there are - // no uses, which goes counter to what selection DAG isel expects. - if (!Op && !Address->use_empty() && isa<Instruction>(Address) && - (!isa<AllocaInst>(Address) || - !FuncInfo.StaticAllocaMap.count(cast<AllocaInst>(Address)))) - Op = MachineOperand::CreateReg(FuncInfo.InitializeRegForValue(Address), - false); - - if (Op) { - assert(DI->getVariable()->isValidLocationForIntrinsic(MIMD.getDL()) && - "Expected inlined-at fields to agree"); - if (FuncInfo.MF->useDebugInstrRef() && Op->isReg()) { - // If using instruction referencing, produce this as a DBG_INSTR_REF, - // to be later patched up by finalizeDebugInstrRefs. Tack a deref onto - // the expression, we don't have an "indirect" flag in DBG_INSTR_REF. - SmallVector<uint64_t, 3> Ops( - {dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_deref}); - auto *NewExpr = DIExpression::prependOpcodes(DI->getExpression(), Ops); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD.getDL(), - TII.get(TargetOpcode::DBG_INSTR_REF), /*IsIndirect*/ false, *Op, - DI->getVariable(), NewExpr); - } else { - // A dbg.declare describes the address of a source variable, so lower it - // into an indirect DBG_VALUE. - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD.getDL(), - TII.get(TargetOpcode::DBG_VALUE), /*IsIndirect*/ true, *Op, - DI->getVariable(), DI->getExpression()); - } - } else { - // We can't yet handle anything else here because it would require - // generating code, thus altering codegen because of debug info. - LLVM_DEBUG(dbgs() << "Dropping debug info for " << *DI - << " (no materialized reg for address)\n"); - } return true; } case Intrinsic::dbg_value: { // This form of DBG_VALUE is target-independent. const DbgValueInst *DI = cast<DbgValueInst>(II); - const MCInstrDesc &II = TII.get(TargetOpcode::DBG_VALUE); const Value *V = DI->getValue(); DIExpression *Expr = DI->getExpression(); DILocalVariable *Var = DI->getVariable(); + if (DI->hasArgList()) + // Signal that we don't have a location for this. + V = nullptr; + assert(Var->isValidLocationForIntrinsic(MIMD.getDL()) && "Expected inlined-at fields to agree"); - if (!V || isa<UndefValue>(V) || DI->hasArgList()) { - // DI is either undef or cannot produce a valid DBG_VALUE, so produce an - // undef DBG_VALUE to terminate any prior location. - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD.getDL(), II, false, 0U, - Var, Expr); - return true; - } - if (const auto *CI = dyn_cast<ConstantInt>(V)) { - // See if there's an expression to constant-fold. - if (Expr) - std::tie(Expr, CI) = Expr->constantFold(CI); - if (CI->getBitWidth() > 64) - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, II) - .addCImm(CI) - .addImm(0U) - .addMetadata(Var) - .addMetadata(Expr); - else - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, II) - .addImm(CI->getZExtValue()) - .addImm(0U) - .addMetadata(Var) - .addMetadata(Expr); - return true; - } - if (const auto *CF = dyn_cast<ConstantFP>(V)) { - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, II) - .addFPImm(CF) - .addImm(0U) - .addMetadata(Var) - .addMetadata(Expr); - return true; - } - if (const auto *Arg = dyn_cast<Argument>(V); - Arg && Expr && Expr->isEntryValue()) { - // As per the Verifier, this case is only valid for swift async Args. - assert(Arg->hasAttribute(Attribute::AttrKind::SwiftAsync)); - - Register Reg = getRegForValue(Arg); - for (auto [PhysReg, VirtReg] : FuncInfo.RegInfo->liveins()) - if (Reg == VirtReg || Reg == PhysReg) { - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD.getDL(), II, - false /*IsIndirect*/, PhysReg, Var, Expr); - return true; - } - LLVM_DEBUG(dbgs() << "Dropping dbg.value: expression is entry_value but " - "couldn't find a physical register\n" - << *DI << "\n"); - return true; - } - if (auto SI = FuncInfo.StaticAllocaMap.find(dyn_cast<AllocaInst>(V)); - SI != FuncInfo.StaticAllocaMap.end()) { - MachineOperand FrameIndexOp = MachineOperand::CreateFI(SI->second); - bool IsIndirect = false; - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD.getDL(), II, IsIndirect, - FrameIndexOp, Var, Expr); - return true; - } - if (Register Reg = lookUpRegForValue(V)) { - // FIXME: This does not handle register-indirect values at offset 0. - if (!FuncInfo.MF->useDebugInstrRef()) { - bool IsIndirect = false; - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD.getDL(), II, IsIndirect, - Reg, Var, Expr); - return true; - } - // If using instruction referencing, produce this as a DBG_INSTR_REF, - // to be later patched up by finalizeDebugInstrRefs. - SmallVector<MachineOperand, 1> MOs({MachineOperand::CreateReg( - /* Reg */ Reg, /* isDef */ false, /* isImp */ false, - /* isKill */ false, /* isDead */ false, - /* isUndef */ false, /* isEarlyClobber */ false, - /* SubReg */ 0, /* isDebug */ true)}); - SmallVector<uint64_t, 2> Ops({dwarf::DW_OP_LLVM_arg, 0}); - auto *NewExpr = DIExpression::prependOpcodes(Expr, Ops); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD.getDL(), - TII.get(TargetOpcode::DBG_INSTR_REF), /*IsIndirect*/ false, MOs, - Var, NewExpr); - return true; - } - // We don't know how to handle other cases, so we drop. - LLVM_DEBUG(dbgs() << "Dropping debug info for " << *DI << "\n"); + if (!lowerDbgValue(V, Expr, Var, MIMD.getDL())) + LLVM_DEBUG(dbgs() << "Dropping debug info for " << *DI << "\n"); + return true; } case Intrinsic::dbg_label: { |