Skip to content

Commit 10b03e6

Browse files
authored
[RemoveDIs] Handle DPValues in FastISel (llvm#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 llvm#76941 (otherwise some modified tests spuriously fail).
1 parent 736cc0c commit 10b03e6

File tree

74 files changed

+398
-151
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+398
-151
lines changed

llvm/include/llvm/CodeGen/FastISel.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,10 @@ class FastISel {
319319
/// Reset InsertPt to the given old insert position.
320320
void leaveLocalValueArea(SavePoint Old);
321321

322+
/// Target-independent lowering of non-instruction debug info associated with
323+
/// this instruction.
324+
void handleDbgInfo(const Instruction *II);
325+
322326
protected:
323327
explicit FastISel(FunctionLoweringInfo &FuncInfo,
324328
const TargetLibraryInfo *LibInfo,
@@ -518,6 +522,16 @@ class FastISel {
518522
return MF->getFunction().hasOptSize();
519523
}
520524

525+
/// Target-independent lowering of debug information. Returns false if the
526+
/// debug information couldn't be lowered and was instead discarded.
527+
virtual bool lowerDbgValue(const Value *V, DIExpression *Expr,
528+
DILocalVariable *Var, const DebugLoc &DL);
529+
530+
/// Target-independent lowering of debug information. Returns false if the
531+
/// debug information couldn't be lowered and was instead discarded.
532+
virtual bool lowerDbgDeclare(const Value *V, DIExpression *Expr,
533+
DILocalVariable *Var, const DebugLoc &DL);
534+
521535
private:
522536
/// Handle PHI nodes in successor blocks.
523537
///

llvm/lib/CodeGen/SelectionDAG/FastISel.cpp

Lines changed: 188 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,6 +1180,184 @@ bool FastISel::selectCall(const User *I) {
11801180
return lowerCall(Call);
11811181
}
11821182

1183+
void FastISel::handleDbgInfo(const Instruction *II) {
1184+
if (!II->hasDbgValues())
1185+
return;
1186+
1187+
// Clear any metadata.
1188+
MIMD = MIMetadata();
1189+
1190+
// Reverse order of debug records, because fast-isel walks through backwards.
1191+
for (DPValue &DPV : llvm::reverse(II->getDbgValueRange())) {
1192+
flushLocalValueMap();
1193+
recomputeInsertPt();
1194+
1195+
Value *V = nullptr;
1196+
if (!DPV.hasArgList())
1197+
V = DPV.getVariableLocationOp(0);
1198+
1199+
bool Res = false;
1200+
if (DPV.getType() == DPValue::LocationType::Value) {
1201+
Res = lowerDbgValue(V, DPV.getExpression(), DPV.getVariable(),
1202+
DPV.getDebugLoc());
1203+
} else {
1204+
assert(DPV.getType() == DPValue::LocationType::Declare);
1205+
if (FuncInfo.PreprocessedDPVDeclares.contains(&DPV))
1206+
continue;
1207+
Res = lowerDbgDeclare(V, DPV.getExpression(), DPV.getVariable(),
1208+
DPV.getDebugLoc());
1209+
}
1210+
1211+
if (!Res)
1212+
LLVM_DEBUG(dbgs() << "Dropping debug-info for " << DPV << "\n";);
1213+
}
1214+
}
1215+
1216+
bool FastISel::lowerDbgValue(const Value *V, DIExpression *Expr,
1217+
DILocalVariable *Var, const DebugLoc &DL) {
1218+
// This form of DBG_VALUE is target-independent.
1219+
const MCInstrDesc &II = TII.get(TargetOpcode::DBG_VALUE);
1220+
if (!V || isa<UndefValue>(V)) {
1221+
// DI is either undef or cannot produce a valid DBG_VALUE, so produce an
1222+
// undef DBG_VALUE to terminate any prior location.
1223+
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, false, 0U, Var, Expr);
1224+
return true;
1225+
}
1226+
if (const auto *CI = dyn_cast<ConstantInt>(V)) {
1227+
// See if there's an expression to constant-fold.
1228+
if (Expr)
1229+
std::tie(Expr, CI) = Expr->constantFold(CI);
1230+
if (CI->getBitWidth() > 64)
1231+
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II)
1232+
.addCImm(CI)
1233+
.addImm(0U)
1234+
.addMetadata(Var)
1235+
.addMetadata(Expr);
1236+
else
1237+
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II)
1238+
.addImm(CI->getZExtValue())
1239+
.addImm(0U)
1240+
.addMetadata(Var)
1241+
.addMetadata(Expr);
1242+
return true;
1243+
}
1244+
if (const auto *CF = dyn_cast<ConstantFP>(V)) {
1245+
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II)
1246+
.addFPImm(CF)
1247+
.addImm(0U)
1248+
.addMetadata(Var)
1249+
.addMetadata(Expr);
1250+
return true;
1251+
}
1252+
if (const auto *Arg = dyn_cast<Argument>(V);
1253+
Arg && Expr && Expr->isEntryValue()) {
1254+
// As per the Verifier, this case is only valid for swift async Args.
1255+
assert(Arg->hasAttribute(Attribute::AttrKind::SwiftAsync));
1256+
1257+
Register Reg = getRegForValue(Arg);
1258+
for (auto [PhysReg, VirtReg] : FuncInfo.RegInfo->liveins())
1259+
if (Reg == VirtReg || Reg == PhysReg) {
1260+
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, false /*IsIndirect*/,
1261+
PhysReg, Var, Expr);
1262+
return true;
1263+
}
1264+
1265+
LLVM_DEBUG(dbgs() << "Dropping dbg.value: expression is entry_value but "
1266+
"couldn't find a physical register\n");
1267+
return false;
1268+
}
1269+
if (auto SI = FuncInfo.StaticAllocaMap.find(dyn_cast<AllocaInst>(V));
1270+
SI != FuncInfo.StaticAllocaMap.end()) {
1271+
MachineOperand FrameIndexOp = MachineOperand::CreateFI(SI->second);
1272+
bool IsIndirect = false;
1273+
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, IsIndirect, FrameIndexOp,
1274+
Var, Expr);
1275+
return true;
1276+
}
1277+
if (Register Reg = lookUpRegForValue(V)) {
1278+
// FIXME: This does not handle register-indirect values at offset 0.
1279+
if (!FuncInfo.MF->useDebugInstrRef()) {
1280+
bool IsIndirect = false;
1281+
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, IsIndirect, Reg, Var,
1282+
Expr);
1283+
return true;
1284+
}
1285+
// If using instruction referencing, produce this as a DBG_INSTR_REF,
1286+
// to be later patched up by finalizeDebugInstrRefs.
1287+
SmallVector<MachineOperand, 1> MOs({MachineOperand::CreateReg(
1288+
/* Reg */ Reg, /* isDef */ false, /* isImp */ false,
1289+
/* isKill */ false, /* isDead */ false,
1290+
/* isUndef */ false, /* isEarlyClobber */ false,
1291+
/* SubReg */ 0, /* isDebug */ true)});
1292+
SmallVector<uint64_t, 2> Ops({dwarf::DW_OP_LLVM_arg, 0});
1293+
auto *NewExpr = DIExpression::prependOpcodes(Expr, Ops);
1294+
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL,
1295+
TII.get(TargetOpcode::DBG_INSTR_REF), /*IsIndirect*/ false, MOs,
1296+
Var, NewExpr);
1297+
return true;
1298+
}
1299+
return false;
1300+
}
1301+
1302+
bool FastISel::lowerDbgDeclare(const Value *Address, DIExpression *Expr,
1303+
DILocalVariable *Var, const DebugLoc &DL) {
1304+
if (!Address || isa<UndefValue>(Address)) {
1305+
LLVM_DEBUG(dbgs() << "Dropping debug info (bad/undef address)\n");
1306+
return false;
1307+
}
1308+
1309+
std::optional<MachineOperand> Op;
1310+
if (Register Reg = lookUpRegForValue(Address))
1311+
Op = MachineOperand::CreateReg(Reg, false);
1312+
1313+
// If we have a VLA that has a "use" in a metadata node that's then used
1314+
// here but it has no other uses, then we have a problem. E.g.,
1315+
//
1316+
// int foo (const int *x) {
1317+
// char a[*x];
1318+
// return 0;
1319+
// }
1320+
//
1321+
// If we assign 'a' a vreg and fast isel later on has to use the selection
1322+
// DAG isel, it will want to copy the value to the vreg. However, there are
1323+
// no uses, which goes counter to what selection DAG isel expects.
1324+
if (!Op && !Address->use_empty() && isa<Instruction>(Address) &&
1325+
(!isa<AllocaInst>(Address) ||
1326+
!FuncInfo.StaticAllocaMap.count(cast<AllocaInst>(Address))))
1327+
Op = MachineOperand::CreateReg(FuncInfo.InitializeRegForValue(Address),
1328+
false);
1329+
1330+
if (Op) {
1331+
assert(Var->isValidLocationForIntrinsic(DL) &&
1332+
"Expected inlined-at fields to agree");
1333+
if (FuncInfo.MF->useDebugInstrRef() && Op->isReg()) {
1334+
// If using instruction referencing, produce this as a DBG_INSTR_REF,
1335+
// to be later patched up by finalizeDebugInstrRefs. Tack a deref onto
1336+
// the expression, we don't have an "indirect" flag in DBG_INSTR_REF.
1337+
SmallVector<uint64_t, 3> Ops(
1338+
{dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_deref});
1339+
auto *NewExpr = DIExpression::prependOpcodes(Expr, Ops);
1340+
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL,
1341+
TII.get(TargetOpcode::DBG_INSTR_REF), /*IsIndirect*/ false, *Op,
1342+
Var, NewExpr);
1343+
return true;
1344+
}
1345+
1346+
// A dbg.declare describes the address of a source variable, so lower it
1347+
// into an indirect DBG_VALUE.
1348+
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL,
1349+
TII.get(TargetOpcode::DBG_VALUE), /*IsIndirect*/ true, *Op, Var,
1350+
Expr);
1351+
return true;
1352+
}
1353+
1354+
// We can't yet handle anything else here because it would require
1355+
// generating code, thus altering codegen because of debug info.
1356+
LLVM_DEBUG(
1357+
dbgs() << "Dropping debug info (no materialized reg for address)\n");
1358+
return false;
1359+
}
1360+
11831361
bool FastISel::selectIntrinsicCall(const IntrinsicInst *II) {
11841362
switch (II->getIntrinsicID()) {
11851363
default:
@@ -1209,153 +1387,28 @@ bool FastISel::selectIntrinsicCall(const IntrinsicInst *II) {
12091387
return true;
12101388

12111389
const Value *Address = DI->getAddress();
1212-
if (!Address || isa<UndefValue>(Address)) {
1213-
LLVM_DEBUG(dbgs() << "Dropping debug info for " << *DI
1214-
<< " (bad/undef address)\n");
1215-
return true;
1216-
}
1390+
if (!lowerDbgDeclare(Address, DI->getExpression(), DI->getVariable(),
1391+
MIMD.getDL()))
1392+
LLVM_DEBUG(dbgs() << "Dropping debug info for " << *DI);
12171393

1218-
std::optional<MachineOperand> Op;
1219-
if (Register Reg = lookUpRegForValue(Address))
1220-
Op = MachineOperand::CreateReg(Reg, false);
1221-
1222-
// If we have a VLA that has a "use" in a metadata node that's then used
1223-
// here but it has no other uses, then we have a problem. E.g.,
1224-
//
1225-
// int foo (const int *x) {
1226-
// char a[*x];
1227-
// return 0;
1228-
// }
1229-
//
1230-
// If we assign 'a' a vreg and fast isel later on has to use the selection
1231-
// DAG isel, it will want to copy the value to the vreg. However, there are
1232-
// no uses, which goes counter to what selection DAG isel expects.
1233-
if (!Op && !Address->use_empty() && isa<Instruction>(Address) &&
1234-
(!isa<AllocaInst>(Address) ||
1235-
!FuncInfo.StaticAllocaMap.count(cast<AllocaInst>(Address))))
1236-
Op = MachineOperand::CreateReg(FuncInfo.InitializeRegForValue(Address),
1237-
false);
1238-
1239-
if (Op) {
1240-
assert(DI->getVariable()->isValidLocationForIntrinsic(MIMD.getDL()) &&
1241-
"Expected inlined-at fields to agree");
1242-
if (FuncInfo.MF->useDebugInstrRef() && Op->isReg()) {
1243-
// If using instruction referencing, produce this as a DBG_INSTR_REF,
1244-
// to be later patched up by finalizeDebugInstrRefs. Tack a deref onto
1245-
// the expression, we don't have an "indirect" flag in DBG_INSTR_REF.
1246-
SmallVector<uint64_t, 3> Ops(
1247-
{dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_deref});
1248-
auto *NewExpr = DIExpression::prependOpcodes(DI->getExpression(), Ops);
1249-
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD.getDL(),
1250-
TII.get(TargetOpcode::DBG_INSTR_REF), /*IsIndirect*/ false, *Op,
1251-
DI->getVariable(), NewExpr);
1252-
} else {
1253-
// A dbg.declare describes the address of a source variable, so lower it
1254-
// into an indirect DBG_VALUE.
1255-
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD.getDL(),
1256-
TII.get(TargetOpcode::DBG_VALUE), /*IsIndirect*/ true, *Op,
1257-
DI->getVariable(), DI->getExpression());
1258-
}
1259-
} else {
1260-
// We can't yet handle anything else here because it would require
1261-
// generating code, thus altering codegen because of debug info.
1262-
LLVM_DEBUG(dbgs() << "Dropping debug info for " << *DI
1263-
<< " (no materialized reg for address)\n");
1264-
}
12651394
return true;
12661395
}
12671396
case Intrinsic::dbg_value: {
12681397
// This form of DBG_VALUE is target-independent.
12691398
const DbgValueInst *DI = cast<DbgValueInst>(II);
1270-
const MCInstrDesc &II = TII.get(TargetOpcode::DBG_VALUE);
12711399
const Value *V = DI->getValue();
12721400
DIExpression *Expr = DI->getExpression();
12731401
DILocalVariable *Var = DI->getVariable();
1402+
if (DI->hasArgList())
1403+
// Signal that we don't have a location for this.
1404+
V = nullptr;
1405+
12741406
assert(Var->isValidLocationForIntrinsic(MIMD.getDL()) &&
12751407
"Expected inlined-at fields to agree");
1276-
if (!V || isa<UndefValue>(V) || DI->hasArgList()) {
1277-
// DI is either undef or cannot produce a valid DBG_VALUE, so produce an
1278-
// undef DBG_VALUE to terminate any prior location.
1279-
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD.getDL(), II, false, 0U,
1280-
Var, Expr);
1281-
return true;
1282-
}
1283-
if (const auto *CI = dyn_cast<ConstantInt>(V)) {
1284-
// See if there's an expression to constant-fold.
1285-
if (Expr)
1286-
std::tie(Expr, CI) = Expr->constantFold(CI);
1287-
if (CI->getBitWidth() > 64)
1288-
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, II)
1289-
.addCImm(CI)
1290-
.addImm(0U)
1291-
.addMetadata(Var)
1292-
.addMetadata(Expr);
1293-
else
1294-
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, II)
1295-
.addImm(CI->getZExtValue())
1296-
.addImm(0U)
1297-
.addMetadata(Var)
1298-
.addMetadata(Expr);
1299-
return true;
1300-
}
1301-
if (const auto *CF = dyn_cast<ConstantFP>(V)) {
1302-
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, II)
1303-
.addFPImm(CF)
1304-
.addImm(0U)
1305-
.addMetadata(Var)
1306-
.addMetadata(Expr);
1307-
return true;
1308-
}
1309-
if (const auto *Arg = dyn_cast<Argument>(V);
1310-
Arg && Expr && Expr->isEntryValue()) {
1311-
// As per the Verifier, this case is only valid for swift async Args.
1312-
assert(Arg->hasAttribute(Attribute::AttrKind::SwiftAsync));
1313-
1314-
Register Reg = getRegForValue(Arg);
1315-
for (auto [PhysReg, VirtReg] : FuncInfo.RegInfo->liveins())
1316-
if (Reg == VirtReg || Reg == PhysReg) {
1317-
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD.getDL(), II,
1318-
false /*IsIndirect*/, PhysReg, Var, Expr);
1319-
return true;
1320-
}
13211408

