mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 04:02:41 +01:00
[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
This commit is contained in:
parent
0ba1ec26dd
commit
6f84fd7763
@ -16,6 +16,7 @@
|
||||
|
||||
#include "llvm/ADT/IntervalMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
@ -352,6 +353,19 @@ public:
|
||||
return It;
|
||||
}
|
||||
|
||||
/// Return a range iterator which iterates over all of the set bits in the
|
||||
/// half-open range [Start, End).
|
||||
iterator_range<const_iterator> half_open_range(IndexT Start,
|
||||
IndexT End) const {
|
||||
assert(Start < End && "Not a valid range");
|
||||
auto StartIt = find(Start);
|
||||
if (StartIt == end() || *StartIt >= End)
|
||||
return {end(), end()};
|
||||
auto EndIt = StartIt;
|
||||
EndIt.advanceToLowerBound(End);
|
||||
return {StartIt, EndIt};
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS) const {
|
||||
OS << "{";
|
||||
for (auto It = Intervals.begin(), End = Intervals.end(); It != End;
|
||||
|
@ -137,16 +137,24 @@ using VarLocSet = CoalescingBitVector<uint64_t>;
|
||||
/// Why encode a location /into/ the VarLocMap index? This makes it possible
|
||||
/// to find the open VarLocs killed by a register def very quickly. This is a
|
||||
/// performance-critical operation for LiveDebugValues.
|
||||
///
|
||||
/// TODO: Consider adding reserved intervals for kinds of VarLocs other than
|
||||
/// RegisterKind, like SpillLocKind or EntryValueKind, to optimize iteration
|
||||
/// over open locations.
|
||||
struct LocIndex {
|
||||
uint32_t Location; // Physical registers live in the range [1;2^30) (see
|
||||
// \ref MCRegister), so we have plenty of range left here
|
||||
// to encode non-register locations.
|
||||
uint32_t Index;
|
||||
|
||||
/// The first location greater than 0 that is not reserved for VarLocs of
|
||||
/// kind RegisterKind.
|
||||
static constexpr uint32_t kFirstInvalidRegLocation = 1 << 30;
|
||||
|
||||
/// A special location reserved for VarLocs of kind SpillLocKind.
|
||||
static constexpr uint32_t kSpillLocation = kFirstInvalidRegLocation;
|
||||
|
||||
/// A special location reserved for VarLocs of kind EntryValueBackupKind and
|
||||
/// EntryValueCopyBackupKind.
|
||||
static constexpr uint32_t kEntryValueBackupLocation =
|
||||
kFirstInvalidRegLocation + 1;
|
||||
|
||||
LocIndex(uint32_t Location, uint32_t Index)
|
||||
: Location(Location), Index(Index) {}
|
||||
|
||||
@ -166,6 +174,14 @@ struct LocIndex {
|
||||
static uint64_t rawIndexForReg(uint32_t Reg) {
|
||||
return LocIndex(Reg, 0).getAsRawInteger();
|
||||
}
|
||||
|
||||
/// Return a range covering all set indices in the interval reserved for
|
||||
/// \p Location in \p Set.
|
||||
static auto indexRangeForLocation(const VarLocSet &Set, uint32_t Location) {
|
||||
uint64_t Start = LocIndex(Location, 0).getAsRawInteger();
|
||||
uint64_t End = LocIndex(Location + 1, 0).getAsRawInteger();
|
||||
return Set.half_open_range(Start, End);
|
||||
}
|
||||
};
|
||||
|
||||
class LiveDebugValues : public MachineFunctionPass {
|
||||
@ -211,6 +227,9 @@ private:
|
||||
bool operator==(const SpillLoc &Other) const {
|
||||
return SpillBase == Other.SpillBase && SpillOffset == Other.SpillOffset;
|
||||
}
|
||||
bool operator!=(const SpillLoc &Other) const {
|
||||
return !(*this == Other);
|
||||
}
|
||||
};
|
||||
|
||||
/// Identity of the variable at this location.
|
||||
@ -477,10 +496,27 @@ private:
|
||||
/// location.
|
||||
SmallDenseMap<uint32_t, std::vector<VarLoc>> Loc2Vars;
|
||||
|
||||
/// Determine the 32-bit location reserved for \p VL, based on its kind.
|
||||
static uint32_t getLocationForVar(const VarLoc &VL) {
|
||||
switch (VL.Kind) {
|
||||
case VarLoc::RegisterKind:
|
||||
assert((VL.Loc.RegNo < LocIndex::kFirstInvalidRegLocation) &&
|
||||
"Physreg out of range?");
|
||||
return VL.Loc.RegNo;
|
||||
case VarLoc::SpillLocKind:
|
||||
return LocIndex::kSpillLocation;
|
||||
case VarLoc::EntryValueBackupKind:
|
||||
case VarLoc::EntryValueCopyBackupKind:
|
||||
return LocIndex::kEntryValueBackupLocation;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/// Retrieve a unique LocIndex for \p VL.
|
||||
LocIndex insert(const VarLoc &VL) {
|
||||
uint32_t Location = VL.isDescribedByReg();
|
||||
uint32_t Location = getLocationForVar(VL);
|
||||
uint32_t &Index = Var2Index[VL];
|
||||
if (!Index) {
|
||||
auto &Vars = Loc2Vars[Location];
|
||||
@ -577,6 +613,30 @@ private:
|
||||
"open ranges are inconsistent");
|
||||
return VarLocs.empty();
|
||||
}
|
||||
|
||||
/// Get an empty range of VarLoc IDs.
|
||||
auto getEmptyVarLocRange() const {
|
||||
return iterator_range<VarLocSet::const_iterator>(getVarLocs().end(),
|
||||
getVarLocs().end());
|
||||
}
|
||||
|
||||
/// Get all set IDs for VarLocs of kind RegisterKind in \p Reg.
|
||||
auto getRegisterVarLocs(Register Reg) const {
|
||||
return LocIndex::indexRangeForLocation(getVarLocs(), Reg);
|
||||
}
|
||||
|
||||
/// Get all set IDs for VarLocs of kind SpillLocKind.
|
||||
auto getSpillVarLocs() const {
|
||||
return LocIndex::indexRangeForLocation(getVarLocs(),
|
||||
LocIndex::kSpillLocation);
|
||||
}
|
||||
|
||||
/// Get all set IDs for VarLocs of kind EntryValueBackupKind or
|
||||
/// EntryValueCopyBackupKind.
|
||||
auto getEntryValueBackupVarLocs() const {
|
||||
return LocIndex::indexRangeForLocation(
|
||||
getVarLocs(), LocIndex::kEntryValueBackupLocation);
|
||||
}
|
||||
};
|
||||
|
||||
/// Collect all VarLoc IDs from \p CollectFrom for VarLocs of kind
|
||||
@ -821,7 +881,10 @@ void LiveDebugValues::getUsedRegs(const VarLocSet &CollectFrom,
|
||||
// All register-based VarLocs are assigned indices greater than or equal to
|
||||
// FirstRegIndex.
|
||||
uint64_t FirstRegIndex = LocIndex::rawIndexForReg(1);
|
||||
for (auto It = CollectFrom.find(FirstRegIndex), End = CollectFrom.end();
|
||||
uint64_t FirstInvalidIndex =
|
||||
LocIndex::rawIndexForReg(LocIndex::kFirstInvalidRegLocation);
|
||||
for (auto It = CollectFrom.find(FirstRegIndex),
|
||||
End = CollectFrom.find(FirstInvalidIndex);
|
||||
It != End;) {
|
||||
// We found a VarLoc ID for a VarLoc that lives in a register. Figure out
|
||||
// which register and add it to UsedRegs.
|
||||
@ -924,11 +987,8 @@ bool LiveDebugValues::removeEntryValue(const MachineInstr &MI,
|
||||
}
|
||||
|
||||
if (TrySalvageEntryValue) {
|
||||
for (uint64_t ID : OpenRanges.getVarLocs()) {
|
||||
for (uint64_t ID : OpenRanges.getEntryValueBackupVarLocs()) {
|
||||
const VarLoc &VL = VarLocIDs[LocIndex::fromRawInteger(ID)];
|
||||
if (!VL.isEntryBackupLoc())
|
||||
continue;
|
||||
|
||||
if (VL.getEntryValueCopyBackupReg() == Reg &&
|
||||
VL.MI.getOperand(0).getReg() == SrcRegOp->getReg())
|
||||
return false;
|
||||
@ -1259,10 +1319,11 @@ void LiveDebugValues::transferSpillOrRestoreInst(MachineInstr &MI,
|
||||
VarLocSet KillSet(Alloc);
|
||||
if (isSpillInstruction(MI, MF)) {
|
||||
Loc = extractSpillBaseRegAndOffset(MI);
|
||||
for (uint64_t ID : OpenRanges.getVarLocs()) {
|
||||
for (uint64_t ID : OpenRanges.getSpillVarLocs()) {
|
||||
LocIndex Idx = LocIndex::fromRawInteger(ID);
|
||||
const VarLoc &VL = VarLocIDs[Idx];
|
||||
if (VL.Kind == VarLoc::SpillLocKind && VL.Loc.SpillLocation == *Loc) {
|
||||
assert(VL.Kind == VarLoc::SpillLocKind && "Broken VarLocSet?");
|
||||
if (VL.Loc.SpillLocation == *Loc) {
|
||||
// This location is overwritten by the current instruction -- terminate
|
||||
// the open range, and insert an explicit DBG_VALUE $noreg.
|
||||
//
|
||||
@ -1298,21 +1359,31 @@ void LiveDebugValues::transferSpillOrRestoreInst(MachineInstr &MI,
|
||||
<< "\n");
|
||||
}
|
||||
// Check if the register or spill location is the location of a debug value.
|
||||
for (uint64_t ID : OpenRanges.getVarLocs()) {
|
||||
auto TransferCandidates = OpenRanges.getEmptyVarLocRange();
|
||||
if (TKind == TransferKind::TransferSpill)
|
||||
TransferCandidates = OpenRanges.getRegisterVarLocs(Reg);
|
||||
else if (TKind == TransferKind::TransferRestore)
|
||||
TransferCandidates = OpenRanges.getSpillVarLocs();
|
||||
for (uint64_t ID : TransferCandidates) {
|
||||
LocIndex Idx = LocIndex::fromRawInteger(ID);
|
||||
const VarLoc &VL = VarLocIDs[Idx];
|
||||
if (TKind == TransferKind::TransferSpill && VL.isDescribedByReg() == Reg) {
|
||||
if (TKind == TransferKind::TransferSpill) {
|
||||
assert(VL.isDescribedByReg() == Reg && "Broken VarLocSet?");
|
||||
LLVM_DEBUG(dbgs() << "Spilling Register " << printReg(Reg, TRI) << '('
|
||||
<< VL.Var.getVariable()->getName() << ")\n");
|
||||
} else if (TKind == TransferKind::TransferRestore &&
|
||||
VL.Kind == VarLoc::SpillLocKind &&
|
||||
VL.Loc.SpillLocation == *Loc) {
|
||||
} else {
|
||||
assert(TKind == TransferKind::TransferRestore &&
|
||||
VL.Kind == VarLoc::SpillLocKind && "Broken VarLocSet?");
|
||||
if (VL.Loc.SpillLocation != *Loc)
|
||||
// The spill location is not the location of a debug value.
|
||||
continue;
|
||||
LLVM_DEBUG(dbgs() << "Restoring Register " << printReg(Reg, TRI) << '('
|
||||
<< VL.Var.getVariable()->getName() << ")\n");
|
||||
} else
|
||||
continue;
|
||||
}
|
||||
insertTransferDebugPair(MI, OpenRanges, Transfers, VarLocIDs, Idx, TKind,
|
||||
Reg);
|
||||
// FIXME: A comment should explain why it's correct to return early here,
|
||||
// if that is in fact correct.
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1356,7 +1427,7 @@ void LiveDebugValues::transferRegisterCopy(MachineInstr &MI,
|
||||
// a parameter describing only a moving of the value around, rather then
|
||||
// modifying it, we are still able to use the entry value if needed.
|
||||
if (isRegOtherThanSPAndFP(*DestRegOp, MI, TRI)) {
|
||||
for (uint64_t ID : OpenRanges.getVarLocs()) {
|
||||
for (uint64_t ID : OpenRanges.getEntryValueBackupVarLocs()) {
|
||||
LocIndex Idx = LocIndex::fromRawInteger(ID);
|
||||
const VarLoc &VL = VarLocIDs[Idx];
|
||||
if (VL.getEntryValueBackupReg() == SrcReg) {
|
||||
@ -1378,13 +1449,14 @@ void LiveDebugValues::transferRegisterCopy(MachineInstr &MI,
|
||||
if (!SrcRegOp->isKill())
|
||||
return;
|
||||
|
||||
for (uint64_t ID : OpenRanges.getVarLocs()) {
|
||||
for (uint64_t ID : OpenRanges.getRegisterVarLocs(SrcReg)) {
|
||||
LocIndex Idx = LocIndex::fromRawInteger(ID);
|
||||
if (VarLocIDs[Idx].isDescribedByReg() == SrcReg) {
|
||||
insertTransferDebugPair(MI, OpenRanges, Transfers, VarLocIDs, Idx,
|
||||
TransferKind::TransferCopy, DestReg);
|
||||
return;
|
||||
}
|
||||
assert(VarLocIDs[Idx].isDescribedByReg() == SrcReg && "Broken VarLocSet?");
|
||||
insertTransferDebugPair(MI, OpenRanges, Transfers, VarLocIDs, Idx,
|
||||
TransferKind::TransferCopy, DestReg);
|
||||
// FIXME: A comment should explain why it's correct to return early here,
|
||||
// if that is in fact correct.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,9 +23,9 @@
|
||||
# CHECK-NEXT: $ebx = MOV32ri 2
|
||||
# CHECK-NEXT: DBG_VALUE $esi, $noreg, ![[ARG_B]], !DIExpression(DW_OP_LLVM_entry_value, 1)
|
||||
# CHECK: bb.3.if.end
|
||||
# CHECK-NEXT: DBG_VALUE $edx, $noreg, ![[ARG_Q]], !DIExpression()
|
||||
# CHECK-NEXT: DBG_VALUE $ebp, $noreg, ![[ARG_C]], !DIExpression()
|
||||
# CHECK-NEXT: DBG_VALUE $esi, $noreg, ![[ARG_B]], !DIExpression(DW_OP_LLVM_entry_value, 1)
|
||||
# CHECK-DAG: DBG_VALUE $edx, $noreg, ![[ARG_Q]], !DIExpression()
|
||||
# CHECK-DAG: DBG_VALUE $ebp, $noreg, ![[ARG_C]], !DIExpression()
|
||||
# CHECK-DAG: DBG_VALUE $esi, $noreg, ![[ARG_B]], !DIExpression(DW_OP_LLVM_entry_value, 1)
|
||||
--- |
|
||||
; ModuleID = 'test.c'
|
||||
source_filename = "test.c"
|
||||
|
@ -31,6 +31,11 @@ bool elementsMatch(const UBitVec &BV, std::initializer_list<unsigned> List) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rangesMatch(iterator_range<UBitVec::const_iterator> R,
|
||||
std::initializer_list<unsigned> List) {
|
||||
return std::equal(R.begin(), R.end(), List.begin(), List.end());
|
||||
}
|
||||
|
||||
TEST(CoalescingBitVectorTest, Set) {
|
||||
UBitVec::Allocator Alloc;
|
||||
UBitVec BV1(Alloc);
|
||||
@ -486,6 +491,56 @@ TEST(CoalescingBitVectorTest, AdvanceToLowerBound) {
|
||||
EXPECT_TRUE(It == BV.end());
|
||||
}
|
||||
|
||||
TEST(CoalescingBitVectorTest, HalfOpenRange) {
|
||||
UBitVec::Allocator Alloc;
|
||||
|
||||
{
|
||||
UBitVec BV(Alloc);
|
||||
BV.set({1, 2, 3});
|
||||
|
||||
EXPECT_EQ(*BV.find(0), 1U); // find(Start) > Start
|
||||
EXPECT_TRUE(rangesMatch(BV.half_open_range(0, 5), {1, 2, 3}));
|
||||
EXPECT_TRUE(rangesMatch(BV.half_open_range(1, 4), {1, 2, 3}));
|
||||
EXPECT_TRUE(rangesMatch(BV.half_open_range(1, 3), {1, 2}));
|
||||
EXPECT_TRUE(rangesMatch(BV.half_open_range(2, 3), {2}));
|
||||
EXPECT_TRUE(rangesMatch(BV.half_open_range(2, 4), {2, 3}));
|
||||
EXPECT_TRUE(rangesMatch(BV.half_open_range(4, 5), {}));
|
||||
}
|
||||
|
||||
{
|
||||
UBitVec BV(Alloc);
|
||||
BV.set({1, 2, 11, 12});
|
||||
|
||||
EXPECT_TRUE(rangesMatch(BV.half_open_range(0, 15), {1, 2, 11, 12}));
|
||||
EXPECT_TRUE(rangesMatch(BV.half_open_range(1, 13), {1, 2, 11, 12}));
|
||||
EXPECT_TRUE(rangesMatch(BV.half_open_range(1, 12), {1, 2, 11}));
|
||||
|
||||
EXPECT_TRUE(rangesMatch(BV.half_open_range(0, 5), {1, 2}));
|
||||
EXPECT_TRUE(rangesMatch(BV.half_open_range(1, 5), {1, 2}));
|
||||
EXPECT_TRUE(rangesMatch(BV.half_open_range(2, 5), {2}));
|
||||
EXPECT_TRUE(rangesMatch(BV.half_open_range(1, 2), {1}));
|
||||
EXPECT_TRUE(rangesMatch(BV.half_open_range(13, 14), {}));
|
||||
|
||||
EXPECT_TRUE(rangesMatch(BV.half_open_range(2, 10), {2}));
|
||||
}
|
||||
|
||||
{
|
||||
UBitVec BV(Alloc);
|
||||
BV.set({1});
|
||||
|
||||
EXPECT_EQ(*BV.find(0), 1U); // find(Start) == End
|
||||
EXPECT_TRUE(rangesMatch(BV.half_open_range(0, 1), {}));
|
||||
}
|
||||
|
||||
{
|
||||
UBitVec BV(Alloc);
|
||||
BV.set({5});
|
||||
|
||||
EXPECT_EQ(*BV.find(3), 5U); // find(Start) > End
|
||||
EXPECT_TRUE(rangesMatch(BV.half_open_range(3, 4), {}));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CoalescingBitVectorTest, Print) {
|
||||
std::string S;
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user