Skip to content

Commit b72d627

Browse files
epilkkzhuravl
authored andcommitted
[HeterogeneousDwarf] Improve -O1 debugging support
Squashed commit, fixes SWDEV-463925. This is a combination of 5 commits. This is the 1st commit message: [AMDGPU] Remove Dwarf encodings for subregisters Previously, registers and subregisters mapped to the same Dwarf encoding. We don't really have any way to refer to subregisters directly from Dwarf, the expression emitter should instead use DW_OPs to stencil out the subregister from the whole register. This was also confusing tools that need to map back to the llvm reg (e.g. dwarfdump), since getLLVMRegNum() would arbitrarily return the _LO16 register. This is a cherry-pick of github.com/llvm/pull/117891 with test fixes. Change-Id: I155bce592c7d556c01a7e3048bb8b251109dd51d This is the commit message #2: [HeterogeneousDwarf] Support poisoned fragments in DIExpression This improves fragment emission, since we previously had to assume that a poisoned expression clobbered all other live variable fragments. Now, it only clobbers the region described by it's fragment. This commit also canonicalizes any DIExpression containing a poison to only the ops DW_OP_LLVM_poisoned and (optionally) DW_OP_LLVM_fragment. The other ops don't really serve any purpose since we can't rely on any invariants (e.g. number of location ops) of a poisoned expression. This also cleans up the dwarf output for posioned exprs. Change-Id: I97bd9513a81b30f290ef70f958dcc8ca4c79e489 This is the commit message #3: [HeterogeneousDwarf] Support Dwarf register emission of subregs/sequences This commit adds support for emitting subregisters and register sequences. This is needed for debugging -O1, since DIExpressions can now refer to these registers. Change-Id: Ic7b468a01855d3f8dc675dce4b2280625bf68574 This is the commit message #4: [SelectionDAG] Add debug info salvaging for bitcast operations This is needed to retain debug info for 64 bit kernel parameters. This is the commit message #5: [SROA] Fix DIOp-DIExpression fragment handling Change-Id: If1f73e941c227d74ebe563c2857f5df2d60e9225 Change-Id: Id3914345ef7a434355f36e45d3ea0bf6c7ae29aa
1 parent 27aaae0 commit b72d627

File tree

60 files changed

+19298
-18709
lines changed

Some content is hidden

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

60 files changed

+19298
-18709
lines changed

