Skip to content

Commit 2ecaf93

Browse files
committed
[LiveDebugValues] Speed up removeEntryValue, NFC
Summary: Instead of iterating over all VarLoc IDs in removeEntryValue(), just iterate over the interval reserved for entry value VarLocs. This changes the iteration order, hence the test update -- otherwise this is NFC. This appears to give an ~8.5x wall time speed-up for LiveDebugValues when compiling sqlite3.c 3.30.1 with a Release clang (on my machine): ``` ---User Time--- --System Time-- --User+System-- ---Wall Time--- --- Name --- Before: 2.5402 ( 18.8%) 0.0050 ( 0.4%) 2.5452 ( 17.3%) 2.5452 ( 17.3%) Live DEBUG_VALUE analysis After: 0.2364 ( 2.1%) 0.0034 ( 0.3%) 0.2399 ( 2.0%) 0.2398 ( 2.0%) Live DEBUG_VALUE analysis ``` The change in removeEntryValue() is the only one that appears to affect wall time, but for consistency (and to resolve a pending TODO), I made the analogous changes for iterating over SpillLocKind VarLocs. Reviewers: nikic, aprantl, jmorse, djtodoro Subscribers: hiraditya, dexonsmith, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D80684
1 parent 836c7dc commit 2ecaf93

File tree

4 files changed

+170
-29
lines changed

4 files changed

+170
-29
lines changed

llvm/include/llvm/ADT/CoalescingBitVector.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "llvm/ADT/IntervalMap.h"
1818
#include "llvm/ADT/SmallVector.h"
19+
#include "llvm/ADT/iterator_range.h"
1920
#include "llvm/Support/Debug.h"
2021
#include "llvm/Support/raw_ostream.h"
2122

@@ -352,6 +353,19 @@ template <typename IndexT, unsigned N = 16> class CoalescingBitVector {
352353
return It;
353354
}
354355