1322-
LLVM_DEBUG(dbgs() << "Dropping dbg.value: expression is entry_value but "
1323-
"couldn't find a physical register\n"
1324-
<< *DI << "\n");
1325-
return true;
1326-
}
1327-
if (auto SI = FuncInfo.StaticAllocaMap.find(dyn_cast<AllocaInst>(V));
1328-
SI != FuncInfo.StaticAllocaMap.end()) {
1329-
MachineOperand FrameIndexOp = MachineOperand::CreateFI(SI->second);
1330-
bool IsIndirect = false;
1331-
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD.getDL(), II, IsIndirect,
1332-
FrameIndexOp, Var, Expr);
1333-
return true;
1334-
}
1335-
if (Register Reg = lookUpRegForValue(V)) {
1336-
// FIXME: This does not handle register-indirect values at offset 0.
1337-
if (!FuncInfo.MF->useDebugInstrRef()) {
1338-
bool IsIndirect = false;
1339-
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD.getDL(), II, IsIndirect,
1340-
Reg, Var, Expr);
1341-
return true;
1342-
}
1343-
// If using instruction referencing, produce this as a DBG_INSTR_REF,
1344-
// to be later patched up by finalizeDebugInstrRefs.
1345-
SmallVector<MachineOperand, 1> MOs({MachineOperand::CreateReg(
1346-
/* Reg */ Reg, /* isDef */ false, /* isImp */ false,
1347-
/* isKill */ false, /* isDead */ false,
1348-
/* isUndef */ false, /* isEarlyClobber */ false,
1349-
/* SubReg */ 0, /* isDebug */ true)});
1350-
SmallVector<uint64_t, 2> Ops({dwarf::DW_OP_LLVM_arg, 0});
1351-
auto *NewExpr = DIExpression::prependOpcodes(Expr, Ops);
1352-
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD.getDL(),
1353-
TII.get(TargetOpcode::DBG_INSTR_REF), /*IsIndirect*/ false, MOs,
1354-
Var, NewExpr);
1355-
return true;
1356-
}
1357-
// We don't know how to handle other cases, so we drop.
1358-
LLVM_DEBUG(dbgs() << "Dropping debug info for " << *DI << "\n");
1409+
if (!lowerDbgValue(V, Expr, Var, MIMD.getDL()))
1410+
LLVM_DEBUG(dbgs() << "Dropping debug info for " << *DI << "\n");
1411+
13591412
return true;
13601413
}
13611414
case Intrinsic::dbg_label: {

0 commit comments

Comments
 (0)