Skip to content

Commit df47368

Browse files
committed
[RegAllocFast] properly handle STATEPOINT instruction.
STATEPOINT is a fancy and complex pseudo instruction which has both tied defs and regmask operand. Basic FastRA algorithm is as follows: 1. Mark registers used by defs as free 2. If instruction has regmask operand displace clobbered registers according to regmask. 3. Assign registers for use operands. In case of tied defs step 1 is replaced with allocation of registers for them. But regmask is still processed, which may displace already allocated registers. As a result, tied use and def will get assigned to different registers. This patch makes FastRA to process instruction's RegMask (if any) when checking for physical registers interference. That way tied operands won't get registers clobbered by regmask. Reviewed By: arsenm, skatkov Differential Revision: https://reviews.llvm.org/D99284
1 parent 3b87383 commit df47368

File tree

2 files changed

+66
-13
lines changed

2 files changed

+66
-13
lines changed

llvm/lib/CodeGen/RegAllocFast.cpp

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ namespace {
147147
RegUnitSet UsedInInstr;
148148
RegUnitSet PhysRegUses;
149149
SmallVector<uint16_t, 8> DefOperandIndexes;
150+
// Register masks attached to the current instruction.
151+
SmallVector<const uint32_t *> RegMasks;
150152

151153
void setPhysRegState(MCPhysReg PhysReg, unsigned NewState);
152154
bool isPhysRegFree(MCPhysReg PhysReg) const;
@@ -157,8 +159,17 @@ namespace {
157159
UsedInInstr.insert(*Units);
158160
}
159161

162+
// Check if physreg is clobbered by instruction's regmask(s).
163+
bool isClobberedByRegMasks(MCPhysReg PhysReg) const {
164+
return llvm::any_of(RegMasks, [PhysReg](const uint32_t *Mask) {
165+
return MachineOperand::clobbersPhysReg(Mask, PhysReg);
166+
});
167+
}
168+
160169
/// Check if a physreg or any of its aliases are used in this instruction.
161170
bool isRegUsedInInstr(MCPhysReg PhysReg, bool LookAtPhysRegUses) const {
171+
if (LookAtPhysRegUses && isClobberedByRegMasks(PhysReg))
172+
return true;
162173
for (MCRegUnitIterator Units(PhysReg, TRI); Units.isValid(); ++Units) {
163174
if (UsedInInstr.count(*Units))
164175
return true;
@@ -1088,6 +1099,7 @@ void RegAllocFast::allocateInstruction(MachineInstr &MI) {
10881099
// operands and early-clobbers.
10891100

10901101
UsedInInstr.clear();
1102+
RegMasks.clear();
10911103
BundleVirtRegsMap.clear();
10921104

10931105
// Scan for special cases; Apply pre-assigned register defs to state.
@@ -1127,6 +1139,7 @@ void RegAllocFast::allocateInstruction(MachineInstr &MI) {
11271139
}
11281140
} else if (MO.isRegMask()) {
11291141
HasRegMask = true;
1142+
RegMasks.push_back(MO.getRegMask());
11301143
}
11311144
}
11321145

@@ -1242,6 +1255,9 @@ void RegAllocFast::allocateInstruction(MachineInstr &MI) {
12421255
continue;
12431256
}
12441257

1258+
assert((!MO.isTied() || !isClobberedByRegMasks(MO.getReg())) &&
1259+
"tied def assigned to clobbered register");
1260+
12451261
// Do not free tied operands and early clobbers.
12461262
if (MO.isTied() || MO.isEarlyClobber())
12471263
continue;
@@ -1258,19 +1274,16 @@ void RegAllocFast::allocateInstruction(MachineInstr &MI) {
12581274

12591275
// Displace clobbered registers.
12601276
if (HasRegMask) {
1261-
for (const MachineOperand &MO : MI.operands()) {
1262-
if (MO.isRegMask()) {
1263-
// MRI bookkeeping.
1264-
MRI->addPhysRegsUsedFromRegMask(MO.getRegMask());
1265-
1266-
// Displace clobbered registers.
1267-
const uint32_t *Mask = MO.getRegMask();
1268-
for (const LiveReg &LR : LiveVirtRegs) {
1269-
MCPhysReg PhysReg = LR.PhysReg;
1270-
if (PhysReg != 0 && MachineOperand::clobbersPhysReg(Mask, PhysReg))
1271-
displacePhysReg(MI, PhysReg);
1272-
}
1273-
}
1277+
assert(!RegMasks.empty() && "expected RegMask");
1278+
// MRI bookkeeping.
1279+
for (const auto *RM : RegMasks)
1280+
MRI->addPhysRegsUsedFromRegMask(RM);
1281+
1282+
// Displace clobbered registers.
1283+
for (const LiveReg &LR : LiveVirtRegs) {
1284+
MCPhysReg PhysReg = LR.PhysReg;
1285+
if (PhysReg != 0 && isClobberedByRegMasks(PhysReg))
1286+
displacePhysReg(MI, PhysReg);
12741287
}
12751288
}
12761289

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# RUN: llc -mtriple=x86_64-- -run-pass=regallocfast -o - %s | FileCheck %s
2+
3+
# Check that fastregalloc does not displace register assigned to tied def when
4+
# RegMask operand is present. STATEPOINT is an example of such instruction.
5+
# Tied def/use must be assigned to the same register.
6+
---
7+
name: test_relocate
8+
tracksRegLiveness: true
9+
body: |
10+
bb.0.entry:
11+
liveins: $rdi
12+
13+
; CHECK: renamable [[REG:\$[a-z0-9]+]] = STATEPOINT 0, 0, 0, target-flags(x86-plt) 0, 2, 0, 2, 0, 2, 0, 2, 1, renamable [[REG]](tied-def 0)
14+
15+
%1:gr64 = COPY $rdi
16+
ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
17+
%1:gr64 = STATEPOINT 0, 0, 0, target-flags(x86-plt) 0, 2, 0, 2, 0, 2, 0, 2, 1, %1(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp
18+
ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
19+
$rax = COPY %1
20+
RET 0, killed $rax
21+
...
22+
23+
# Same as above but with multiple RegMask operands per instruction.
24+
# These regmasks have no real meaning and chosen to allow only single register to be assignable ($r12)
25+
---
26+
name: test_relocate_multi_regmasks
27+
tracksRegLiveness: true
28+
body: |
29+
bb.0.entry:
30+
liveins: $rdi
31+
32+
; CHECK: renamable $r12 = STATEPOINT 0, 0, 0, target-flags(x86-plt) 0, 2, 0, 2, 0, 2, 0, 2, 1, renamable $r12(tied-def 0)
33+
34+
%1:gr64 = COPY $rdi
35+
ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
36+
%1:gr64 = STATEPOINT 0, 0, 0, target-flags(x86-plt) 0, 2, 0, 2, 0, 2, 0, 2, 1, %1(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64_rt_allregs, csr_64_hhvm, implicit-def $rsp, implicit-def $ssp
37+
ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
38+
$rax = COPY %1
39+
RET 0, killed $rax
40+
...

0 commit comments

Comments
 (0)