[llvm] [AArch64MIPeepholeOpt] Coalesce sibling base-address materializations (PR #223682)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 21 23:24:54 PDT 2026
================
@@ -957,6 +966,106 @@ bool AArch64MIPeepholeOptImpl::visitCopy(MachineInstr &MI) {
return true;
}
+bool AArch64MIPeepholeOptImpl::shareBaseAddresses(MachineBasicBlock &MBB) {
+ if (!EnableBaseAddressCSE)
+ return false;
+
+ bool Changed = false;
+
+ struct Cand {
+ MachineInstr *DefMI;
+ Register SrcReg;
+ unsigned Opc;
+ int64_t C;
+ Register BaseReg;
+ MachineInstr *UserMI;
+ int Scale;
+ int64_t OldOff;
+ };
+ SmallVector<Cand, 8> Cands;
+ using Key = std::pair<Register, unsigned>;
+ MapVector<Key, SmallVector<unsigned, 4>> Groups;
+
+ DenseMap<MachineInstr *, unsigned> Pos;
+ unsigned Idx = 0;
+ for (MachineInstr &MI : MBB.instrs()) {
+ Pos[&MI] = Idx++;
+ unsigned Opc = MI.getOpcode();
+ if (Opc != AArch64::ADDXri && Opc != AArch64::SUBXri)
+ continue;
+ if (!MI.getOperand(2).isImm() || !MI.getOperand(3).isImm() ||
+ MI.getOperand(3).getImm() != 0) // shift must be 0 (no LSL #12)
+ continue;
+ Register SrcReg = MI.getOperand(1).getReg();
+ Register BaseReg = MI.getOperand(0).getReg();
+ if (!SrcReg.isVirtual() || !BaseReg.isVirtual() ||
+ !MRI->hasOneUse(BaseReg)) // secondary def is erased below
+ continue;
+ MachineInstr &User = *MRI->use_instr_begin(BaseReg);
+ if (!User.mayLoadOrStore() || AArch64InstrInfo::isPairedLdSt(User) ||
+ AArch64InstrInfo::isPreLdSt(User) || // different operand layout
+ TII->hasUnscaledLdStOffset(User) || // rewrite below assumes scaled
+ !AArch64InstrInfo::getLdStOffsetOp(User).isImm())
+ continue;
+ const MachineOperand &BaseOp = AArch64InstrInfo::getLdStBaseOp(User);
+ if (!BaseOp.isReg() || BaseOp.getReg() != BaseReg)
+ continue;
+ unsigned CIdx = Cands.size();
+ Cands.push_back({&MI, SrcReg, Opc, MI.getOperand(2).getImm(), BaseReg,
+ &User, TII->getMemScale(User),
+ AArch64InstrInfo::getLdStOffsetOp(User).getImm()});
+ Groups[{SrcReg, Opc}].push_back(CIdx);
+ }
+
+ auto Eff = [](const Cand &C) {
+ return C.Opc == AArch64::ADDXri ? C.C : -C.C;
+ };
+
+ for (auto &Group : Groups) {
+ auto &Idxs = Group.second;
+ if (Idxs.size() < 2)
+ continue;
+ unsigned PrimaryIdx = Idxs[0];
+ for (unsigned i : Idxs)
+ if (Eff(Cands[i]) < Eff(Cands[PrimaryIdx]))
+ PrimaryIdx = i;
+ const Cand &Primary = Cands[PrimaryIdx];
+ Register PrimaryBaseReg = Primary.BaseReg;
+ MachineInstr *PrimaryDef = Primary.DefMI;
+
+ for (unsigned i : Idxs) {
+ if (i == PrimaryIdx)
+ continue;
+ Cand &Sec = Cands[i];
+ int64_t Delta = Eff(Sec) - Eff(Primary);
+ if (Delta % Sec.Scale != 0)
+ continue;
+ int64_t NewOff = Sec.OldOff + Delta / Sec.Scale;
+ if (NewOff < 0 || NewOff > 0xFFF)
+ continue;
+ if (Pos[PrimaryDef] >= Pos[Sec.UserMI])
----------------
whokeke wrote:
Done. The check is NewOff < 0 || NewOff > 0xFFF — 0xFFF is the encoding limit of the 12-bit unsigned scaled immediate that LDRWui/STRXui/etc. use (uimm12), and NewOff < 0 guards against the rewrite producing a negative offset, which that addressing mode can't encode at all. Added a comment spelling this out.
https://github.com/llvm/llvm-project/pull/223682
More information about the llvm-commits
mailing list