Skip to content

Commit ee7f6a5

Browse files
authored
[KeyInstr] Merge atoms in DILocation::getMergedLocation (#133480)
NFC for builds with LLVM_EXPERIMENTAL_KEY_INSTRUCTIONS=OFF (default). In an ideal world we would be able to track that the merged location is used in multiple source atoms. We can't do this though, so instead we arbitrarily but deterministically pick one. In cases where the InlinedAt field is unchanged we keep the atom with the lowest non-zero rank (highest precedence). If the ranks are equal we choose the smaller non-zero group number (arbitrary choice). In cases where the InlinedAt field is adjusted we generate a new atom group. Keeping the group wouldn't make sense (a source atom is identified by the group number and InlinedAt pair) but discarding the atom info could result in missed is_stmts. Add unittest in MetadataTest.cpp. RFC: https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668
1 parent e8adb3a commit ee7f6a5

File tree

2 files changed

+206
-6
lines changed

2 files changed

+206
-6
lines changed

llvm/lib/IR/DebugInfoMetadata.cpp

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -306,11 +306,15 @@ DILocation *DILocation::getMergedLocation(DILocation *LocA, DILocation *LocB) {
306306

307307
// Merge the two locations if possible, using the supplied
308308
// inlined-at location for the created location.
309-
auto MergeLocPair = [&C](const DILocation *L1, const DILocation *L2,
310-
DILocation *InlinedAt) -> DILocation * {
309+
auto *LocAIA = LocA->getInlinedAt();
310+
auto *LocBIA = LocB->getInlinedAt();
311+
auto MergeLocPair = [&C, LocAIA,
312+
LocBIA](const DILocation *L1, const DILocation *L2,
313+
DILocation *InlinedAt) -> DILocation * {
311314
if (L1 == L2)
312315
return DILocation::get(C, L1->getLine(), L1->getColumn(), L1->getScope(),
313-
InlinedAt);
316+
InlinedAt, L1->isImplicitCode(),
317+
L1->getAtomGroup(), L1->getAtomRank());
314318

315319
// If the locations originate from different subprograms we can't produce
316320
// a common location.
@@ -346,8 +350,47 @@ DILocation *DILocation::getMergedLocation(DILocation *LocA, DILocation *LocB) {
346350
bool SameCol = L1->getColumn() == L2->getColumn();
347351
unsigned Line = SameLine ? L1->getLine() : 0;
348352
unsigned Col = SameLine && SameCol ? L1->getColumn() : 0;
349-
350-
return DILocation::get(C, Line, Col, Scope, InlinedAt);
353+
bool IsImplicitCode = L1->isImplicitCode() && L2->isImplicitCode();
354+
355+
// Discard source location atom if the line becomes 0. And there's nothing
356+
// further to do if neither location has an atom number.
357+
if (!SameLine || !(L1->getAtomGroup() || L2->getAtomGroup()))
358+
return DILocation::get(C, Line, Col, Scope, InlinedAt, IsImplicitCode,
359+
/*AtomGroup*/ 0, /*AtomRank*/ 0);
360+
361+
uint64_t Group = 0;
362+
uint64_t Rank = 0;
363+
// If we're preserving the same matching inlined-at field we can
364+
// preserve the atom.
365+
if (LocBIA == LocAIA && InlinedAt == LocBIA) {
366+
// Deterministically keep the lowest non-zero ranking atom group
367+
// number.
368+
// FIXME: It would be nice if we could track that an instruction
369+
// belongs to two source atoms.
370+
bool UseL1Atom = [L1, L2]() {
371+
if (L1->getAtomRank() == L2->getAtomRank()) {
372+
// Arbitrarily choose the lowest non-zero group number.
373+
if (!L1->getAtomGroup() || !L2->getAtomGroup())
374+
return !L2->getAtomGroup();
375+
return L1->getAtomGroup() < L2->getAtomGroup();
376+
}
377+
// Choose the lowest non-zero rank.
378+
if (!L1->getAtomRank() || !L2->getAtomRank())
379+
return !L2->getAtomRank();
380+
return L1->getAtomRank() < L2->getAtomRank();
381+
}();
382+
Group = UseL1Atom ? L1->getAtomGroup() : L2->getAtomGroup();
383+
Rank = UseL1Atom ? L1->getAtomRank() : L2->getAtomRank();
384+
} else {
385+
// If either instruction is part of a source atom, reassign it a new
386+
// atom group. This essentially regresses to non-key-instructions
387+
// behaviour (now that it's the only instruction in its group it'll
388+
// probably get is_stmt applied).
389+
Group = C.incNextDILocationAtomGroup();
390+
Rank = 1;
391+
}
392+
return DILocation::get(C, Line, Col, Scope, InlinedAt, IsImplicitCode,
393+
Group, Rank);
351394
};
352395

353396
DILocation *Result = ARIt != ALocs.rend() ? (*ARIt)->getInlinedAt() : nullptr;
@@ -374,7 +417,10 @@ DILocation *DILocation::getMergedLocation(DILocation *LocA, DILocation *LocB) {
374417
// historically picked A's scope, and a nullptr inlined-at location, so that
375418
// behavior is mimicked here but I am not sure if this is always the correct
376419
// way to handle this.
377-
return DILocation::get(C, 0, 0, LocA->getScope(), nullptr);
420+
// Key Instructions: it's fine to drop atom group and rank here, as line 0
421+
// is a nonsensical is_stmt location.
422+
return DILocation::get(C, 0, 0, LocA->getScope(), nullptr, false,
423+
/*AtomGroup*/ 0, /*AtomRank*/ 0);
378424
}
379425

380426
std::optional<unsigned>

llvm/unittests/IR/MetadataTest.cpp

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,6 +1468,160 @@ TEST_F(DILocationTest, Merge) {
14681468
EXPECT_EQ(N, M2->getScope());
14691469
PickMergedSourceLocations = false;
14701470
}
1471+
1472+
#ifdef EXPERIMENTAL_KEY_INSTRUCTIONS
1473+
#define EXPECT_ATOM(Loc, Group, Rank) \
1474+
EXPECT_EQ(Group, M->getAtomGroup()); \
1475+
EXPECT_EQ(Rank, M->getAtomRank());
1476+
#else
1477+
#define EXPECT_ATOM(Loc, Group, Rank) \
1478+
EXPECT_EQ(0u, M->getAtomGroup()); \
1479+
EXPECT_EQ(0u, M->getAtomRank()); \
1480+
(void)Group; \
1481+
(void)Rank;
1482+
#endif
1483+
// Identical, including source atom numbers.
1484+
{
1485+
auto *A = DILocation::get(Context, 2, 7, N, nullptr, false, /*AtomGroup*/ 1,
1486+
/*AtomRank*/ 1);
1487+
auto *B = DILocation::get(Context, 2, 7, N, nullptr, false, /*AtomGroup*/ 1,
1488+
/*AtomRank*/ 1);
1489+
auto *M = DILocation::getMergedLocation(A, B);
1490+
EXPECT_ATOM(M, /*AtomGroup*/ 1u, 1u);
1491+
// DILocations are uniqued, so we can check equality by ptr.
1492+
EXPECT_EQ(M, DILocation::getMergedLocation(A, B));
1493+
}
1494+
1495+
// Identical but different atom ranks (same atom) - choose the lowest nonzero
1496+
// rank.
1497+
{
1498+
auto *A = DILocation::get(Context, 2, 7, N, nullptr, false, /*AtomGroup*/ 1,
1499+
/*AtomRank*/ 1);
1500+
auto *B = DILocation::get(Context, 2, 7, N, nullptr, false, /*AtomGroup*/ 1,
1501+
/*AtomRank*/ 2);
1502+
auto *M = DILocation::getMergedLocation(A, B);
1503+
EXPECT_ATOM(M, /*AtomGroup*/ 1u, /*AtomRank*/ 1u);
1504+
EXPECT_EQ(M, DILocation::getMergedLocation(B, A));
1505+
1506+
A = DILocation::get(Context, 2, 7, N, nullptr, false, /*AtomGroup*/ 1,
1507+
/*AtomRank*/ 0);
1508+
B = DILocation::get(Context, 2, 7, N, nullptr, false, /*AtomGroup*/ 1,
1509+
/*AtomRank*/ 2);
1510+
M = DILocation::getMergedLocation(A, B);
1511+
EXPECT_ATOM(M, /*AtomGroup*/ 1u, /*AtomRank*/ 2u);
1512+
EXPECT_EQ(M, DILocation::getMergedLocation(B, A));
1513+
}
1514+
1515+
// Identical but different atom ranks (different atom) - choose the lowest
1516+
// nonzero rank.
1517+
{
1518+
auto *A = DILocation::get(Context, 2, 7, N, nullptr, false, /*AtomGroup*/ 1,
1519+
/*AtomRank*/ 1);
1520+
auto *B = DILocation::get(Context, 2, 7, N, nullptr, false, /*AtomGroup*/ 2,
1521+
/*AtomRank*/ 2);
1522+
auto *M = DILocation::getMergedLocation(A, B);
1523+
EXPECT_ATOM(M, 1u, 1u);
1524+
EXPECT_EQ(M, DILocation::getMergedLocation(B, A));
1525+
1526+
A = DILocation::get(Context, 2, 7, N, nullptr, false, /*AtomGroup*/ 1,
1527+
/*AtomRank*/ 0);
1528+
B = DILocation::get(Context, 2, 7, N, nullptr, false, /*AtomGroup*/ 2,
1529+
/*AtomRank*/ 2);
1530+
M = DILocation::getMergedLocation(A, B);
1531+
EXPECT_ATOM(M, /*AtomGroup*/ 2u, /*AtomRank*/ 2u);
1532+
EXPECT_EQ(M, DILocation::getMergedLocation(B, A));
1533+
}
1534+
1535+
// Identical but equal atom rank (different atom) - choose the lowest non-zero
1536+
// group (arbitrary choice for deterministic behaviour).
1537+
{
1538+
auto *A = DILocation::get(Context, 2, 7, N, nullptr, false, /*AtomGroup*/ 1,
1539+
/*AtomRank*/ 1);
1540+
auto *B = DILocation::get(Context, 2, 7, N, nullptr, false, /*AtomGroup*/ 2,
1541+
/*AtomRank*/ 1);
1542+
auto *M = DILocation::getMergedLocation(A, B);
1543+
EXPECT_ATOM(M, 1u, 1u);
1544+
EXPECT_EQ(M, DILocation::getMergedLocation(B, A));
1545+
1546+
A = DILocation::get(Context, 2, 7, N, nullptr, false, /*AtomGroup*/ 0,
1547+
/*AtomRank*/ 1);
1548+
B = DILocation::get(Context, 2, 7, N, nullptr, false, /*AtomGroup*/ 2,
1549+
/*AtomRank*/ 1);
1550+
M = DILocation::getMergedLocation(A, B);
1551+
EXPECT_ATOM(M, /*AtomGroup*/ 2u, /*AtomRank*/ 1u);
1552+
EXPECT_EQ(M, DILocation::getMergedLocation(B, A));
1553+
}
1554+
1555+
// Completely different except same atom numbers. Zero out the atoms.
1556+
{
1557+
auto *I = DILocation::get(Context, 2, 7, N);
1558+
auto *A = DILocation::get(Context, 1, 6, S, I, false, /*AtomGroup*/ 1,
1559+
/*AtomRank*/ 1);
1560+
auto *B = DILocation::get(Context, 2, 7, getSubprogram(), nullptr, false,
1561+
/*AtomGroup*/ 1, /*AtomRank*/ 1);
1562+
auto *M = DILocation::getMergedLocation(A, B);
1563+
EXPECT_EQ(0u, M->getLine());
1564+
EXPECT_EQ(0u, M->getColumn());
1565+
EXPECT_TRUE(isa<DILocalScope>(M->getScope()));
1566+
EXPECT_EQ(S, M->getScope());
1567+
EXPECT_EQ(nullptr, M->getInlinedAt());
1568+
}
1569+
1570+
// Same inlined-at chain but different atoms. Choose the lowest
1571+
// non-zero group (arbitrary choice for deterministic behaviour).
1572+
{
1573+
auto *I = DILocation::get(Context, 1, 7, N);
1574+
auto *F = getSubprogram();
1575+
auto *A = DILocation::get(Context, 1, 1, F, I, false, /*AtomGroup*/ 1,
1576+
/*AtomRank*/ 2);
1577+
auto *B = DILocation::get(Context, 1, 1, F, I, false, /*AtomGroup*/ 2,
1578+
/*AtomRank*/ 2);
1579+
auto *M = DILocation::getMergedLocation(A, B);
1580+
EXPECT_ATOM(M, /*AtomGroup*/ 1u, /*AtomRank*/ 2u);
1581+
EXPECT_EQ(M, DILocation::getMergedLocation(B, A));
1582+
1583+
A = DILocation::get(Context, 1, 1, F, I, false, /*AtomGroup*/ 1,
1584+
/*AtomRank*/ 2);
1585+
B = DILocation::get(Context, 1, 1, F, I, false, /*AtomGroup*/ 2,
1586+
/*AtomRank*/ 0);
1587+
M = DILocation::getMergedLocation(A, B);
1588+
EXPECT_ATOM(M, /*AtomGroup*/ 1u, /*AtomRank*/ 2u);
1589+
EXPECT_EQ(M, DILocation::getMergedLocation(B, A));
1590+
}
1591+
1592+
// Partially equal inlined-at chain but different atoms. Generate a new atom
1593+
// group (if either have a group number). This configuration seems unlikely
1594+
// to occur as line numbers must match, but isn't impossible.
1595+
{
1596+
// Reset global counter to ensure EXPECT numbers line up.
1597+
Context.pImpl->NextAtomGroup = 1;
1598+
// x1 -> y2 -> z4
1599+
// y3 -> z4
1600+
auto *FX = getSubprogram();
1601+
auto *FY = getSubprogram();
1602+
auto *FZ = getSubprogram();
1603+
auto *Z4 = DILocation::get(Context, 1, 4, FZ);
1604+
auto *Y3IntoZ4 = DILocation::get(Context, 1, 3, FY, Z4, false,
1605+
/*AtomGroup*/ 1, /*AtomRank*/ 1);
1606+
auto *Y2IntoZ4 = DILocation::get(Context, 1, 2, FY, Z4);
1607+
auto *X1IntoY2 = DILocation::get(Context, 1, 1, FX, Y2IntoZ4);
1608+
auto *M = DILocation::getMergedLocation(X1IntoY2, Y3IntoZ4);
1609+
EXPECT_EQ(M->getScope(), FY);
1610+
EXPECT_EQ(M->getInlinedAt()->getScope(), FZ);
1611+
EXPECT_ATOM(M, /*AtomGroup*/ 2u, /*AtomRank*/ 1u);
1612+
1613+
// This swapped merge will produce a new atom group too.
1614+
M = DILocation::getMergedLocation(Y3IntoZ4, X1IntoY2);
1615+
1616+
// Same again, even if the atom numbers match.
1617+
auto *X1IntoY2SameAtom = DILocation::get(Context, 1, 1, FX, Y2IntoZ4, false,
1618+
/*AtomGroup*/ 1, /*AtomRank*/ 1);
1619+
M = DILocation::getMergedLocation(X1IntoY2SameAtom, Y3IntoZ4);
1620+
EXPECT_ATOM(M, /*AtomGroup*/ 4u, /*AtomRank*/ 1u);
1621+
M = DILocation::getMergedLocation(Y3IntoZ4, X1IntoY2SameAtom);
1622+
EXPECT_ATOM(M, /*AtomGroup*/ 5u, /*AtomRank*/ 1u);
1623+
}
1624+
#undef EXPECT_ATOM
14711625
}
14721626

14731627
TEST_F(DILocationTest, getDistinct) {

0 commit comments

Comments
 (0)