Skip to content

Commit 10bf29b

Browse files
committed
Fix untracked registers in stackmaps.
This commit fixes yet another bug in stackmaps that leads to registers being untracked. The bug went unnoticed until the recent entryblock change exposed it. The fix consists of two changes, allowing spill mappings to be applied transitively and replacing killed registers in the stackmap with non-killed registers holding the same value. See comments for more detail.
1 parent 7873e69 commit 10bf29b

File tree

2 files changed

+37
-8
lines changed

2 files changed

+37
-8
lines changed

llvm/lib/CodeGen/StackMaps.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -305,8 +305,22 @@ StackMaps::parseOperand(MachineInstr::const_mop_iterator MOI,
305305
// each one of them. Note, that the stackmap may track either of %rbx or
306306
// %rcx, resulting in different ways below to retrieve the mappings.
307307
int ExtraReg = 0;
308+
Register R = MOI->getReg();
308309
if (MOI->isReg()) {
309-
Register R = MOI->getReg();
310+
if (MOI->isKill()) {
311+
// There's no point in tracking a killed register. Instead, try and
312+
// find a copy of the register and use that to increase the likelyhood
313+
// of us tracking that value.
314+
// YKFIXME: This is likely only a temporary fix. In the future we might
315+
// want to allow stackmaps to track arbitrarily many locations per live
316+
// variable. Currently, we can only track two.
317+
for (auto I : SpillOffsets) {
318+
if (I.second == R) {
319+
R = I.first;
320+
break;
321+
}
322+
}
323+
}
310324
if (SpillOffsets.count(R) > 0) {
311325
RHS = SpillOffsets[R];
312326
assert(SpillOffsets[R] != 0);
@@ -333,9 +347,9 @@ StackMaps::parseOperand(MachineInstr::const_mop_iterator MOI,
333347
}
334348
}
335349

336-
unsigned DwarfRegNum = getDwarfRegNum(MOI->getReg(), TRI);
350+
unsigned DwarfRegNum = getDwarfRegNum(R, TRI);
337351
unsigned LLVMRegNum = *TRI->getLLVMRegNum(DwarfRegNum, false);
338-
unsigned SubRegIdx = TRI->getSubRegIndex(LLVMRegNum, MOI->getReg());
352+
unsigned SubRegIdx = TRI->getSubRegIndex(LLVMRegNum, R);
339353
if (SubRegIdx)
340354
Offset = TRI->getSubRegIdxOffset(SubRegIdx);
341355

llvm/lib/Target/X86/X86AsmPrinter.cpp

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,21 @@ void clearRhs(Register Reg, std::map<Register, int64_t> &SpillMap) {
6565
auto I = SpillMap.begin();
6666
while (I != SpillMap.end()) {
6767
if (I->second == Reg) {
68-
I = SpillMap.erase(I);
68+
// If there's a mapping A => B, where B has been reassigned and has a
69+
// mapping B => C, then transitively apply the mapping so that A => C.
70+
// This makes sure we don't remove mappings (especially to stack slots)
71+
// when a register is reassigned. Example:
72+
// store $r13 in [$rbp - 8]
73+
// $rcx = $r13
74+
// $r13 = $rbx
75+
// Upon assigning `$r13 = $rbx`, we apply `$r13`'s previous mapping to
76+
// `$rcx` so that `SpillMap[$rcx] = -8`.
77+
if(SpillMap.count(Reg) > 0) {
78+
SpillMap[I->first] = SpillMap[Reg];
79+
++I;
80+
} else {
81+
I = SpillMap.erase(I);
82+
}
6983
} else {
7084
++I;
7185
}
@@ -99,13 +113,14 @@ void processInstructions(
99113
const MachineOperand Rhs = Instr.getOperand(1);
100114
assert(Lhs.isReg() && "Is register.");
101115
assert(Rhs.isReg() && "Is register.");
116+
// Reassigning a new value to LHS means any mappings to Lhs are now void
117+
// and need to be removed. We need to do this before updating the
118+
// mapping, so the transitive property of the SpillMap isn't violated
119+
// (see `clearRhs` for more info).
120+
clearRhs(Lhs.getReg(), SpillMap);
102121
SpillMap[Lhs.getReg()] = Rhs.getReg();
103122
// YKFIXME: If the `mov` instruction has a killed-flag, remove the
104123
// register from the map.
105-
106-
// Reassigning a new value to Lhs means any mappings to Lhs are now void
107-
// and need to be removed.
108-
clearRhs(Lhs.getReg(), SpillMap);
109124
continue;
110125
}
111126

0 commit comments

Comments
 (0)