[llvm] [SPARC] Implement TargetInstrInfo::insertIndirectBranch() (PR #226678)

via llvm-commits llvm-commits at lists.llvm.org
Sat Sep 26 04:26:49 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-sparc

Author: Koakuma (koachan)

<details>
<summary>Changes</summary>

Implement `insertIndirectBranch` so that branch relaxation pass can insert unconditional long-range branching.
Follow an approach similar to the one used in AVR and use the CALL instruction to get a reach of 32-bit signed offset instead of emitting actual indirect branches.

---
Full diff: https://github.com/llvm/llvm-project/pull/226678.diff


3 Files Affected:

- (modified) llvm/lib/Target/Sparc/SparcInstrInfo.cpp (+70) 
- (modified) llvm/lib/Target/Sparc/SparcInstrInfo.h (+5) 
- (modified) llvm/test/CodeGen/SPARC/branches-relax.ll (+39) 


``````````diff
diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.cpp b/llvm/lib/Target/Sparc/SparcInstrInfo.cpp
index 3f6023b8c0706..021d91d959343 100644
--- a/llvm/lib/Target/Sparc/SparcInstrInfo.cpp
+++ b/llvm/lib/Target/Sparc/SparcInstrInfo.cpp
@@ -19,6 +19,7 @@
 #include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/MachineMemOperand.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/RegisterScavenging.h"
 #include "llvm/Support/ErrorHandling.h"
 
 using namespace llvm;
@@ -399,6 +400,75 @@ unsigned SparcInstrInfo::insertBranch(MachineBasicBlock &MBB,
   return 2;
 }
 
+void SparcInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB,
+                                          MachineBasicBlock &NewDestBB,
+                                          MachineBasicBlock &RestoreBB,
+                                          const DebugLoc &DL, int64_t BrOffset,
+                                          RegScavenger *RS) const {
+  assert(RS && "RegScavenger required for long branching");
+  assert(MBB.empty() &&
+         "new block should be inserted for expanding unconditional branch");
+  assert(MBB.pred_size() == 1);
+  assert(RestoreBB.empty() &&
+         "restore block should be inserted for restoring clobbered registers");
+
+  MachineFunction *MF = MBB.getParent();
+  MachineFrameInfo &MFI = MF->getFrameInfo();
+
+  if (!isInt<32>(BrOffset))
+    report_fatal_error(
+        "Branch offsets outside of the signed 32-bit range not supported");
+  RS->enterBasicBlockEnd(MBB);
+
+  // A SPARC CALL instruction already has signed 32-bit range, so we'll use it
+  // instead of actually emitting an indirect branch.
+  //
+  // Note that using CALLs to do unconditional long-range branch in this manner
+  // should only be done if the target is out of range of a regular BA
+  // instruction, given that CALLS will always clobber %o7 and interfere with
+  // the processor's predictor machinery.
+  bool IsO7Used = RS->isRegUsed(SP::O7);
+  Register ScratchReg = RS->FindUnusedReg(&SP::IntRegsRegClass);
+  int FI = 0;
+  if (IsO7Used) {
+    if (ScratchReg.isValid()) {
+      BuildMI(&MBB, DL, get(SP::ORrr), ScratchReg)
+          .addReg(SP::G0)
+          .addReg(SP::O7, RegState::Kill);
+      RS->setRegUsed(ScratchReg);
+    } else {
+      // In case we run out of usable registers we'll spill it into the stack.
+      const MCRegisterClass &RC =
+          Subtarget.is64Bit() ? SP::I64RegsRegClass : SP::IntRegsRegClass;
+      unsigned SpillSize = TRI.getSpillSize(RC);
+      Align SpillAlign = TRI.getSpillAlign(RC);
+
+      FI = MFI.CreateStackObject(SpillSize, SpillAlign, true);
+
+      MachineBasicBlock::iterator I = MBB.end();
+      storeRegToStackSlot(MBB, I, SP::O7, true, FI, &RC, Register());
+      TRI.eliminateFrameIndex(std::prev(I), 0, 0, RS);
+    }
+  }
+
+  BuildMI(&MBB, DL, get(SP::CALL)).addMBB(IsO7Used ? &RestoreBB : &NewDestBB);
+
+  if (IsO7Used) {
+    if (ScratchReg.isValid()) {
+      BuildMI(&RestoreBB, DL, get(SP::ORrr), SP::O7)
+          .addReg(SP::G0)
+          .addReg(ScratchReg, RegState::Kill);
+    } else {
+      const MCRegisterClass &RC =
+          Subtarget.is64Bit() ? SP::I64RegsRegClass : SP::IntRegsRegClass;
+
+      MachineBasicBlock::iterator I = RestoreBB.begin();
+      loadRegFromStackSlot(RestoreBB, I, SP::O7, FI, &RC, Register());
+      TRI.eliminateFrameIndex(std::prev(I), 0, 1, RS);
+    }
+  }
+}
+
 unsigned SparcInstrInfo::removeBranch(MachineBasicBlock &MBB,
                                       int *BytesRemoved) const {
   MachineBasicBlock::iterator I = MBB.end();
diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.h b/llvm/lib/Target/Sparc/SparcInstrInfo.h
index a719391559eba..a6b32df23062f 100644
--- a/llvm/lib/Target/Sparc/SparcInstrInfo.h
+++ b/llvm/lib/Target/Sparc/SparcInstrInfo.h
@@ -82,6 +82,11 @@ class SparcInstrInfo : public SparcGenInstrInfo {
                         const DebugLoc &DL,
                         int *BytesAdded = nullptr) const override;
 
+  void insertIndirectBranch(MachineBasicBlock &MBB,
+                            MachineBasicBlock &NewDestBB,
+                            MachineBasicBlock &RestoreBB, const DebugLoc &DL,
+                            int64_t BrOffset, RegScavenger *RS) const override;
+
   bool
   reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
 
diff --git a/llvm/test/CodeGen/SPARC/branches-relax.ll b/llvm/test/CodeGen/SPARC/branches-relax.ll
index 334a7ebfb6739..8d8d30da952bd 100644
--- a/llvm/test/CodeGen/SPARC/branches-relax.ll
+++ b/llvm/test/CodeGen/SPARC/branches-relax.ll
@@ -162,3 +162,42 @@ false:
   call void asm sideeffect "nop\0A\09nop\0A\09nop\0A\09nop\0A\09nop\0A\09nop\0A\09nop\0A\09nop", ""()
   ret float 0.0
 }
