Skip to content

Commit c4a872b

Browse files
gbossuqcolombet
authored andcommitted
FastRegAlloc: Fix implicit operands not rewritten
This patch fixes a potential crash due to RegAllocFast not rewriting virtual registers. This essentially happens because of a call to MachineInstr::addRegisterKilled() in the process of allocating a "killed" vreg. The former can eventually delete implicit operands without RegAllocFast noticing, leading to some operands being "skipped" and not rewritten to use physical registers. Note that I noticed this crash when working on a solution for tying a register with one/multiple of its sub-registers within an instruction. (See problem description here: https://discourse.llvm.org/t/pass-to-tie-an-output-operand-to-a-subregister-of-an-input-operand/67184). Aside from this fix, I believe there could be further improvements to the RegAllocFast when it comes to instructions with multiple uses of a same virtual register. You can see it in the added test where the implicit uses have been re-written in a somewhat surprising way because of phase ordering. Ultimately, when allocating vregs for an instruction, I believe we should iterate on the vregs it uses (and then process all the operands that use this vregs), instead of directly iterating on operands and somewhat assuming each operand uses a different vreg. This would in the end be quite close to what greedy+virtregrewriter does. If that makes sense, I would probably spin off another patch (after I get more familiar with RegAllocFast). Differential Revision: https://reviews.llvm.org/D145169
1 parent e4fd46b commit c4a872b

File tree

2 files changed

+233
-116
lines changed

2 files changed

+233
-116
lines changed

llvm/lib/CodeGen/RegAllocFast.cpp

Lines changed: 155 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,8 @@ namespace {
240240
void addRegClassDefCounts(std::vector<unsigned> &RegClassDefCounts,
241241
Register Reg) const;
242242

243+
void findAndSortDefOperandIndexes(const MachineInstr &MI);
244+
243245
void allocateInstruction(MachineInstr &MI);
244246
void handleDebugValue(MachineInstr &MI);
245247
void handleBundle(MachineInstr &MI);
@@ -265,18 +267,18 @@ namespace {
265267
void allocVirtRegUndef(MachineOperand &MO);
266268
void assignDanglingDebugValues(MachineInstr &Def, Register VirtReg,
267269
MCPhysReg Reg);
268-
void defineLiveThroughVirtReg(MachineInstr &MI, unsigned OpNum,
270+
bool defineLiveThroughVirtReg(MachineInstr &MI, unsigned OpNum,
269271
Register VirtReg);
270-
void defineVirtReg(MachineInstr &MI, unsigned OpNum, Register VirtReg,
272+
bool defineVirtReg(MachineInstr &MI, unsigned OpNum, Register VirtReg,
271273
bool LookAtPhysRegUses = false);
272-
void useVirtReg(MachineInstr &MI, unsigned OpNum, Register VirtReg);
274+
bool useVirtReg(MachineInstr &MI, unsigned OpNum, Register VirtReg);
273275

274276
MachineBasicBlock::iterator
275277
getMBBBeginInsertionPoint(MachineBasicBlock &MBB,
276278
SmallSet<Register, 2> &PrologLiveIns) const;
277279

278280
void reloadAtBegin(MachineBasicBlock &MBB);
279-
void setPhysReg(MachineInstr &MI, MachineOperand &MO, MCPhysReg PhysReg);
281+
bool setPhysReg(MachineInstr &MI, MachineOperand &MO, MCPhysReg PhysReg);
280282

281283
Register traceCopies(Register VirtReg) const;
282284
Register traceCopyChain(Register Reg) const;
@@ -875,10 +877,11 @@ void RegAllocFast::allocVirtRegUndef(MachineOperand &MO) {
875877

876878
/// Variation of defineVirtReg() with special handling for livethrough regs
877879
/// (tied or earlyclobber) that may interfere with preassigned uses.
878-
void RegAllocFast::defineLiveThroughVirtReg(MachineInstr &MI, unsigned OpNum,
880+
/// \return true if MI's MachineOperands were re-arranged/invalidated.
881+
bool RegAllocFast::defineLiveThroughVirtReg(MachineInstr &MI, unsigned OpNum,
879882
Register VirtReg) {
880883
if (!shouldAllocateRegister(VirtReg))
881-
return;
884+
return false;
882885
LiveRegMap::iterator LRI = findLiveVirtReg(VirtReg);
883886
if (LRI != LiveVirtRegs.end()) {
884887
MCPhysReg PrevReg = LRI->PhysReg;
@@ -909,11 +912,13 @@ void RegAllocFast::defineLiveThroughVirtReg(MachineInstr &MI, unsigned OpNum,
909912
/// perform an allocation if:
910913
/// - It is a dead definition without any uses.
911914
/// - The value is live out and all uses are in different basic blocks.
912-
void RegAllocFast::defineVirtReg(MachineInstr &MI, unsigned OpNum,
915+
///
916+
/// \return true if MI's MachineOperands were re-arranged/invalidated.
917+
bool RegAllocFast::defineVirtReg(MachineInstr &MI, unsigned OpNum,
913918
Register VirtReg, bool LookAtPhysRegUses) {
914919
assert(VirtReg.isVirtual() && "Not a virtual register");
915920
if (!shouldAllocateRegister(VirtReg))
916-
return;
921+
return false;
917922
MachineOperand &MO = MI.getOperand(OpNum);
918923
LiveRegMap::iterator LRI;
919924
bool New;
@@ -974,15 +979,16 @@ void RegAllocFast::defineVirtReg(MachineInstr &MI, unsigned OpNum,
974979
BundleVirtRegsMap[VirtReg] = PhysReg;
975980
}
976981
markRegUsedInInstr(PhysReg);
977-
setPhysReg(MI, MO, PhysReg);
982+
return setPhysReg(MI, MO, PhysReg);
978983
}
979984

980985
/// Allocates a register for a VirtReg use.
981-
void RegAllocFast::useVirtReg(MachineInstr &MI, unsigned OpNum,
986+
/// \return true if MI's MachineOperands were re-arranged/invalidated.
987+
bool RegAllocFast::useVirtReg(MachineInstr &MI, unsigned OpNum,
982988
Register VirtReg) {
983989
assert(VirtReg.isVirtual() && "Not a virtual register");
984990
if (!shouldAllocateRegister(VirtReg))
985-
return;
991+
return false;
986992
MachineOperand &MO = MI.getOperand(OpNum);
987993
LiveRegMap::iterator LRI;
988994
bool New;
@@ -1019,8 +1025,7 @@ void RegAllocFast::useVirtReg(MachineInstr &MI, unsigned OpNum,
10191025
if (LRI->Error) {
10201026
const TargetRegisterClass &RC = *MRI->getRegClass(VirtReg);
10211027
ArrayRef<MCPhysReg> AllocationOrder = RegClassInfo.getOrder(&RC);
1022-
setPhysReg(MI, MO, *AllocationOrder.begin());
1023-
return;
1028+
return setPhysReg(MI, MO, *AllocationOrder.begin());
10241029
}
10251030
}
10261031

@@ -1030,18 +1035,17 @@ void RegAllocFast::useVirtReg(MachineInstr &MI, unsigned OpNum,
10301035
BundleVirtRegsMap[VirtReg] = LRI->PhysReg;
10311036
}
10321037
markRegUsedInInstr(LRI->PhysReg);
1033-
setPhysReg(MI, MO, LRI->PhysReg);
1038+
return setPhysReg(MI, MO, LRI->PhysReg);
10341039
}
10351040

1036-
/// Changes operand OpNum in MI the refer the PhysReg, considering subregs. This
1037-
/// may invalidate any operand pointers. Return true if the operand kills its
1038-
/// register.
1039-
void RegAllocFast::setPhysReg(MachineInstr &MI, MachineOperand &MO,
1041+
/// Changes operand OpNum in MI the refer the PhysReg, considering subregs.
1042+
/// \return true if MI's MachineOperands were re-arranged/invalidated.
1043+
bool RegAllocFast::setPhysReg(MachineInstr &MI, MachineOperand &MO,
10401044
MCPhysReg PhysReg) {
10411045
if (!MO.getSubReg()) {
10421046
MO.setReg(PhysReg);
10431047
MO.setIsRenamable(true);
1044-
return;
1048+
return false;
10451049
}
10461050

10471051
// Handle subregister index.
@@ -1057,7 +1061,8 @@ void RegAllocFast::setPhysReg(MachineInstr &MI, MachineOperand &MO,
10571061
// register kill.
10581062
if (MO.isKill()) {
10591063
MI.addRegisterKilled(PhysReg, TRI, true);
1060-
return;
1064+
// Conservatively assume implicit MOs were re-arranged
1065+
return true;
10611066
}
10621067

10631068
// A <def,read-undef> of a sub-register requires an implicit def of the full
@@ -1067,7 +1072,10 @@ void RegAllocFast::setPhysReg(MachineInstr &MI, MachineOperand &MO,
10671072
MI.addRegisterDead(PhysReg, TRI, true);
10681073
else
10691074
MI.addRegisterDefined(PhysReg, TRI);
1075+
// Conservatively assume implicit MOs were re-arranged
1076+
return true;
10701077
}
1078+
return false;
10711079
}
10721080

10731081
#ifndef NDEBUG
@@ -1147,6 +1155,72 @@ void RegAllocFast::addRegClassDefCounts(std::vector<unsigned> &RegClassDefCounts
11471155
}
11481156
}
11491157

1158+
/// Compute \ref DefOperandIndexes so it contains the indices of "def" operands
1159+
/// that are to be allocated. Those are ordered in a way that small classes,
1160+
/// early clobbers and livethroughs are allocated first.
1161+
void RegAllocFast::findAndSortDefOperandIndexes(const MachineInstr &MI) {
1162+
DefOperandIndexes.clear();
1163+
1164+
// Track number of defs which may consume a register from the class.
1165+
std::vector<unsigned> RegClassDefCounts(TRI->getNumRegClasses(), 0);
1166+
assert(RegClassDefCounts[0] == 0);
1167+
1168+
LLVM_DEBUG(dbgs() << "Need to assign livethroughs\n");
1169+
for (unsigned I = 0, E = MI.getNumOperands(); I < E; ++I) {
1170+
const MachineOperand &MO = MI.getOperand(I);
1171+
if (!MO.isReg())
1172+
continue;
1173+
Register Reg = MO.getReg();
1174+
if (MO.readsReg()) {
1175+
if (Reg.isPhysical()) {
1176+
LLVM_DEBUG(dbgs() << "mark extra used: " << printReg(Reg, TRI) << '\n');
1177+
markPhysRegUsedInInstr(Reg);
1178+
}
1179+
}
1180+
1181+
if (MO.isDef()) {
1182+
if (Reg.isVirtual() && shouldAllocateRegister(Reg))
1183+
DefOperandIndexes.push_back(I);
1184+
1185+
addRegClassDefCounts(RegClassDefCounts, Reg);
1186+
}
1187+
}
1188+
1189+
llvm::sort(DefOperandIndexes, [&](uint16_t I0, uint16_t I1) {
1190+
const MachineOperand &MO0 = MI.getOperand(I0);
1191+
const MachineOperand &MO1 = MI.getOperand(I1);
1192+
Register Reg0 = MO0.getReg();
1193+
Register Reg1 = MO1.getReg();
1194+
const TargetRegisterClass &RC0 = *MRI->getRegClass(Reg0);
1195+
const TargetRegisterClass &RC1 = *MRI->getRegClass(Reg1);
1196+
1197+
// Identify regclass that are easy to use up completely just in this
1198+
// instruction.
1199+
unsigned ClassSize0 = RegClassInfo.getOrder(&RC0).size();
1200+
unsigned ClassSize1 = RegClassInfo.getOrder(&RC1).size();
1201+
1202+
bool SmallClass0 = ClassSize0 < RegClassDefCounts[RC0.getID()];
1203+
bool SmallClass1 = ClassSize1 < RegClassDefCounts[RC1.getID()];
1204+
if (SmallClass0 > SmallClass1)
1205+
return true;
1206+
if (SmallClass0 < SmallClass1)
1207+
return false;
1208+
1209+
// Allocate early clobbers and livethrough operands first.
1210+
bool Livethrough0 = MO0.isEarlyClobber() || MO0.isTied() ||
1211+
(MO0.getSubReg() == 0 && !MO0.isUndef());
1212+
bool Livethrough1 = MO1.isEarlyClobber() || MO1.isTied() ||
1213+
(MO1.getSubReg() == 0 && !MO1.isUndef());
1214+
if (Livethrough0 > Livethrough1)
1215+
return true;
1216+
if (Livethrough0 < Livethrough1)
1217+
return false;
1218+
1219+
// Tie-break rule: operand index.
1220+
return I0 < I1;
1221+
});
1222+
}
1223+
11501224
void RegAllocFast::allocateInstruction(MachineInstr &MI) {
11511225
// The basic algorithm here is:
11521226
// 1. Mark registers of def operands as free
@@ -1218,97 +1292,56 @@ void RegAllocFast::allocateInstruction(MachineInstr &MI) {
12181292
// Allocate virtreg defs.
12191293
if (HasDef) {
12201294
if (HasVRegDef) {
1295+
// Note that Implicit MOs can get re-arranged by defineVirtReg(), so loop
1296+
// multiple times to ensure no operand is missed.
1297+
bool ReArrangedImplicitOps = true;
1298+
12211299
// Special handling for early clobbers, tied operands or subregister defs:
12221300
// Compared to "normal" defs these:
12231301
// - Must not use a register that is pre-assigned for a use operand.
12241302
// - In order to solve tricky inline assembly constraints we change the
12251303
// heuristic to figure out a good operand order before doing
12261304
// assignments.
12271305
if (NeedToAssignLiveThroughs) {
1228-
DefOperandIndexes.clear();
12291306
PhysRegUses.clear();
12301307

1231-
// Track number of defs which may consume a register from the class.
1232-
std::vector<unsigned> RegClassDefCounts(TRI->getNumRegClasses(), 0);
1233-
assert(RegClassDefCounts[0] == 0);
1234-
1235-
LLVM_DEBUG(dbgs() << "Need to assign livethroughs\n");
1236-
for (unsigned I = 0, E = MI.getNumOperands(); I < E; ++I) {
1237-
const MachineOperand &MO = MI.getOperand(I);
1238-
if (!MO.isReg())
1239-
continue;
1240-
Register Reg = MO.getReg();
1241-
if (MO.readsReg()) {
1242-
if (Reg.isPhysical()) {
1243-
LLVM_DEBUG(dbgs() << "mark extra used: " << printReg(Reg, TRI)
1244-
<< '\n');
1245-
markPhysRegUsedInInstr(Reg);
1308+
while (ReArrangedImplicitOps) {
1309+
ReArrangedImplicitOps = false;
1310+
findAndSortDefOperandIndexes(MI);
1311+
for (uint16_t OpIdx : DefOperandIndexes) {
1312+
MachineOperand &MO = MI.getOperand(OpIdx);
1313+
LLVM_DEBUG(dbgs() << "Allocating " << MO << '\n');
1314+
unsigned Reg = MO.getReg();
1315+
if (MO.isEarlyClobber() ||
1316+
(MO.isTied() && !TiedOpIsUndef(MO, OpIdx)) ||
1317+
(MO.getSubReg() && !MO.isUndef())) {
1318+
ReArrangedImplicitOps = defineLiveThroughVirtReg(MI, OpIdx, Reg);
1319+
} else {
1320+
ReArrangedImplicitOps = defineVirtReg(MI, OpIdx, Reg);
1321+
}
1322+
if (ReArrangedImplicitOps) {
1323+
// Implicit operands of MI were re-arranged,
1324+
// re-compute DefOperandIndexes.
1325+
break;
12461326
}
1247-
}
1248-
1249-
if (MO.isDef()) {
1250-
if (Reg.isVirtual() && shouldAllocateRegister(Reg))
1251-
DefOperandIndexes.push_back(I);
1252-
1253-
addRegClassDefCounts(RegClassDefCounts, Reg);
1254-
}
1255-
}
1256-
1257-
llvm::sort(DefOperandIndexes, [&](uint16_t I0, uint16_t I1) {
1258-
const MachineOperand &MO0 = MI.getOperand(I0);
1259-
const MachineOperand &MO1 = MI.getOperand(I1);
1260-
Register Reg0 = MO0.getReg();
1261-
Register Reg1 = MO1.getReg();
1262-
const TargetRegisterClass &RC0 = *MRI->getRegClass(Reg0);
1263-
const TargetRegisterClass &RC1 = *MRI->getRegClass(Reg1);
1264-
1265-
// Identify regclass that are easy to use up completely just in this
1266-
// instruction.
1267-
unsigned ClassSize0 = RegClassInfo.getOrder(&RC0).size();
1268-
unsigned ClassSize1 = RegClassInfo.getOrder(&RC1).size();
1269-
1270-
bool SmallClass0 = ClassSize0 < RegClassDefCounts[RC0.getID()];
1271-
bool SmallClass1 = ClassSize1 < RegClassDefCounts[RC1.getID()];
1272-
if (SmallClass0 > SmallClass1)
1273-
return true;
1274-
if (SmallClass0 < SmallClass1)
1275-
return false;
1276-
1277-
// Allocate early clobbers and livethrough operands first.
1278-
bool Livethrough0 = MO0.isEarlyClobber() || MO0.isTied() ||
1279-
(MO0.getSubReg() == 0 && !MO0.isUndef());
1280-
bool Livethrough1 = MO1.isEarlyClobber() || MO1.isTied() ||
1281-
(MO1.getSubReg() == 0 && !MO1.isUndef());
1282-
if (Livethrough0 > Livethrough1)
1283-
return true;
1284-
if (Livethrough0 < Livethrough1)
1285-
return false;
1286-
1287-
// Tie-break rule: operand index.
1288-
return I0 < I1;
1289-
});
1290-
1291-
for (uint16_t OpIdx : DefOperandIndexes) {
1292-
MachineOperand &MO = MI.getOperand(OpIdx);
1293-
LLVM_DEBUG(dbgs() << "Allocating " << MO << '\n');
1294-
unsigned Reg = MO.getReg();
1295-
if (MO.isEarlyClobber() ||
1296-
(MO.isTied() && !TiedOpIsUndef(MO, OpIdx)) ||
1297-
(MO.getSubReg() && !MO.isUndef())) {
1298-
defineLiveThroughVirtReg(MI, OpIdx, Reg);
1299-
} else {
1300-
defineVirtReg(MI, OpIdx, Reg);
13011327
}
13021328
}
13031329
} else {
13041330
// Assign virtual register defs.
1305-
for (unsigned I = 0, E = MI.getNumOperands(); I < E; ++I) {
1306-
MachineOperand &MO = MI.getOperand(I);
1307-
if (!MO.isReg() || !MO.isDef())
1308-
continue;
1309-
Register Reg = MO.getReg();
1310-
if (Reg.isVirtual())
1311-
defineVirtReg(MI, I, Reg);
1331+
while (ReArrangedImplicitOps) {
1332+
ReArrangedImplicitOps = false;
1333+
for (unsigned I = 0, E = MI.getNumOperands(); I < E; ++I) {
1334+
MachineOperand &MO = MI.getOperand(I);
1335+
if (!MO.isReg() || !MO.isDef())
1336+
continue;
1337+
Register Reg = MO.getReg();
1338+
if (Reg.isVirtual()) {
1339+
ReArrangedImplicitOps = defineVirtReg(MI, I, Reg);
1340+
if (ReArrangedImplicitOps) {
1341+
break;
1342+
}
1343+
}
1344+
}
13121345
}
13131346
}
13141347
}
@@ -1382,29 +1415,35 @@ void RegAllocFast::allocateInstruction(MachineInstr &MI) {
13821415
}
13831416

13841417
// Allocate virtreg uses and insert reloads as necessary.
1418+
// Implicit MOs can get moved/removed by useVirtReg(), so loop multiple
1419+
// times to ensure no operand is missed.
13851420
bool HasUndefUse = false;
1386-
for (unsigned I = 0; I < MI.getNumOperands(); ++I) {
1387-
MachineOperand &MO = MI.getOperand(I);
1388-
if (!MO.isReg() || !MO.isUse())
1389-
continue;
1390-
Register Reg = MO.getReg();
1391-
if (!Reg.isVirtual() || !shouldAllocateRegister(Reg))
1392-
continue;
1393-
1394-
if (MO.isUndef()) {
1395-
HasUndefUse = true;
1396-
continue;
1397-
}
1398-
1421+
bool ReArrangedImplicitMOs = true;
1422+
while (ReArrangedImplicitMOs) {
1423+
ReArrangedImplicitMOs = false;
1424+
for (unsigned I = 0; I < MI.getNumOperands(); ++I) {
1425+
MachineOperand &MO = MI.getOperand(I);
1426+
if (!MO.isReg() || !MO.isUse())
1427+
continue;
1428+
Register Reg = MO.getReg();
1429+
if (!Reg.isVirtual() || !shouldAllocateRegister(Reg))
1430+
continue;
13991431

1400-
// Populate MayLiveAcrossBlocks in case the use block is allocated before
1401-
// the def block (removing the vreg uses).
1402-
mayLiveIn(Reg);
1432+
if (MO.isUndef()) {
1433+
HasUndefUse = true;
1434+
continue;
1435+
}
14031436

1437+
// Populate MayLiveAcrossBlocks in case the use block is allocated before
1438+
// the def block (removing the vreg uses).
1439+
mayLiveIn(Reg);
14041440

1405-
assert(!MO.isInternalRead() && "Bundles not supported");
1406-
assert(MO.readsReg() && "reading use");
1407-
useVirtReg(MI, I, Reg);
1441+
assert(!MO.isInternalRead() && "Bundles not supported");
1442+
assert(MO.readsReg() && "reading use");
1443+
ReArrangedImplicitMOs = useVirtReg(MI, I, Reg);
1444+
if (ReArrangedImplicitMOs)
1445+
break;
1446+
}
14081447
}
14091448

14101449
// Allocate undef operands. This is a separate step because in a situation

0 commit comments

Comments
 (0)