[llvm] [CodeGen] Notify delegate before erasing folded instruction (PR #222919)

via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 11 06:53:19 PDT 2026


https://github.com/GongJianxiang-Ben updated https://github.com/llvm/llvm-project/pull/222919

>From afe85ca4ac23a76bddb371b592080573889d7edc Mon Sep 17 00:00:00 2001
From: Gong Jianxiang <3247276791 at qq.com>
Date: Fri, 11 Sep 2026 18:50:20 +0800
Subject: [PATCH 1/3] [CodeGen] Notify delegate before erasing folded
 instruction

---
 llvm/lib/CodeGen/LiveRangeEdit.cpp | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/CodeGen/LiveRangeEdit.cpp b/llvm/lib/CodeGen/LiveRangeEdit.cpp
index 1d6b835f16468..3059b4f583724 100644
--- a/llvm/lib/CodeGen/LiveRangeEdit.cpp
+++ b/llvm/lib/CodeGen/LiveRangeEdit.cpp
@@ -24,12 +24,12 @@ using namespace llvm;
 
 #define DEBUG_TYPE "regalloc"
 
-STATISTIC(NumDCEDeleted,        "Number of instructions deleted by DCE");
-STATISTIC(NumDCEFoldedLoads,    "Number of single use loads folded after DCE");
-STATISTIC(NumFracRanges,        "Number of live ranges fractured by DCE");
+STATISTIC(NumDCEDeleted, "Number of instructions deleted by DCE");
+STATISTIC(NumDCEFoldedLoads, "Number of single use loads folded after DCE");
+STATISTIC(NumFracRanges, "Number of live ranges fractured by DCE");
 STATISTIC(NumReMaterialization, "Number of instructions rematerialized");
 
-void LiveRangeEdit::Delegate::anchor() { }
+void LiveRangeEdit::Delegate::anchor() {}
 
 LiveInterval &LiveRangeEdit::createEmptyIntervalFrom(Register OldReg,
                                                      bool createSubRanges) {
@@ -108,7 +108,7 @@ void LiveRangeEdit::eraseVirtReg(Register Reg) {
 }
 
 bool LiveRangeEdit::foldAsLoad(LiveInterval *LI,
-                               SmallVectorImpl<MachineInstr*> &Dead) {
+                               SmallVectorImpl<MachineInstr *> &Dead) {
   MachineInstr *DefMI = nullptr, *UseMI = nullptr;
 
   // Check that there is a single def and a single use.
@@ -161,6 +161,8 @@ bool LiveRangeEdit::foldAsLoad(LiveInterval *LI,
   // Update the call info.
   if (UseMI->shouldUpdateAdditionalCallInfo())
     UseMI->getMF()->moveAdditionalCallInfo(UseMI, FoldMI);
+  if (TheDelegate)
+    TheDelegate->LRE_WillEraseInstruction(UseMI);
   UseMI->eraseFromParent();
   DefMI->addRegisterDead(LI->reg(), nullptr);
   Dead.push_back(DefMI);
@@ -339,10 +341,10 @@ void LiveRangeEdit::eliminateDeadDef(MachineInstr *MI, ToShrinkSet &ToShrink) {
     MI->setDesc(TII.get(TargetOpcode::KILL));
     // Remove all operands that aren't physregs.
     for (unsigned i = MI->getNumOperands(); i; --i) {
-      const MachineOperand &MO = MI->getOperand(i-1);
+      const MachineOperand &MO = MI->getOperand(i - 1);
       if (MO.isReg() && MO.getReg().isPhysical())
         continue;
-      MI->removeOperand(i-1);
+      MI->removeOperand(i - 1);
     }
     MI->dropMemRefs(*MI->getMF());
     LLVM_DEBUG(dbgs() << "Converted physregs to:\t" << *MI);
@@ -395,7 +397,7 @@ void LiveRangeEdit::eliminateDeadDefs(SmallVectorImpl<MachineInstr *> &Dead,
 
     // LI may have been separated, create new intervals.
     LI->RenumberValues();
-    SmallVector<LiveInterval*, 8> SplitLIs;
+    SmallVector<LiveInterval *, 8> SplitLIs;
     LIS.splitSeparateComponents(*LI, SplitLIs);
     if (!SplitLIs.empty())
       ++NumFracRanges;
@@ -415,8 +417,7 @@ void LiveRangeEdit::eliminateDeadDefs(SmallVectorImpl<MachineInstr *> &Dead,
 
 // Keep track of new virtual registers created via
 // MachineRegisterInfo::createVirtualRegister.
-void
-LiveRangeEdit::MRI_NoteNewVirtualRegister(Register VReg) {
+void LiveRangeEdit::MRI_NoteNewVirtualRegister(Register VReg) {
   if (VRM)
     VRM->grow();
 

>From 45afaa06b7248cedaea596e6f7310f377f0c03d2 Mon Sep 17 00:00:00 2001
From: Gong Jianxiang <3247276791 at qq.com>
Date: Fri, 11 Sep 2026 20:02:40 +0800
Subject: [PATCH 2/3] Revert some formatting changes

---
 llvm/lib/CodeGen/LiveRangeEdit.cpp | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/CodeGen/LiveRangeEdit.cpp b/llvm/lib/CodeGen/LiveRangeEdit.cpp
index 3059b4f583724..71b1dda6edd8c 100644
--- a/llvm/lib/CodeGen/LiveRangeEdit.cpp
+++ b/llvm/lib/CodeGen/LiveRangeEdit.cpp
@@ -24,12 +24,12 @@ using namespace llvm;
 
 #define DEBUG_TYPE "regalloc"
 
-STATISTIC(NumDCEDeleted, "Number of instructions deleted by DCE");
-STATISTIC(NumDCEFoldedLoads, "Number of single use loads folded after DCE");
-STATISTIC(NumFracRanges, "Number of live ranges fractured by DCE");
+STATISTIC(NumDCEDeleted,        "Number of instructions deleted by DCE");
+STATISTIC(NumDCEFoldedLoads,    "Number of single use loads folded after DCE");
+STATISTIC(NumFracRanges,        "Number of live ranges fractured by DCE");
 STATISTIC(NumReMaterialization, "Number of instructions rematerialized");
 
-void LiveRangeEdit::Delegate::anchor() {}
+void LiveRangeEdit::Delegate::anchor() { }
 
 LiveInterval &LiveRangeEdit::createEmptyIntervalFrom(Register OldReg,
                                                      bool createSubRanges) {
@@ -108,7 +108,7 @@ void LiveRangeEdit::eraseVirtReg(Register Reg) {
 }
 
 bool LiveRangeEdit::foldAsLoad(LiveInterval *LI,
-                               SmallVectorImpl<MachineInstr *> &Dead) {
+                               SmallVectorImpl<MachineInstr*> &Dead) {
   MachineInstr *DefMI = nullptr, *UseMI = nullptr;
 
   // Check that there is a single def and a single use.
@@ -341,10 +341,10 @@ void LiveRangeEdit::eliminateDeadDef(MachineInstr *MI, ToShrinkSet &ToShrink) {
     MI->setDesc(TII.get(TargetOpcode::KILL));
     // Remove all operands that aren't physregs.
     for (unsigned i = MI->getNumOperands(); i; --i) {
-      const MachineOperand &MO = MI->getOperand(i - 1);
+      const MachineOperand &MO = MI->getOperand(i-1);
       if (MO.isReg() && MO.getReg().isPhysical())
         continue;
-      MI->removeOperand(i - 1);
+      MI->removeOperand(i-1);
     }
     MI->dropMemRefs(*MI->getMF());
     LLVM_DEBUG(dbgs() << "Converted physregs to:\t" << *MI);
@@ -397,7 +397,7 @@ void LiveRangeEdit::eliminateDeadDefs(SmallVectorImpl<MachineInstr *> &Dead,
 
     // LI may have been separated, create new intervals.
     LI->RenumberValues();
-    SmallVector<LiveInterval *, 8> SplitLIs;
+    SmallVector<LiveInterval*, 8> SplitLIs;
     LIS.splitSeparateComponents(*LI, SplitLIs);
     if (!SplitLIs.empty())
       ++NumFracRanges;

>From 113f7d5ed45ed80ddb233882d0a9a854e7632ba7 Mon Sep 17 00:00:00 2001
From: Gong Jianxiang <3247276791 at qq.com>
Date: Fri, 11 Sep 2026 21:51:09 +0800
Subject: [PATCH 3/3] Include some RISCVInstrInfo backend and a test case

---
 llvm/lib/Target/RISCV/RISCVInstrInfo.cpp      | 13 +++++++++
 llvm/lib/Target/RISCV/RISCVInstrInfo.td       |  2 +-
 .../CodeGen/RISCV/foldasload-coalescer-uaf.ll | 27 +++++++++++++++++++
 3 files changed, 41 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/CodeGen/RISCV/foldasload-coalescer-uaf.ll

diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index ee47963aa041e..a7e21c8652c41 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -969,6 +969,19 @@ MachineInstr *RISCVInstrInfo::foldMemoryOperandImpl(
     MachineInstr &LoadMI, MachineInstr *&CopyMI, LiveIntervals *LIS,
     VirtRegMap *VRM) const {
   MachineBasicBlock::iterator InsertPt = MI;
+
+  if (MI.isCopy() && Ops.size() == 1 && Ops[0] == 1 &&
+      LoadMI.getOpcode() == RISCV::ADDI &&
+      LoadMI.getOperand(1).getReg() == RISCV::X0 &&
+      LoadMI.getOperand(2).isImm()) {
+    int64_t Imm = LoadMI.getOperand(2).getImm();
+    if (!isInt<32>(Imm))
+      return nullptr;
+    return BuildMI(*MI.getParent(), InsertPt, MI.getDebugLoc(),
+                   get(RISCV::PseudoMovImm), MI.getOperand(0).getReg())
+        .addImm(Imm);
+  }
+
   // For now, only handle RISCV::PseudoCCMOVGPR.
   if (MI.getOpcode() != RISCV::PseudoCCMOVGPR)
     return nullptr;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index a9dafff24862c..626c38b1f807d 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -862,7 +862,7 @@ def SW : Store_rri<0b010, "sw">, Sched<[WriteSTW, ReadStoreData, ReadMemBase]>;
 
 // ADDI isn't always rematerializable, but isReMaterializable will be used as
 // a hint which is verified in isReMaterializableImpl.
-let isReMaterializable = 1, isAsCheapAsAMove = 1 in
+let canFoldAsLoad = 1, isReMaterializable = 1, isAsCheapAsAMove = 1 in
 def ADDI  : ALU_ri<0b000, "addi">;
 
 let IsSignExtendingOpW = 1 in {
diff --git a/llvm/test/CodeGen/RISCV/foldasload-coalescer-uaf.ll b/llvm/test/CodeGen/RISCV/foldasload-coalescer-uaf.ll
new file mode 100644
index 0000000000000..75cf4fec3c327
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/foldasload-coalescer-uaf.ll
@@ -0,0 +1,27 @@
+; RUN: llc -O3 -mtriple=riscv64 -riscv-use-rematerializable-movimm \
+; RUN:   < %s -o /dev/null
+
+; This keeps a rematerializable immediate and a COPY alive through register
+; coalescing. LiveRangeEdit::foldAsLoad() folds the immediate into the COPY,
+; then removes the old COPY from the coalescer worklist.
+
+target triple = "riscv64-pc-unknown-gnu"
+
+define void @f() {
+entry:
+  br label %loop
+
+loop:
+  %i32 = phi i32 [ %and, %inc ], [ 3, %entry ]
+  %i8 = phi i8 [ %tr, %inc ], [ 3, %entry ]
+  %c = icmp eq i8 %i8, 0
+  br i1 %c, label %exit, label %inc
+
+exit:
+  ret void
+
+inc:
+  %tr = trunc i32 %i32 to i8
+  %and = and i32 %i32, 255
+  br label %loop
+}
\ No newline at end of file



More information about the llvm-commits mailing list