356+
/// Return a range iterator which iterates over all of the set bits in the
357+
/// half-open range [Start, End).
358+
iterator_range<const_iterator> half_open_range(IndexT Start,
359+
IndexT End) const {
360+
assert(Start < End && "Not a valid range");
361+
auto StartIt = find(Start);
362+
if (StartIt == end() || *StartIt >= End)
363+
return {end(), end()};
364+
auto EndIt = StartIt;
365+
EndIt.advanceToLowerBound(End);
366+
return {StartIt, EndIt};
367+
}
368+
355369
void print(raw_ostream &OS) const {
356370
OS << "{";
357371
for (auto It = Intervals.begin(), End = Intervals.end(); It != End;

llvm/lib/CodeGen/LiveDebugValues.cpp

Lines changed: 98 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -137,16 +137,24 @@ using VarLocSet = CoalescingBitVector<uint64_t>;
137137
/// Why encode a location /into/ the VarLocMap index? This makes it possible
138138
/// to find the open VarLocs killed by a register def very quickly. This is a
139139
/// performance-critical operation for LiveDebugValues.
140-
///
141-
/// TODO: Consider adding reserved intervals for kinds of VarLocs other than
142-
/// RegisterKind, like SpillLocKind or EntryValueKind, to optimize iteration
143-
/// over open locations.
144140
struct LocIndex {
145141
uint32_t Location; // Physical registers live in the range [1;2^30) (see
146142
// \ref MCRegister), so we have plenty of range left here
147143
// to encode non-register locations.
148144
uint32_t Index;
149145

146+
/// The first location greater than 0 that is not reserved for VarLocs of
147+
/// kind RegisterKind.
148+
static constexpr uint32_t kFirstInvalidRegLocation = 1 << 30;
149+
150+
/// A special location reserved for VarLocs of kind SpillLocKind.
151+
static constexpr uint32_t kSpillLocation = kFirstInvalidRegLocation;
152+
153+
/// A special location reserved for VarLocs of kind EntryValueBackupKind and
154+
/// EntryValueCopyBackupKind.
155+
static constexpr uint32_t kEntryValueBackupLocation =
156+
kFirstInvalidRegLocation + 1;
157+
150158
LocIndex(uint32_t Location, uint32_t Index)
151159
: Location(Location), Index(Index) {}
152160

@@ -166,6 +174,14 @@ struct LocIndex {
166174
static uint64_t rawIndexForReg(uint32_t Reg) {
167175
return LocIndex(Reg, 0).getAsRawInteger();
168176
}
177+
178+
/// Return a range covering all set indices in the interval reserved for
179+
/// \p Location in \p Set.
180+
static auto indexRangeForLocation(const VarLocSet &Set, uint32_t Location) {
181+
uint64_t Start = LocIndex(Location, 0).getAsRawInteger();
182+
uint64_t End = LocIndex(Location + 1, 0).getAsRawInteger();
183+
return Set.half_open_range(Start, End);
184+
}
169185
};
170186

171187
class LiveDebugValues : public MachineFunctionPass {
@@ -211,6 +227,9 @@ class LiveDebugValues : public MachineFunctionPass {
211227
bool operator==(const SpillLoc &Other) const {
212228
return SpillBase == Other.SpillBase && SpillOffset == Other.SpillOffset;
213229
}
230+
bool operator!=(const SpillLoc &Other) const {
231+
return !(*this == Other);
232+
}
214233
};
215234

216235
/// Identity of the variable at this location.
@@ -477,10 +496,27 @@ class LiveDebugValues : public MachineFunctionPass {
477496
/// location.
478497
SmallDenseMap<uint32_t, std::vector<VarLoc>> Loc2Vars;
479498

499+
/// Determine the 32-bit location reserved for \p VL, based on its kind.
500+
static uint32_t getLocationForVar(const VarLoc &VL) {
501+
switch (VL.Kind) {
502+
case VarLoc::RegisterKind:
503+
assert((VL.Loc.RegNo < LocIndex::kFirstInvalidRegLocation) &&
504+
"Physreg out of range?");
505+
return VL.Loc.RegNo;
506+
case VarLoc::SpillLocKind:
507+
return LocIndex::kSpillLocation;
508+
case VarLoc::EntryValueBackupKind:
509+
case VarLoc::EntryValueCopyBackupKind:
510+
return LocIndex::kEntryValueBackupLocation;
511+
default:
512+
return 0;
513+
}
514+
}
515+
480516
public:
481517
/// Retrieve a unique LocIndex for \p VL.
482518
LocIndex insert(const VarLoc &VL) {
483-
uint32_t Location = VL.isDescribedByReg();
519+
uint32_t Location = getLocationForVar(VL);
484520
uint32_t &Index = Var2Index[VL];
485521
if (!Index) {
486522
auto &Vars = Loc2Vars[Location];
@@ -577,6 +613,30 @@ class LiveDebugValues : public MachineFunctionPass {
577613
"open ranges are inconsistent");
578614
return VarLocs.empty();
579615
}
616+
617+
/// Get an empty range of VarLoc IDs.
618+
auto getEmptyVarLocRange() const {
619+
return iterator_range<VarLocSet::const_iterator>(getVarLocs().end(),
620+
getVarLocs().end());
621+
}
622+
623+
/// Get all set IDs for VarLocs of kind RegisterKind in \p Reg.
624+
auto getRegisterVarLocs(Register Reg) const {
625+
return LocIndex::indexRangeForLocation(getVarLocs(), Reg);
626+
}
627+
628+
/// Get all set IDs for VarLocs of kind SpillLocKind.
629+
auto getSpillVarLocs() const {
630+
return LocIndex::indexRangeForLocation(getVarLocs(),
631+
LocIndex::kSpillLocation);
632+
}
633+
634+
/// Get all set IDs for VarLocs of kind EntryValueBackupKind or
635+
/// EntryValueCopyBackupKind.
636+
auto getEntryValueBackupVarLocs() const {
637+
return LocIndex::indexRangeForLocation(
638+
getVarLocs(), LocIndex::kEntryValueBackupLocation);
639+
}
580640
};
581641

582642
/// Collect all VarLoc IDs from \p CollectFrom for VarLocs of kind
@@ -821,7 +881,10 @@ void LiveDebugValues::getUsedRegs(const VarLocSet &CollectFrom,
821881
// All register-based VarLocs are assigned indices greater than or equal to
822882
// FirstRegIndex.
823883
uint64_t FirstRegIndex = LocIndex::rawIndexForReg(1);
824-
for (auto It = CollectFrom.find(FirstRegIndex), End = CollectFrom.end();
884+
uint64_t FirstInvalidIndex =
885+
LocIndex::rawIndexForReg(LocIndex::kFirstInvalidRegLocation);
886+
for (auto It = CollectFrom.find(FirstRegIndex),
887+
End = CollectFrom.find(FirstInvalidIndex);
825888
It != End;) {
826889
// We found a VarLoc ID for a VarLoc that lives in a register. Figure out
827890
// which register and add it to UsedRegs.
@@ -924,11 +987,8 @@ bool LiveDebugValues::removeEntryValue(const MachineInstr &MI,
924987
}
925988

926989
if (TrySalvageEntryValue) {
927-
for (uint64_t ID : OpenRanges.getVarLocs()) {
990+
for (uint64_t ID : OpenRanges.getEntryValueBackupVarLocs()) {
928991
const VarLoc &VL = VarLocIDs[LocIndex::fromRawInteger(ID)];
929-
if (!VL.isEntryBackupLoc())
930-
continue;
931-
932992
if (VL.getEntryValueCopyBackupReg() == Reg &&
933993
VL.MI.getOperand(0).getReg() == SrcRegOp->getReg())
934994
return false;
@@ -1259,10 +1319,11 @@ void LiveDebugValues::transferSpillOrRestoreInst(MachineInstr &MI,
12591319
VarLocSet KillSet(Alloc);
12601320
if (isSpillInstruction(MI, MF)) {
12611321
Loc = extractSpillBaseRegAndOffset(MI);
1262-
for (uint64_t ID : OpenRanges.getVarLocs()) {
1322+
for (uint64_t ID : OpenRanges.getSpillVarLocs()) {
12631323
LocIndex Idx = LocIndex::fromRawInteger(ID);
12641324
const VarLoc &VL = VarLocIDs[Idx];
1265-
if (VL.Kind == VarLoc::SpillLocKind && VL.Loc.SpillLocation == *Loc) {
1325+
assert(VL.Kind == VarLoc::SpillLocKind && "Broken VarLocSet?");
1326+
if (VL.Loc.SpillLocation == *Loc) {
12661327
// This location is overwritten by the current instruction -- terminate
12671328
// the open range, and insert an explicit DBG_VALUE $noreg.
12681329
//
@@ -1298,21 +1359,31 @@ void LiveDebugValues::transferSpillOrRestoreInst(MachineInstr &MI,
12981359
<< "\n");
12991360
}
13001361
// Check if the register or spill location is the location of a debug value.
1301-
for (uint64_t ID : OpenRanges.getVarLocs()) {
1362+
auto TransferCandidates = OpenRanges.getEmptyVarLocRange();
1363+
if (TKind == TransferKind::TransferSpill)
1364+
TransferCandidates = OpenRanges.getRegisterVarLocs(Reg);
1365+
else if (TKind == TransferKind::TransferRestore)
1366+
TransferCandidates = OpenRanges.getSpillVarLocs();
1367+
for (uint64_t ID : TransferCandidates) {
13021368
LocIndex Idx = LocIndex::fromRawInteger(ID);
13031369
const VarLoc &VL = VarLocIDs[Idx];
1304-
if (TKind == TransferKind::TransferSpill && VL.isDescribedByReg() == Reg) {
1370+
if (TKind == TransferKind::TransferSpill) {
1371+
assert(VL.isDescribedByReg() == Reg && "Broken VarLocSet?");
13051372
LLVM_DEBUG(dbgs() << "Spilling Register " << printReg(Reg, TRI) << '('
13061373
<< VL.Var.getVariable()->getName() << ")\n");
1307-
} else if (TKind == TransferKind::TransferRestore &&
1308-
VL.Kind == VarLoc::SpillLocKind &&
1309-
VL.Loc.SpillLocation == *Loc) {
1374+
} else {
1375+
assert(TKind == TransferKind::TransferRestore &&
1376+
VL.Kind == VarLoc::SpillLocKind && "Broken VarLocSet?");
1377+
if (VL.Loc.SpillLocation != *Loc)
1378+
// The spill location is not the location of a debug value.
1379+
continue;
13101380
LLVM_DEBUG(dbgs() << "Restoring Register " << printReg(Reg, TRI) << '('
13111381
<< VL.Var.getVariable()->getName() << ")\n");
1312-
} else
1313-
continue;
1382+
}
13141383
insertTransferDebugPair(MI, OpenRanges, Transfers, VarLocIDs, Idx, TKind,
13151384
Reg);
1385+
// FIXME: A comment should explain why it's correct to return early here,
1386+
// if that is in fact correct.
13161387
return;
13171388
}
13181389
}
@@ -1356,7 +1427,7 @@ void LiveDebugValues::transferRegisterCopy(MachineInstr &MI,
13561427
// a parameter describing only a moving of the value around, rather then
13571428
// modifying it, we are still able to use the entry value if needed.
13581429
if (isRegOtherThanSPAndFP(*DestRegOp, MI, TRI)) {
1359-
for (uint64_t ID : OpenRanges.getVarLocs()) {
1430+
for (uint64_t ID : OpenRanges.getEntryValueBackupVarLocs()) {
13601431
LocIndex Idx = LocIndex::fromRawInteger(ID);
13611432
const VarLoc &VL = VarLocIDs[Idx];
13621433
if (VL.getEntryValueBackupReg() == SrcReg) {
@@ -1378,13 +1449,14 @@ void LiveDebugValues::transferRegisterCopy(MachineInstr &MI,
13781449
if (!SrcRegOp->isKill())
13791450
return;
13801451

1381-
for (uint64_t ID : OpenRanges.getVarLocs()) {
1452+
for (uint64_t ID : OpenRanges.getRegisterVarLocs(SrcReg)) {
13821453
LocIndex Idx = LocIndex::fromRawInteger(ID);
1383-
if (VarLocIDs[Idx].isDescribedByReg() == SrcReg) {
1384-
insertTransferDebugPair(MI, OpenRanges, Transfers, VarLocIDs, Idx,
1385-
TransferKind::TransferCopy, DestReg);
1386-
return;
1387-
}
1454+
assert(VarLocIDs[Idx].isDescribedByReg() == SrcReg && "Broken VarLocSet?");
1455+
insertTransferDebugPair(MI, OpenRanges, Transfers, VarLocIDs, Idx,
1456+
TransferKind::TransferCopy, DestReg);
1457+
// FIXME: A comment should explain why it's correct to return early here,
1458+
// if that is in fact correct.
1459+
return;
13881460
}
13891461
}
13901462

llvm/test/DebugInfo/MIR/X86/entry-values-diamond-bbs.mir

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
# CHECK-NEXT: $ebx = MOV32ri 2
2424
# CHECK-NEXT: DBG_VALUE $esi, $noreg, ![[ARG_B]], !DIExpression(DW_OP_LLVM_entry_value, 1)
2525
# CHECK: bb.3.if.end
26-
# CHECK-NEXT: DBG_VALUE $edx, $noreg, ![[ARG_Q]], !DIExpression()
27-
# CHECK-NEXT: DBG_VALUE $ebp, $noreg, ![[ARG_C]], !DIExpression()
28-
# CHECK-NEXT: DBG_VALUE $esi, $noreg, ![[ARG_B]], !DIExpression(DW_OP_LLVM_entry_value, 1)
26+
# CHECK-DAG: DBG_VALUE $edx, $noreg, ![[ARG_Q]], !DIExpression()
27+
# CHECK-DAG: DBG_VALUE $ebp, $noreg, ![[ARG_C]], !DIExpression()
28+
# CHECK-DAG: DBG_VALUE $esi, $noreg, ![[ARG_B]], !DIExpression(DW_OP_LLVM_entry_value, 1)
2929
--- |
3030
; ModuleID = 'test.c'
3131
source_filename = "test.c"

llvm/unittests/ADT/CoalescingBitVectorTest.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ bool elementsMatch(const UBitVec &BV, std::initializer_list<unsigned> List) {
3131
return true;
3232
}
3333

34+
bool rangesMatch(iterator_range<UBitVec::const_iterator> R,
35+
std::initializer_list<unsigned> List) {
36+
return std::equal(R.begin(), R.end(), List.begin(), List.end());
37+
}
38+
3439
TEST(CoalescingBitVectorTest, Set) {
3540
UBitVec::Allocator Alloc;
3641
UBitVec BV1(Alloc);
@@ -486,6 +491,56 @@ TEST(CoalescingBitVectorTest, AdvanceToLowerBound) {
486491
EXPECT_TRUE(It == BV.end());
487492
}
488493

494+
TEST(CoalescingBitVectorTest, HalfOpenRange) {
495+
UBitVec::Allocator Alloc;
496+
497+
{
498+
UBitVec BV(Alloc);
499+
BV.set({1, 2, 3});
500+
501+
EXPECT_EQ(*BV.find(0), 1U); // find(Start) > Start
502+
EXPECT_TRUE(rangesMatch(BV.half_open_range(0, 5), {1, 2, 3}));
503+
EXPECT_TRUE(rangesMatch(BV.half_open_range(1, 4), {1, 2, 3}));
504+
EXPECT_TRUE(rangesMatch(BV.half_open_range(1, 3), {1, 2}));
505+
EXPECT_TRUE(rangesMatch(BV.half_open_range(2, 3), {2}));
506+
EXPECT_TRUE(rangesMatch(BV.half_open_range(2, 4), {2, 3}));
507+
EXPECT_TRUE(rangesMatch(BV.half_open_range(4, 5), {}));
508+
}
509+
510+
{
511+
UBitVec BV(Alloc);
512+
BV.set({1, 2, 11, 12});
513+
514+
EXPECT_TRUE(rangesMatch(BV.half_open_range(0, 15), {1, 2, 11, 12}));
515+
EXPECT_TRUE(rangesMatch(BV.half_open_range(1, 13), {1, 2, 11, 12}));
516+
EXPECT_TRUE(rangesMatch(BV.half_open_range(1, 12), {1, 2, 11}));
517+
518+
EXPECT_TRUE(rangesMatch(BV.half_open_range(0, 5), {1, 2}));
519+
EXPECT_TRUE(rangesMatch(BV.half_open_range(1, 5), {1, 2}));
520+
EXPECT_TRUE(rangesMatch(BV.half_open_range(2, 5), {2}));
521+
EXPECT_TRUE(rangesMatch(BV.half_open_range(1, 2), {1}));
522+
EXPECT_TRUE(rangesMatch(BV.half_open_range(13, 14), {}));
523+
524+
EXPECT_TRUE(rangesMatch(BV.half_open_range(2, 10), {2}));
525+
}
526+
527+
{
528+
UBitVec BV(Alloc);
529+
BV.set({1});
530+
531+
EXPECT_EQ(*BV.find(0), 1U); // find(Start) == End
532+
EXPECT_TRUE(rangesMatch(BV.half_open_range(0, 1), {}));
533+
}
534+
535+
{
536+
UBitVec BV(Alloc);
537+
BV.set({5});
538+
539+
EXPECT_EQ(*BV.find(3), 5U); // find(Start) > End
540+
EXPECT_TRUE(rangesMatch(BV.half_open_range(3, 4), {}));
541+
}
542+
}
543+
489544
TEST(CoalescingBitVectorTest, Print) {
490545
std::string S;
491546
{

0 commit comments

Comments
 (0)