+
+define i32 @branch_relax_large(i32 %in) {
+; SPARC64-LABEL: branch_relax_large:
+; SPARC64:         .cfi_startproc
+; SPARC64-NEXT:  ! %bb.0:
+; SPARC64-NEXT:    save %sp, -128, %sp
+; SPARC64-NEXT:    .cfi_def_cfa_register %fp
+; SPARC64-NEXT:    .cfi_window_save
+; SPARC64-NEXT:    .cfi_register %o7, %i7
+; SPARC64-NEXT:    cmp %i0, 0
+; SPARC64-NEXT:    bne %icc, .LBB3_1
+; SPARC64-NEXT:    nop
+; SPARC64-NEXT:  ! %bb.3:
+; SPARC64-NEXT:    call .LBB3_2
+; SPARC64-NEXT:    nop
+; SPARC64-NEXT:  .LBB3_1: ! %false
+; SPARC64-NEXT:    !APP
+; SPARC64-NEXT:    .skip 268435456
+; SPARC64-NEXT:    !NO_APP
+; SPARC64-NEXT:    ret
+; SPARC64-NEXT:    restore %g0, %g0, %o0
+; SPARC64-NEXT:  .LBB3_2: ! %true
+; SPARC64-NEXT:    mov 4, %i0
+; SPARC64-NEXT:    !APP
+; SPARC64-NEXT:    .skip 268435456
+; SPARC64-NEXT:    !NO_APP
+; SPARC64-NEXT:    ret
+; SPARC64-NEXT:    restore
+  %tst = icmp eq i32 %in, 0
+  br i1 %tst, label %true, label %false
+
+true:
+  call void asm sideeffect ".space 268435456", ""()
+  ret i32 4
+
+false:
+  call void asm sideeffect ".space 268435456", ""()
+  ret i32 0
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/226678


More information about the llvm-commits mailing list