[llvm] 3c3c850 - [ReachingDefAnalysis] Extend the analysis to stack objects. (#118097)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 29 07:55:19 PST 2025


Author: Mikhail Gudim
Date: 2025-01-29T10:55:16-05:00
New Revision: 3c3c850a45c8f1ea1e9d6aa514e2b6076d1a4534

URL: https://github.com/llvm/llvm-project/commit/3c3c850a45c8f1ea1e9d6aa514e2b6076d1a4534
DIFF: https://github.com/llvm/llvm-project/commit/3c3c850a45c8f1ea1e9d6aa514e2b6076d1a4534.diff

LOG: [ReachingDefAnalysis] Extend the analysis to stack objects. (#118097)

We track definitions of stack objects, the implementation is identical
to tracking of registers.

Also, added printing of all found reaching definitions for testing
purposes.

---------

Co-authored-by: Michael Maitland <michaeltmaitland at gmail.com>

Added: 
    llvm/test/CodeGen/RISCV/rda-stack.mir
    llvm/test/CodeGen/SystemZ/rda-stack-copy.mir

Modified: 
    llvm/include/llvm/CodeGen/ReachingDefAnalysis.h
    llvm/lib/CodeGen/ReachingDefAnalysis.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/CodeGen/ReachingDefAnalysis.h b/llvm/include/llvm/CodeGen/ReachingDefAnalysis.h
index 2e976a88b4cea1..cff422f539f62d 100644
--- a/llvm/include/llvm/CodeGen/ReachingDefAnalysis.h
+++ b/llvm/include/llvm/CodeGen/ReachingDefAnalysis.h
@@ -114,8 +114,11 @@ class ReachingDefAnalysis : public MachineFunctionPass {
 private:
   MachineFunction *MF = nullptr;
   const TargetRegisterInfo *TRI = nullptr;
+  const TargetInstrInfo *TII = nullptr;
   LoopTraversal::TraversalOrder TraversedMBBOrder;
   unsigned NumRegUnits = 0;
+  unsigned NumStackObjects = 0;
+  int ObjectIndexBegin = 0;
   /// Instruction that defined each register, relative to the beginning of the
   /// current basic block.  When a LiveRegsDefInfo is used to represent a
   /// live-out register, this value is relative to the end of the basic block,
@@ -138,6 +141,13 @@ class ReachingDefAnalysis : public MachineFunctionPass {
   DenseMap<MachineInstr *, int> InstIds;
 
   MBBReachingDefsInfo MBBReachingDefs;
+  using MBBFrameObjsReachingDefsInfo =
+      DenseMap<unsigned, DenseMap<int, SmallVector<int>>>;
+  // MBBFrameObjsReachingDefs[i][j] is a list of instruction indices (relative
+  // to begining of MBB) that define frame index (j +
+  // MF->getFrameInfo().getObjectIndexBegin()) in MBB i. This is used in
+  // answering reaching definition queries.
+  MBBFrameObjsReachingDefsInfo MBBFrameObjsReachingDefs;
 
   /// Default values are 'nothing happened a long time ago'.
   const int ReachingDefDefaultVal = -(1 << 21);
@@ -158,6 +168,7 @@ class ReachingDefAnalysis : public MachineFunctionPass {
     MachineFunctionPass::getAnalysisUsage(AU);
   }
 
+  void printAllReachingDefs(MachineFunction &MF);
   bool runOnMachineFunction(MachineFunction &MF) override;
 
   MachineFunctionProperties getRequiredProperties() const override {
@@ -177,6 +188,7 @@ class ReachingDefAnalysis : public MachineFunctionPass {
 
   /// Provides the instruction id of the closest reaching def instruction of
   /// Reg that reaches MI, relative to the begining of MI's basic block.
+  /// Note that Reg may represent a stack slot.
   int getReachingDef(MachineInstr *MI, Register Reg) const;
 
   /// Return whether A and B use the same def of Reg.
@@ -305,6 +317,7 @@ class ReachingDefAnalysis : public MachineFunctionPass {
 
   /// Provides the instruction of the closest reaching def instruction of
   /// Reg that reaches MI, relative to the begining of MI's basic block.
+  /// Note that Reg may represent a stack slot.
   MachineInstr *getReachingLocalMIDef(MachineInstr *MI, Register Reg) const;
 };
 

diff  --git a/llvm/lib/CodeGen/ReachingDefAnalysis.cpp b/llvm/lib/CodeGen/ReachingDefAnalysis.cpp
index 9459904d56e4c3..3d88c6815d51c9 100644
--- a/llvm/lib/CodeGen/ReachingDefAnalysis.cpp
+++ b/llvm/lib/CodeGen/ReachingDefAnalysis.cpp
@@ -10,6 +10,8 @@
 #include "llvm/ADT/SetOperations.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/CodeGen/LiveRegUnits.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/TargetInstrInfo.h"
 #include "llvm/CodeGen/TargetRegisterInfo.h"
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include "llvm/Support/Debug.h"
@@ -18,6 +20,10 @@ using namespace llvm;
 
 #define DEBUG_TYPE "reaching-defs-analysis"
 
+static cl::opt<bool> PrintAllReachingDefs("print-all-reaching-defs", cl::Hidden,
+                                          cl::desc("Used for test purpuses"),
+                                          cl::Hidden);
+
 char ReachingDefAnalysis::ID = 0;
 INITIALIZE_PASS(ReachingDefAnalysis, DEBUG_TYPE, "ReachingDefAnalysis", false,
                 true)
@@ -48,6 +54,16 @@ static bool isValidRegDefOf(const MachineOperand &MO, Register Reg,
   return TRI->regsOverlap(MO.getReg(), Reg);
 }
 
+static bool isFIDef(const MachineInstr &MI, int FrameIndex,
+                    const TargetInstrInfo *TII) {
+  int DefFrameIndex = 0;
+  int SrcFrameIndex = 0;
+  if (TII->isStoreToStackSlot(MI, DefFrameIndex) ||
+      TII->isStackSlotCopy(MI, DefFrameIndex, SrcFrameIndex))
+    return DefFrameIndex == FrameIndex;
+  return false;
+}
+
 void ReachingDefAnalysis::enterBasicBlock(MachineBasicBlock *MBB) {
   unsigned MBBNumber = MBB->getNumber();
   assert(MBBNumber < MBBReachingDefs.numBlockIDs() &&
@@ -126,6 +142,22 @@ void ReachingDefAnalysis::processDefs(MachineInstr *MI) {
          "Unexpected basic block number.");
 
   for (auto &MO : MI->operands()) {
+    if (MO.isFI()) {
+      int FrameIndex = MO.getIndex();
+      assert(FrameIndex >= 0 && "Can't handle negative frame indicies yet!");
+      if (!isFIDef(*MI, FrameIndex, TII))
+        continue;
+      if (MBBFrameObjsReachingDefs.contains(MBBNumber)) {
+        auto Frame2InstrIdx = MBBFrameObjsReachingDefs[MBBNumber];
+        if (Frame2InstrIdx.count(FrameIndex - ObjectIndexBegin) > 0)
+          Frame2InstrIdx[FrameIndex - ObjectIndexBegin].push_back(CurInstr);
+        else
+          Frame2InstrIdx[FrameIndex - ObjectIndexBegin] = {CurInstr};
+      } else {
+        MBBFrameObjsReachingDefs[MBBNumber] = {
+            {FrameIndex - ObjectIndexBegin, {CurInstr}}};
+      }
+    }
     if (!isValidRegDef(MO))
       continue;
     for (MCRegUnit Unit : TRI->regunits(MO.getReg().asMCReg())) {
@@ -209,12 +241,54 @@ void ReachingDefAnalysis::processBasicBlock(
   leaveBasicBlock(MBB);
 }
 
+void ReachingDefAnalysis::printAllReachingDefs(MachineFunction &MF) {
+  dbgs() << "RDA results for " << MF.getName() << "\n";
+  int Num = 0;
+  DenseMap<MachineInstr *, int> InstToNumMap;
+  SmallPtrSet<MachineInstr *, 2> Defs;
+  for (MachineBasicBlock &MBB : MF) {
+    for (MachineInstr &MI : MBB) {
+      for (MachineOperand &MO : MI.operands()) {
+        Register Reg;
+        if (MO.isFI()) {
+          int FrameIndex = MO.getIndex();
+          assert(FrameIndex >= 0 &&
+                 "Can't handle negative frame indicies yet!");
+          Reg = Register::index2StackSlot(FrameIndex);
+        } else if (MO.isReg()) {
+          if (MO.isDef())
+            continue;
+          Reg = MO.getReg();
+          if (!Reg.isValid())
+            continue;
+        } else
+          continue;
+        Defs.clear();
+        getGlobalReachingDefs(&MI, Reg, Defs);
+        MO.print(dbgs(), TRI);
+        dbgs() << ":{ ";
+        for (MachineInstr *Def : Defs)
+          dbgs() << InstToNumMap[Def] << " ";
+        dbgs() << "}\n";
+      }
+      dbgs() << Num << ": " << MI << "\n";
+      InstToNumMap[&MI] = Num;
+      ++Num;
+    }
+  }
+}
+
 bool ReachingDefAnalysis::runOnMachineFunction(MachineFunction &mf) {
   MF = &mf;
   TRI = MF->getSubtarget().getRegisterInfo();
+  const TargetSubtargetInfo &STI = MF->getSubtarget();
+  TRI = STI.getRegisterInfo();
+  TII = STI.getInstrInfo();
   LLVM_DEBUG(dbgs() << "********** REACHING DEFINITION ANALYSIS **********\n");
   init();
   traverse();
+  if (PrintAllReachingDefs)
+    printAllReachingDefs(*MF);
   return false;
 }
 
@@ -222,6 +296,7 @@ void ReachingDefAnalysis::releaseMemory() {
   // Clear the internal vectors.
   MBBOutRegsInfos.clear();
   MBBReachingDefs.clear();
+  MBBFrameObjsReachingDefs.clear();
   InstIds.clear();
   LiveRegs.clear();
 }
@@ -234,6 +309,8 @@ void ReachingDefAnalysis::reset() {
 
 void ReachingDefAnalysis::init() {
   NumRegUnits = TRI->getNumRegUnits();
+  NumStackObjects = MF->getFrameInfo().getNumObjects();
+  ObjectIndexBegin = MF->getFrameInfo().getObjectIndexBegin();
   MBBReachingDefs.init(MF->getNumBlockIDs());
   // Initialize the MBBOutRegsInfos
   MBBOutRegsInfos.resize(MF->getNumBlockIDs());
@@ -268,6 +345,19 @@ int ReachingDefAnalysis::getReachingDef(MachineInstr *MI, Register Reg) const {
   assert(MBBNumber < MBBReachingDefs.numBlockIDs() &&
          "Unexpected basic block number.");
   int LatestDef = ReachingDefDefaultVal;
+
+  if (Register::isStackSlot(Reg)) {
+    int FrameIndex = Register::stackSlot2Index(Reg);
+    for (int Def : MBBFrameObjsReachingDefs.lookup(MBBNumber).lookup(
+             FrameIndex - ObjectIndexBegin)) {
+      if (Def >= InstId)
+        break;
+      DefRes = Def;
+    }
+    LatestDef = std::max(LatestDef, DefRes);
+    return LatestDef;
+  }
+
   for (MCRegUnit Unit : TRI->regunits(Reg)) {
     for (int Def : MBBReachingDefs.defs(MBBNumber, Unit)) {
       if (Def >= InstId)
@@ -419,7 +509,7 @@ void ReachingDefAnalysis::getLiveOuts(MachineBasicBlock *MBB, Register Reg,
   VisitedBBs.insert(MBB);
   LiveRegUnits LiveRegs(*TRI);
   LiveRegs.addLiveOuts(*MBB);
-  if (LiveRegs.available(Reg))
+  if (Register::isPhysicalRegister(Reg) && LiveRegs.available(Reg))
     return;
 
   if (auto *Def = getLocalLiveOutMIDef(MBB, Reg))
@@ -500,7 +590,7 @@ bool ReachingDefAnalysis::isReachingDefLiveOut(MachineInstr *MI,
   MachineBasicBlock *MBB = MI->getParent();
   LiveRegUnits LiveRegs(*TRI);
   LiveRegs.addLiveOuts(*MBB);
-  if (LiveRegs.available(Reg))
+  if (Register::isPhysicalRegister(Reg) && LiveRegs.available(Reg))
     return false;
 
   auto Last = MBB->getLastNonDebugInstr();
@@ -520,14 +610,21 @@ MachineInstr *ReachingDefAnalysis::getLocalLiveOutMIDef(MachineBasicBlock *MBB,
                                                         Register Reg) const {
   LiveRegUnits LiveRegs(*TRI);
   LiveRegs.addLiveOuts(*MBB);
-  if (LiveRegs.available(Reg))
+  if (Register::isPhysicalRegister(Reg) && LiveRegs.available(Reg))
     return nullptr;
 
   auto Last = MBB->getLastNonDebugInstr();
   if (Last == MBB->end())
     return nullptr;
 
+  if (Register::isStackSlot(Reg)) {
+    int FrameIndex = Register::stackSlot2Index(Reg);
+    if (isFIDef(*Last, FrameIndex, TII))
+      return &*Last;
+  }
+
   int Def = getReachingDef(&*Last, Reg);
+
   for (auto &MO : Last->operands())
     if (isValidRegDefOf(MO, Reg, TRI))
       return &*Last;

diff  --git a/llvm/test/CodeGen/RISCV/rda-stack.mir b/llvm/test/CodeGen/RISCV/rda-stack.mir
new file mode 100644
index 00000000000000..5f4974181c1cd5
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rda-stack.mir
@@ -0,0 +1,151 @@
+# RUN: llc %s -mtriple=riscv64 -run-pass=reaching-defs-analysis -print-all-reaching-defs -o - 2>&1 | FileCheck %s
+
+---
+name:            test0
+tracksRegLiveness: true
+stack:
+  - { id: 0, name: '', type: default, offset: 0, size: 4, alignment: 4,
+      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+body:             |
+  ; CHECK-LABEL: RDA results for test0
+  ; CHECK-NEXT: %stack.0:{ }
+  ; CHECK-NEXT:0: $x10 = LD %stack.0, 0 :: (load (s64))
+  ; CHECK-EMPTY:
+  ; CHECK-NEXT: implicit $x10:{ 0 }
+  ; CHECK-NEXT:1: PseudoRET implicit $x10
+
+  bb.0.entry:
+    $x10 = LD %stack.0, 0 :: (load (s64))
+    PseudoRET implicit $x10
+
+...
+---
+name:            test1
+tracksRegLiveness: true
+stack:
+  - { id: 0, name: '', type: default, offset: 0, size: 4, alignment: 4,
+      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+  - { id: 1, name: '', type: default, offset: 0, size: 4, alignment: 4,
+      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+body:             |
+  ; CHECK-LABEL: RDA results for test1
+  ; CHECK-NEXT: %stack.0:{ }
+  ; CHECK-NEXT: 0: $x10 = LD %stack.0, 0 :: (load (s64))
+  ; CHECK-EMPTY: 
+  ; CHECK-NEXT: %stack.1:{ }
+  ; CHECK-NEXT: 1: $x11 = LD %stack.1, 0 :: (load (s64))
+  ; CHECK-EMPTY: 
+  ; CHECK-NEXT: $x10:{ 0 }
+  ; CHECK-NEXT: $x11:{ 1 }
+  ; CHECK-NEXT: 2: $x10 = ADD $x10, $x11
+  ; CHECK-EMPTY: 
+  ; CHECK-NEXT: implicit $x10:{ 2 }
+  ; CHECK-NEXT: 3: PseudoRET implicit $x10
+
+  bb.0.entry:
+    $x10 = LD %stack.0, 0 :: (load (s64))
+    $x11 = LD %stack.1, 0 :: (load (s64))
+    $x10 = ADD $x10, $x11
+    PseudoRET implicit $x10
+
+...
+---
+name:            test2
+tracksRegLiveness: true
+stack:
+  - { id: 0, name: '', type: default, offset: 0, size: 4, alignment: 4,
+      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+  - { id: 1, name: '', type: default, offset: 0, size: 4, alignment: 4,
+      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+body:             |
+  ; CHECK-LABEL: RDA results for test2
+  ; CHECK-NEXT: %stack.0:{ }
+  ; CHECK-NEXT: 0: $x10 = LD %stack.0, 0 :: (load (s64))
+  ; CHECK-EMPTY: 
+  ; CHECK-NEXT: %stack.1:{ }
+  ; CHECK-NEXT: 1: $x11 = LD %stack.1, 0 :: (load (s64))
+  ; CHECK-EMPTY: 
+  ; CHECK-NEXT: $x10:{ 0 }
+  ; CHECK-NEXT: $x11:{ 1 }
+  ; CHECK-NEXT: 2: $x10 = ADD $x10, $x11
+  ; CHECK-EMPTY: 
+  ; CHECK-NEXT: $x10:{ 2 }
+  ; CHECK-NEXT: %stack.0:{ }
+  ; CHECK-NEXT: 3: SD $x10, %stack.0, 0 :: (store (s64))
+  ; CHECK-EMPTY: 
+  ; CHECK-NEXT: %stack.0:{ 3 }
+  ; CHECK-NEXT: 4: $x10 = LD %stack.0, 0 :: (load (s64))
+  ; CHECK-EMPTY: 
+  ; CHECK-NEXT: implicit $x10:{ 4 }
+  ; CHECK-NEXT: 5: PseudoRET implicit $x10
+
+  bb.0.entry:
+    $x10 = LD %stack.0, 0 :: (load (s64))
+    $x11 = LD %stack.1, 0 :: (load (s64))
+    $x10 = ADD $x10, $x11
+    SD $x10, %stack.0, 0 :: (store (s64))
+    $x10 = LD %stack.0, 0 :: (load (s64))
+    PseudoRET implicit $x10
+
+...
+---
+name:            test3
+tracksRegLiveness: true
+stack:
+  - { id: 0, name: '', type: default, offset: 0, size: 4, alignment: 4,
+      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+body:             |
+  ; CHECK-LABEL: RDA results for test3
+  ; CHECK-NEXT: $x10:{ }
+  ; CHECK-NEXT: $x0:{ }
+  ; CHECK-NEXT: 0: BEQ $x10, $x0, %bb.2
+  ; CHECK-EMPTY: 
+  ; CHECK-NEXT: $x10:{ }
+  ; CHECK-NEXT: 1: $x10 = ADDI $x10, 1
+  ; CHECK-EMPTY: 
+  ; CHECK-NEXT: $x10:{ 1 }
+  ; CHECK-NEXT: %stack.0:{ }
+  ; CHECK-NEXT: 2: SD $x10, %stack.0, 0 :: (store (s64))
+  ; CHECK-EMPTY: 
+  ; CHECK-NEXT: $x0:{ }
+  ; CHECK-NEXT: $x0:{ }
+  ; CHECK-NEXT: 3: BEQ $x0, $x0, %bb.3
+  ; CHECK-EMPTY: 
+  ; CHECK-NEXT: $x10:{ 1 }
+  ; CHECK-NEXT: 4: $x10 = ADDI $x10, 2
+  ; CHECK-EMPTY: 
+  ; CHECK-NEXT: $x10:{ 4 }
+  ; CHECK-NEXT: %stack.0:{ 2 }
+  ; CHECK-NEXT: 5: SD $x10, %stack.0, 0 :: (store (s64))
+  ; CHECK-EMPTY: 
+  ; CHECK-NEXT: %stack.0:{ 2 5 }
+  ; CHECK-NEXT: 6: $x10 = LD %stack.0, 0 :: (load (s64))
+  ; CHECK-EMPTY: 
+  ; CHECK-NEXT: implicit $x10:{ 6 }
+  ; CHECK-NEXT: 7: PseudoRET implicit $x10
+
+  bb.0.entry:
+    liveins: $x10
+    BEQ $x10, $x0, %bb.2
+
+  bb.1:
+    liveins: $x10
+    $x10 = ADDI $x10, 1
+    SD $x10, %stack.0, 0 :: (store (s64))
+    BEQ $x0, $x0, %bb.3
+
+  bb.2:
+    liveins: $x10
+    $x10 = ADDI $x10, 2
+    SD $x10, %stack.0, 0 :: (store (s64))
+
+  bb.3:
+    $x10 = LD %stack.0, 0 :: (load (s64))
+    PseudoRET implicit $x10
+...

diff  --git a/llvm/test/CodeGen/SystemZ/rda-stack-copy.mir b/llvm/test/CodeGen/SystemZ/rda-stack-copy.mir
new file mode 100644
index 00000000000000..a93b59324a8e52
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/rda-stack-copy.mir
@@ -0,0 +1,30 @@
+# RUN: llc %s -mtriple=s390x-linux-gnu -run-pass=reaching-defs-analysis -print-all-reaching-defs -o - 2>&1 | FileCheck %s
+
+---
+name:            test0
+tracksRegLiveness: true
+stack:
+  - { id: 0, name: '', type: default, offset: 0, size: 4, alignment: 4,
+      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+  - { id: 1, name: '', type: default, offset: 0, size: 4, alignment: 4,
+      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+body:             |
+  ; CHECK-LABEL: RDA results for test0
+  ; CHECK-NEXT: %stack.1:{ }
+  ; CHECK-NEXT: %stack.0:{ }
+  ; CHECK-NEXT: 0: MVC %stack.1, 0, 4, %stack.0, 0 :: (store (s32) into %stack.1), (load (s32) from %stack.0)
+  ; CHECK-EMPTY: 
+  ; CHECK-NEXT: %stack.1:{ 0 }
+  ; CHECK-NEXT: 1: $r2l = L %stack.1, 0, $noreg
+  ; CHECK-EMPTY: 
+  ; CHECK-NEXT: implicit $r2l:{ 1 }
+  ; CHECK-NEXT: 2: Return implicit $r2l
+
+  bb.0:
+    MVC %stack.1, 0 , 4, %stack.0, 0:: (store (s32) into %stack.1), (load (s32) from %stack.0)
+    $r2l = L %stack.1, 0, $noreg
+    Return implicit $r2l
+
+...


        


More information about the llvm-commits mailing list