[llvm] Reland "[LoongArch] Add `isSafeToMove` hook to prevent unsafe instruction motion" (PR #167465)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 11 05:12:07 PST 2025
https://github.com/heiher updated https://github.com/llvm/llvm-project/pull/167465
>From 4d88d37c285c96d562b7e3ce83685801a220684e Mon Sep 17 00:00:00 2001
From: hev <wangrui at loongson.cn>
Date: Fri, 7 Nov 2025 21:01:53 +0800
Subject: [PATCH 1/2] Reland "[LoongArch] Add `isSafeToMove` hook to prevent
unsafe instruction motion"
This patch introduces a new virtual method
`TargetInstrInfo::isSafeToMove()` to allow backends to control whether a
machine instruction can be safely moved by optimization passes.
The `BranchFolder` pass now respects this hook when hoisting common
code. By default, all instructions are considered safe to to move.
For LoongArch, `isSafeToMove()` is overridden to prevent
relocation-related instruction sequences (e.g. PC-relative addressing
and calls) from being broken by instruction motion. Correspondingly,
`isSchedulingBoundary()` is updated to reuse this logic for consistency.
---
llvm/include/llvm/CodeGen/TargetInstrInfo.h | 11 +++++
llvm/lib/CodeGen/BranchFolding.cpp | 5 +++
.../Target/LoongArch/LoongArchInstrInfo.cpp | 45 +++++++++++--------
.../lib/Target/LoongArch/LoongArchInstrInfo.h | 3 ++
4 files changed, 46 insertions(+), 18 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/TargetInstrInfo.h b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
index 43f28ed79f9dd..18142c2c0adf3 100644
--- a/llvm/include/llvm/CodeGen/TargetInstrInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
@@ -1765,6 +1765,17 @@ class LLVM_ABI TargetInstrInfo : public MCInstrInfo {
return true;
}
+ /// Return true if it's safe to move a machine instruction.
+ /// This allows the backend to prevent certain special instruction
+ /// sequences from being broken by instruction motion in optimization
+ /// passes.
+ /// By default, this returns true for every instruction.
+ virtual bool isSafeToMove(const MachineInstr &MI,
+ const MachineBasicBlock *MBB,
+ const MachineFunction &MF) const {
+ return true;
+ }
+
/// Test if the given instruction should be considered a scheduling boundary.
/// This primarily includes labels and terminators.
virtual bool isSchedulingBoundary(const MachineInstr &MI,
diff --git a/llvm/lib/CodeGen/BranchFolding.cpp b/llvm/lib/CodeGen/BranchFolding.cpp
index 7292bc2be0df2..0b212fb0beb20 100644
--- a/llvm/lib/CodeGen/BranchFolding.cpp
+++ b/llvm/lib/CodeGen/BranchFolding.cpp
@@ -1979,6 +1979,7 @@ bool BranchFolder::HoistCommonCodeInSuccs(MachineBasicBlock *MBB) {
MachineBasicBlock::iterator FIB = FBB->begin();
MachineBasicBlock::iterator TIE = TBB->end();
MachineBasicBlock::iterator FIE = FBB->end();
+ MachineFunction &MF = *TBB->getParent();
while (TIB != TIE && FIB != FIE) {
// Skip dbg_value instructions. These do not count.
TIB = skipDebugInstructionsForward(TIB, TIE, false);
@@ -1993,6 +1994,10 @@ bool BranchFolder::HoistCommonCodeInSuccs(MachineBasicBlock *MBB) {
// Hard to reason about register liveness with predicated instruction.
break;
+ if (!TII->isSafeToMove(*TIB, TBB, MF))
+ // Don't hoist the instruction if it isn't safe to move.
+ break;
+
bool IsSafe = true;
for (MachineOperand &MO : TIB->operands()) {
// Don't attempt to hoist instructions with register masks.
diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
index 9a33dccd002c7..9fc862af7ea24 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
@@ -378,12 +378,9 @@ bool LoongArchInstrInfo::isBranchOffsetInRange(unsigned BranchOp,
}
}
-bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
- const MachineBasicBlock *MBB,
- const MachineFunction &MF) const {
- if (TargetInstrInfo::isSchedulingBoundary(MI, MBB, MF))
- return true;
-
+bool LoongArchInstrInfo::isSafeToMove(const MachineInstr &MI,
+ const MachineBasicBlock *MBB,
+ const MachineFunction &MF) const {
auto MII = MI.getIterator();
auto MIE = MBB->end();
@@ -429,25 +426,25 @@ bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
auto MO2 = Lu32I->getOperand(2).getTargetFlags();
if (MO0 == LoongArchII::MO_PCREL_HI && MO1 == LoongArchII::MO_PCREL_LO &&
MO2 == LoongArchII::MO_PCREL64_LO)
- return true;
+ return false;
if ((MO0 == LoongArchII::MO_GOT_PC_HI || MO0 == LoongArchII::MO_LD_PC_HI ||
MO0 == LoongArchII::MO_GD_PC_HI) &&
MO1 == LoongArchII::MO_GOT_PC_LO && MO2 == LoongArchII::MO_GOT_PC64_LO)
- return true;
+ return false;
if (MO0 == LoongArchII::MO_IE_PC_HI && MO1 == LoongArchII::MO_IE_PC_LO &&
MO2 == LoongArchII::MO_IE_PC64_LO)
- return true;
+ return false;
if (MO0 == LoongArchII::MO_DESC_PC_HI &&
MO1 == LoongArchII::MO_DESC_PC_LO &&
MO2 == LoongArchII::MO_DESC64_PC_LO)
- return true;
+ return false;
break;
}
case LoongArch::LU52I_D: {
auto MO = MI.getOperand(2).getTargetFlags();
if (MO == LoongArchII::MO_PCREL64_HI || MO == LoongArchII::MO_GOT_PC64_HI ||
MO == LoongArchII::MO_IE_PC64_HI || MO == LoongArchII::MO_DESC64_PC_HI)
- return true;
+ return false;
break;
}
default:
@@ -487,7 +484,7 @@ bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
auto MO1 = LoongArchII::getDirectFlags(SecondOp->getOperand(2));
auto MO2 = LoongArchII::getDirectFlags(Ld->getOperand(2));
if (MO1 == LoongArchII::MO_DESC_PC_LO && MO2 == LoongArchII::MO_DESC_LD)
- return true;
+ return false;
break;
}
if (SecondOp == MIE ||
@@ -496,34 +493,34 @@ bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
auto MO1 = LoongArchII::getDirectFlags(SecondOp->getOperand(2));
if (MO0 == LoongArchII::MO_PCREL_HI && SecondOp->getOpcode() == AddiOp &&
MO1 == LoongArchII::MO_PCREL_LO)
- return true;
+ return false;
if (MO0 == LoongArchII::MO_GOT_PC_HI && SecondOp->getOpcode() == LdOp &&
MO1 == LoongArchII::MO_GOT_PC_LO)
- return true;
+ return false;
if ((MO0 == LoongArchII::MO_LD_PC_HI ||
MO0 == LoongArchII::MO_GD_PC_HI) &&
SecondOp->getOpcode() == AddiOp && MO1 == LoongArchII::MO_GOT_PC_LO)
- return true;
+ return false;
break;
}
case LoongArch::ADDI_W:
case LoongArch::ADDI_D: {
auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));
if (MO == LoongArchII::MO_PCREL_LO || MO == LoongArchII::MO_GOT_PC_LO)
- return true;
+ return false;
break;
}
case LoongArch::LD_W:
case LoongArch::LD_D: {
auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));
if (MO == LoongArchII::MO_GOT_PC_LO)
- return true;
+ return false;
break;
}
case LoongArch::PseudoDESC_CALL: {
auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));
if (MO == LoongArchII::MO_DESC_CALL)
- return true;
+ return false;
break;
}
default:
@@ -531,6 +528,18 @@ bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
}
}
+ return true;
+}
+
+bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
+ const MachineBasicBlock *MBB,
+ const MachineFunction &MF) const {
+ if (TargetInstrInfo::isSchedulingBoundary(MI, MBB, MF))
+ return true;
+
+ if (!isSafeToMove(MI, MBB, MF))
+ return true;
+
return false;
}
diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.h b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.h
index 796ef9f3a5715..9f7a0a2239a87 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.h
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.h
@@ -66,6 +66,9 @@ class LoongArchInstrInfo : public LoongArchGenInstrInfo {
bool isBranchOffsetInRange(unsigned BranchOpc,
int64_t BrOffset) const override;
+ bool isSafeToMove(const MachineInstr &MI, const MachineBasicBlock *MBB,
+ const MachineFunction &MF) const override;
+
bool isSchedulingBoundary(const MachineInstr &MI,
const MachineBasicBlock *MBB,
const MachineFunction &MF) const override;
>From 439fbe7131319880c96623ebaa27c038d875d287 Mon Sep 17 00:00:00 2001
From: WANG Rui <wangrui at loongson.cn>
Date: Tue, 11 Nov 2025 21:13:42 +0800
Subject: [PATCH 2/2] Address Weining's comment
---
llvm/test/CodeGen/LoongArch/issue163681.ll | 56 ++++++++++++++++++++++
1 file changed, 56 insertions(+)
create mode 100644 llvm/test/CodeGen/LoongArch/issue163681.ll
diff --git a/llvm/test/CodeGen/LoongArch/issue163681.ll b/llvm/test/CodeGen/LoongArch/issue163681.ll
new file mode 100644
index 0000000000000..f6df349253045
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/issue163681.ll
@@ -0,0 +1,56 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc --mtriple=loongarch64 -code-model=large --verify-machineinstrs < %s \
+; RUN: | FileCheck %s
+
+ at .str = external constant [1 x i8]
+
+define void @caller(ptr %0) {
+; CHECK-LABEL: caller:
+; CHECK: # %bb.0:
+; CHECK-NEXT: addi.d $sp, $sp, -16
+; CHECK-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
+; CHECK-NEXT: .cfi_offset 1, -8
+; CHECK-NEXT: ld.w $a2, $zero, 0
+; CHECK-NEXT: ld.d $a1, $a0, 0
+; CHECK-NEXT: beqz $a2, .LBB0_2
+; CHECK-NEXT: # %bb.1:
+; CHECK-NEXT: pcalau12i $a0, %got_pc_hi20(.str)
+; CHECK-NEXT: addi.d $a2, $zero, %got_pc_lo12(.str)
+; CHECK-NEXT: lu32i.d $a2, %got64_pc_lo20(.str)
+; CHECK-NEXT: lu52i.d $a2, $a2, %got64_pc_hi12(.str)
+; CHECK-NEXT: ldx.d $a2, $a2, $a0
+; CHECK-NEXT: move $a0, $zero
+; CHECK-NEXT: jirl $ra, $zero, 0
+; CHECK-NEXT: b .LBB0_3
+; CHECK-NEXT: .LBB0_2:
+; CHECK-NEXT: pcalau12i $a0, %got_pc_hi20(.str)
+; CHECK-NEXT: addi.d $a2, $zero, %got_pc_lo12(.str)
+; CHECK-NEXT: lu32i.d $a2, %got64_pc_lo20(.str)
+; CHECK-NEXT: lu52i.d $a2, $a2, %got64_pc_hi12(.str)
+; CHECK-NEXT: ldx.d $a2, $a2, $a0
+; CHECK-NEXT: move $a0, $zero
+; CHECK-NEXT: move $a3, $zero
+; CHECK-NEXT: jirl $ra, $zero, 0
+; CHECK-NEXT: .LBB0_3:
+; CHECK-NEXT: st.d $zero, $zero, 0
+; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
+; CHECK-NEXT: addi.d $sp, $sp, 16
+; CHECK-NEXT: ret
+ %2 = load i32, ptr null, align 4
+ %3 = icmp eq i32 %2, 0
+ %4 = load i64, ptr %0, align 8
+ br i1 %3, label %6, label %5
+
+5: ; preds = %1
+ call void null(ptr null, i64 %4, ptr @.str)
+ br label %7
+
+6: ; preds = %1
+ tail call void null(ptr null, i64 %4, ptr @.str, i32 0)
+ br label %7
+
+7: ; preds = %6, %5
+ store ptr null, ptr null, align 8
+ ret void
+}
More information about the llvm-commits
mailing list