llvm/include/llvm/IR/DebugInfoMetadata.h

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3228,6 +3228,29 @@ class DIExpression : public MDNode {
32283228
static constexpr std::array<uint64_t, 1> PoisonedExpr = {
32293229
dwarf::DW_OP_LLVM_poisoned};
32303230

3231+
DIExpression *getPoisonedFragment(unsigned OffsetInBits,
3232+
unsigned SizeInBits) const {
3233+
std::array<uint64_t, 4> PoisonedOps = {dwarf::DW_OP_LLVM_poisoned,
3234+
dwarf::DW_OP_LLVM_fragment,
3235+
OffsetInBits, SizeInBits};
3236+
return DIExpression::get(getContext(), PoisonedOps);
3237+
}
3238+
3239+
OldElementsRef getPoisonedElements() const {
3240+
std::optional<FragmentInfo> Frag = getFragmentInfo();
3241+
if (!Frag)
3242+
return PoisonedExpr;
3243+
return getPoisonedFragment(Frag->OffsetInBits, Frag->SizeInBits)
3244+
->getElements();
3245+
}
3246+
3247+
DIExpression *getPoisoned() const {
3248+
std::optional<FragmentInfo> Frag = getFragmentInfo();
3249+
if (!Frag)
3250+
return DIExpression::get(getContext(), PoisonedExpr);
3251+
return getPoisonedFragment(Frag->OffsetInBits, Frag->SizeInBits);
3252+
}
3253+
32313254
DIExpression(LLVMContext &C, StorageType Storage, ArrayRef<uint64_t> Elements)
32323255
: MDNode(C, DIExpressionKind, Storage, std::nullopt),
32333256
Elements(std::in_place_type<OldElements>, Elements.begin(),
@@ -3264,17 +3287,12 @@ class DIExpression : public MDNode {
32643287
(bool /*ignored*/, ArrayRef<DIOp::Variant> Elements),
32653288
(false, Elements))
32663289

3267-
static DIExpression *getPoisoned(LLVMContext &Ctx) {
3268-
return get(Ctx, PoisonedExpr);
3269-
}
3270-
DIExpression *getPoisoned() const { return getPoisoned(getContext()); }
3271-
32723290
TempDIExpression clone() const { return cloneImpl(); }
32733291

32743292
OldElementsRef getElements() const {
32753293
if (auto *E = std::get_if<OldElements>(&Elements))
32763294
return *E;
3277-
return PoisonedExpr;
3295+
return getPoisonedElements();
32783296
}
32793297

32803298
unsigned getNumElements() const { return getElements().size(); }

llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp

Lines changed: 101 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -192,19 +192,25 @@ void DwarfExpression::addStackValue() {
192192
}
193193

194194
void DwarfExpression::addSignedConstant(int64_t Value) {
195+
if (IsPoisonedExpr)
196+
return;
195197
assert(isImplicitLocation() || isUnknownLocation());
196198
LocationKind = Implicit;
197199
emitOp(dwarf::DW_OP_consts);
198200
emitSigned(Value);
199201
}
200202

201203
void DwarfExpression::addUnsignedConstant(uint64_t Value) {
204+
if (IsPoisonedExpr)
205+
return;
202206
assert(isImplicitLocation() || isUnknownLocation());
203207
LocationKind = Implicit;
204208
emitConstu(Value);
205209
}
206210

207211
void DwarfExpression::addUnsignedConstant(const APInt &Value) {
212+
if (IsPoisonedExpr)
213+
return;
208214
assert(isImplicitLocation() || isUnknownLocation());
209215
LocationKind = Implicit;
210216

@@ -225,6 +231,8 @@ void DwarfExpression::addUnsignedConstant(const APInt &Value) {
225231
}
226232

227233
void DwarfExpression::addConstantFP(const APFloat &APF, const AsmPrinter &AP) {
234+
if (IsPoisonedExpr)
235+
return;
228236
assert(isImplicitLocation() || isUnknownLocation());
229237
APInt API = APF.bitcastToAPInt();
230238
int NumBytes = API.getBitWidth() / 8;
@@ -255,6 +263,8 @@ bool DwarfExpression::addMachineRegExpression(const TargetRegisterInfo &TRI,
255263
DIExpressionCursor &ExprCursor,
256264
llvm::Register MachineReg,
257265
unsigned FragmentOffsetInBits) {
266+
if (IsPoisonedExpr)
267+
return true;
258268
auto Fragment = ExprCursor.getFragmentInfo();
259269
if (!addMachineReg(TRI, MachineReg, Fragment ? Fragment->SizeInBits : ~1U)) {
260270
LocationKind = Unknown;
@@ -510,6 +520,8 @@ bool DwarfExpression::addExpression(
510520
// and not any other parts of the following DWARF expression.
511521
assert(!IsEmittingEntryValue && "Can't emit entry value around expression");
512522

523+
IsPoisonedExpr = false;
524+
513525
std::optional<DIExpression::ExprOperand> PrevConvertOp;
514526

515527
while (ExprCursor) {
@@ -529,7 +541,7 @@ bool DwarfExpression::addExpression(
529541
emitOp(dwarf::DW_OP_LLVM_user);
530542
emitOp(dwarf::DW_OP_LLVM_USER_undefined);
531543
LocationKind = Unknown;
532-
return true;
544+
break;
533545
case dwarf::DW_OP_LLVM_arg:
534546
if (!InsertArg(Op->getArg(0), ExprCursor)) {
535547
LocationKind = Unknown;
@@ -715,10 +727,22 @@ bool DwarfExpression::addExpression(
715727
void DwarfExpression::addExpression(DIExpression::NewElementsRef Expr,
716728
ArrayRef<DbgValueLocEntry> ArgLocEntries,
717729
const TargetRegisterInfo *TRI) {
730+
assert(!IsPoisonedExpr && "poisoned exprs should have old elements");
718731
this->ArgLocEntries = ArgLocEntries;
719732
this->TRI = TRI;
733+
std::optional<DIOp::Fragment> FragOp;
734+
for (DIOp::Variant Op : Expr) {
735+
if (auto *Frag = std::get_if<DIOp::Fragment>(&Op)) {
736+
FragOp = *Frag;
737+
IsFragment = true;
738+
break;
739+
}
740+
}
720741
buildAST(Expr);
721742
traverse(ASTRoot.get(), ValueKind::LocationDesc);
743+
if (FragOp)
744+
addOpPiece(FragOp->getBitSize());
745+
IsFragment = false;
722746
ASTRoot.reset();
723747
this->TRI = nullptr;
724748
this->ArgLocEntries = std::nullopt;
@@ -756,7 +780,13 @@ void DwarfExpression::finalize() {
756780
}
757781

758782
void DwarfExpression::addFragmentOffset(const DIExpression *Expr) {
759-
if (!Expr || !Expr->isFragment())
783+
if (!Expr)
784+
return;
785+
786+
if (Expr->holdsOldElements() && Expr->isPoisoned())
787+
IsPoisonedExpr = true;
788+
789+
if (!Expr->isFragment())
760790
return;
761791

762792
uint64_t FragmentOffset = Expr->getFragmentInfo()->OffsetInBits;
@@ -806,6 +836,8 @@ void DwarfExpression::emitLegacyZExt(unsigned FromBits) {
806836
}
807837

808838
void DwarfExpression::addWasmLocation(unsigned Index, uint64_t Offset) {
839+
if (IsPoisonedExpr)
840+
return;
809841
emitOp(dwarf::DW_OP_WASM_location);
810842
emitUnsigned(Index == 4/*TI_LOCAL_INDIRECT*/ ? 0/*TI_LOCAL*/ : Index);
811843
emitUnsigned(Offset);
@@ -912,16 +944,72 @@ std::optional<NewOpResult> DwarfExpression::traverse(DIOp::Arg Arg,
912944
}
913945

914946
if (Entry.isLocation()) {
915-
auto DWARFRegister = TRI->getDwarfRegNum(Entry.getLoc().getReg(), false);
916-
if (DWARFRegister < 0) {
947+
assert(DwarfRegs.empty() && "unconsumed registers?");
948+
if (!addMachineReg(*TRI, Entry.getLoc().getReg())) {
949+
DwarfRegs.clear();
917950
return std::nullopt;
918951
}
919-
addReg(DWARFRegister);
952+
953+
// addMachineReg sets DwarfRegs and SubRegister{Size,Offset}InBits. Collect
954+
// them here and reset the fields to avoid hitting any asserts.
955+
decltype(DwarfRegs) Regs;
956+
std::swap(Regs, DwarfRegs);
957+
unsigned SubRegOffset = SubRegisterOffsetInBits;
958+
unsigned SubRegSize = SubRegisterSizeInBits;
959+
SubRegisterOffsetInBits = SubRegisterSizeInBits = 0;
960+
if (SubRegOffset % 8 || SubRegSize % 8)
961+
return std::nullopt;
962+
SubRegOffset /= 8;
963+
SubRegSize /= 8;
964+
965+
if (Regs.size() == 1) {
966+
addReg(Regs[0].DwarfRegNo, Regs[0].Comment);
967+
968+
if (SubRegOffset) {
969+
emitUserOp(dwarf::DW_OP_LLVM_USER_offset_uconst);
970+
emitUnsigned(SubRegOffset);
971+
}
972+
973+
if (SubRegSize) {
974+
emitOp(dwarf::DW_OP_deref_size);
975+
emitData1(SubRegSize);
976+
return NewOpResult{Arg.getResultType(), ValueKind::Value};
977+
}
978+
979+
return NewOpResult{Arg.getResultType(), ValueKind::LocationDesc};
980+
}
981+
982+
assert(SubRegOffset == 0 && SubRegSize == 0 &&
983+
"register piece cannot apply to multiple registers");
984+
985+
// When emitting fragments, the top element on the stack might be an
986+
// incomplete composite. Push/drop a lit0 so that we don't add the registers
987+
// to the larger composite.
988+
if (IsFragment)
989+
emitOp(dwarf::DW_OP_lit0);
990+
991+
unsigned RegSize = 0;
992+
for (auto &Reg : Regs) {
993+
if (Reg.SubRegSize % 8)
994+
return std::nullopt;
995+
RegSize += Reg.SubRegSize;
996+
if (Reg.DwarfRegNo >= 0)
997+
addReg(Reg.DwarfRegNo, Reg.Comment);
998+
emitOp(dwarf::DW_OP_piece);
999+
emitUnsigned(Reg.SubRegSize / 8);
1000+
}
1001+
emitUserOp(dwarf::DW_OP_LLVM_USER_piece_end);
1002+
1003+
if (IsFragment) {
1004+
emitOp(dwarf::DW_OP_swap);
1005+
emitOp(dwarf::DW_OP_drop);
1006+
}
1007+
9201008
return NewOpResult{Arg.getResultType(), ValueKind::LocationDesc};
9211009
}
9221010

9231011
if (Entry.isInt()) {
924-
addUnsignedConstant(Entry.getInt());
1012+
emitConstu(Entry.getInt());
9251013
} else if (Entry.isConstantFP()) {
9261014
// DwarfExpression does not support arguments wider than 64 bits
9271015
// (see PR52584).
@@ -930,12 +1018,12 @@ std::optional<NewOpResult> DwarfExpression::traverse(DIOp::Arg Arg,
9301018
APInt RawBytes = Entry.getConstantFP()->getValueAPF().bitcastToAPInt();
9311019
if (RawBytes.getBitWidth() > 64)
9321020
return std::nullopt;
933-
addUnsignedConstant(RawBytes.getZExtValue());
1021+
emitConstu(RawBytes.getZExtValue());
9341022
} else if (Entry.isConstantInt()) {
9351023
APInt RawBytes = Entry.getConstantInt()->getValue();
9361024
if (RawBytes.getBitWidth() > 64)
9371025
return std::nullopt;
938-
addUnsignedConstant(RawBytes.getZExtValue());
1026+
emitConstu(RawBytes.getZExtValue());
9391027
} else if (Entry.isTargetIndexLocation()) {
9401028
return std::nullopt;
9411029
} else {
@@ -955,9 +1043,10 @@ std::optional<NewOpResult> DwarfExpression::traverse(DIOp::Constant Constant,
9551043
return std::nullopt;
9561044

9571045
if (isUnsigned(IntLiteralValue)) {
958-
addUnsignedConstant(IntLiteralValue->getZExtValue());
1046+
emitConstu(IntLiteralValue->getZExtValue());
9591047
} else {
960-
addSignedConstant(IntLiteralValue->getSExtValue());
1048+
emitOp(dwarf::DW_OP_consts);
1049+
emitSigned(IntLiteralValue->getSExtValue());
9611050
}
9621051

9631052
return NewOpResult{IntLiteralValue->getType(), ValueKind::Value};
@@ -1056,7 +1145,7 @@ std::optional<NewOpResult> DwarfExpression::traverse(DIOp::Deref Deref,
10561145

10571146
emitOp(dwarf::DW_OP_deref_size);
10581147
emitData1(PointerSizeInBytes);
1059-
addUnsignedConstant(*PointerDWARFAddrSpace);
1148+
emitConstu(*PointerDWARFAddrSpace);
10601149
emitUserOp(dwarf::DW_OP_LLVM_USER_form_aspace_address);
10611150

10621151
// FIXME(KZHURAVL): Is the following result type correct?
@@ -1153,7 +1242,7 @@ void DwarfExpression::readToValue(Type *Ty) {
11531242

11541243
if (NeedsMask) {
11551244
uint64_t Mask = (1ULL << PrimitiveSizeInBits) - 1ULL;
1156-
addUnsignedConstant(Mask);
1245+
emitConstu(Mask);
11571246
emitOp(dwarf::DW_OP_and);
11581247
}
11591248
}

llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,13 @@ class DwarfExpression {
361361
// the expression lowers as expected. If the lowering is not supported, it
362362
// is terminated by a DW_OP_LLVM_undefined operation.
363363
bool IsImplemented = true;
364+
bool IsFragment = false;
365+
366+
/// Set when emitting a fragment/non-fragment expression that contains a
367+
/// DW_OP_LLVM_poison operation. This matters for correctness in the fragment
368+
/// case, since we need to ensure that we don't add any registers or constants
369+
/// onto the stack. In the non-fragment case it's simply an optimization.
370+
bool IsPoisonedExpr = false;
364371

365372
void buildAST(DIExpression::NewElementsRef Elements);
366373

llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15402,8 +15402,10 @@ SDValue DAGCombiner::visitBITCAST(SDNode *N) {
1540215402
}
1540315403

1540415404
// (conv (conv x, t1), t2) -> (conv x, t2)
15405-
if (N0.getOpcode() == ISD::BITCAST)
15405+
if (N0.getOpcode() == ISD::BITCAST) {
15406+
DAG.salvageDebugInfo(*N0.getNode());
1540615407
return DAG.getBitcast(VT, N0.getOperand(0));
15408+
}
1540715409

1540815410
// fold (conv (logicop (conv x), (c))) -> (logicop x, (conv c))
1540915411
// iff the current bitwise logicop type isn't legal

llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11273,6 +11273,35 @@ void SelectionDAG::salvageDebugInfo(SDNode &N) {
1127311273
dbgs() << " into " << *DbgExpression << '\n');
1127411274
break;
1127511275
}
11276+
case ISD::BITCAST: {
11277+
DIExpression *Expr = DV->getExpression();
11278+
if (Expr->holdsOldElements())
11279+
break;
11280+
11281+
SDValue N0 = N.getOperand(0);
11282+
auto NewLocOps = DV->copyLocationOps();
11283+
bool Changed = false;
11284+
for (size_t i = 0; i < NewLocOps.size(); ++i) {
11285+
if (NewLocOps[i].getKind() != SDDbgOperand::SDNODE ||
11286+
NewLocOps[i].getSDNode() != &N)
11287+
continue;
11288+
NewLocOps[i] = SDDbgOperand::fromNode(N0.getNode(), N0.getResNo());
11289+
Changed = true;
11290+
}
11291+
assert(Changed && "Salvage target doesn't use N");
11292+
(void)Changed;
11293+
11294+
SDDbgValue *Clone =
11295+
getDbgValueList(DV->getVariable(), Expr, NewLocOps,
11296+
DV->getAdditionalDependencies(), DV->isIndirect(),
11297+
DV->getDebugLoc(), DV->getOrder(), DV->isVariadic());
11298+
ClonedDVs.push_back(Clone);
11299+
DV->setIsInvalidated();
11300+
DV->setIsEmitted();
11301+
LLVM_DEBUG(dbgs() << "SALVAGE: Rewriting"; N0.getNode()->dumprFull(this);
11302+
dbgs() << " into " << *Expr << '\n');
11303+
break;
11304+
}
1127611305
}
1127711306
}
1127811307

llvm/lib/IR/DebugInfoMetadata.cpp

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1386,6 +1386,28 @@ DIExpression *DIExpression::getImpl(LLVMContext &Context,
13861386
DIExpression *DIExpression::getImpl(LLVMContext &Context,
13871387
OldElementsRef Elements,
13881388
StorageType Storage, bool ShouldCreate) {
1389+
// If Elements is any expression containing DW_OP_LLVM_poisoned and an
1390+
// optional fragment then canonicalize, the other ops aren't doing anything.
1391+
SmallVector<uint64_t, 4> CanonicalizedPoisonOps;
1392+
for (unsigned Idx = 0; Idx < Elements.size();) {
1393+
ExprOperand Op(&Elements[Idx]);
1394+
1395+
if (CanonicalizedPoisonOps.empty()) {
1396+
if (Op.getOp() == dwarf::DW_OP_LLVM_poisoned)
1397+
CanonicalizedPoisonOps.push_back(Op.getOp());
1398+
} else if (Op.getOp() == dwarf::DW_OP_LLVM_fragment &&
1399+
Idx + 2 < Elements.size()) {
1400+
CanonicalizedPoisonOps.push_back(Op.getOp());
1401+
CanonicalizedPoisonOps.push_back(Op.getArg(0));
1402+
CanonicalizedPoisonOps.push_back(Op.getArg(1));
1403+
}
1404+
1405+
// Have to handle invalid exprs.
1406+
Idx += Op.getSize();
1407+
}
1408+
if (!CanonicalizedPoisonOps.empty())
1409+
Elements = CanonicalizedPoisonOps;
1410+
13891411
DEFINE_GETIMPL_LOOKUP(DIExpression, (Elements));
13901412
DEFINE_GETIMPL_STORE_NO_OPS(DIExpression, (Elements));
13911413
}
@@ -2368,13 +2390,6 @@ std::optional<DIExpression *> DIExpression::createFragmentExpression(
23682390
if (Expr->holdsNewElements())
23692391
return createNewFragmentExpression(Expr, OffsetInBits, SizeInBits);
23702392

2371-
// FIXME(diexpression-poison): Is it safe to handle each fragment
2372-
// independently? If a fragment gets poisoned we lose the fragment info, so
2373-
// can't locate it correctly. Conservatively we can just have it cover the
2374-
// whole variable.
2375-
if (Expr->isPoisoned())
2376-
return Expr->getPoisoned();
2377-
23782393
SmallVector<uint64_t, 8> Ops;
23792394
// Track whether it's safe to split the value at the top of the DWARF stack,
23802395
// assuming that it'll be used as an implicit location value.

0 commit comments

Comments
 (0)