[llvm] [MachineLICM] Only mark live-ins as non-invariant if defined in loop (PR #191755)
Yuyang Zhang via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 23 00:09:17 PDT 2026
================
@@ -596,20 +596,37 @@ void MachineLICMImpl::HoistRegionPostRA(MachineLoop *CurLoop) {
SmallVector<CandidateInfo, 32> Candidates;
SmallDenseSet<int> StoredFIs;
- // Walk the entire region, count number of defs for each register, and
- // collect potential LICM candidates.
+ // First pass: collect all register units defined within the loop.
+ BitVector LoopRUDefs(NumRegUnits);
+ for (MachineBasicBlock *BB : CurLoop->getBlocks()) {
+ for (MachineInstr &MI : *BB) {
+ for (const MachineOperand &MO : MI.operands()) {
+ if (!MO.isReg() || !MO.isDef())
+ continue;
+ Register Reg = MO.getReg();
+ if (!Reg)
+ continue;
+ for (MCRegUnit Unit : TRI->regunits(Reg))
+ LoopRUDefs.set(static_cast<unsigned>(Unit));
+ }
+ }
+ }
+
+ // Second pass: walk the entire region, count number of defs for each
+ // register, and collect potential LICM candidates.
for (MachineBasicBlock *BB : CurLoop->getBlocks()) {
// If the header of the loop containing this basic block is a landing pad,
// then don't try to hoist instructions out of this loop.
const MachineLoop *ML = MLI->getLoopFor(BB);
if (ML && ML->getHeader()->isEHPad()) continue;
- // Conservatively treat live-in's as an external def.
- // FIXME: That means a reload that're reused in successor block(s) will not
- // be LICM'ed.
+ // Only treat live-in registers that are also defined within the loop as
+ // non-invariant. Live-ins that are solely defined outside the loop are
+ // loop-invariant and should not block hoisting.
for (const auto &LI : BB->liveins()) {
for (MCRegUnit Unit : TRI->regunits(LI.PhysReg))
- RUDefs.set(static_cast<unsigned>(Unit));
+ if (LoopRUDefs.test(static_cast<unsigned>(Unit)))
+ RUDefs.set(static_cast<unsigned>(Unit));
----------------
yuyzhang512 wrote:
`RUDefs` is still needed for on-the-fly multi-def detection. It is built incrementally, so when `ProcessMI` reaches a definition of a register unit already present in `RUDefs`, that register unit has been defined by another instruction and is added to `RUClobbers`. `LoopRUDefs` cannot serve this purpose because it already contains the current instruction's own definition, making every definition appear to be a redefinition.
The live-in marking is also required for correctness rather than merely being conservative. Without it, a loop-carried register that is defined only once in the loop would no longer be forced into `RUClobbers`, allowing its definition to be hoisted. For example:
```
loop:
$x2 = ADDXri $x0, 0, 0 ; reads live-in $x0
$x0 = MOVi64imm 5 ; single invariant def of $x0
```
Without the live-in marking, `$x0 = MOVi64imm 5` is hoisted into the preheader, causing the first iteration to read `5` instead of the incoming value of `$x0`, resulting in a miscompile.
https://github.com/llvm/llvm-project/pull/191755
More information about the llvm-commits
mailing list