Skip to content

Commit ea10026

Browse files
authored
Reland "[LoongArch] Add isSafeToMove hook to prevent unsafe instruction motion" (#167465)
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. Relands #163725
1 parent 79d9ae7 commit ea10026

File tree

5 files changed

+102
-18
lines changed

5 files changed

+102
-18
lines changed

llvm/include/llvm/CodeGen/TargetInstrInfo.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1765,6 +1765,17 @@ class LLVM_ABI TargetInstrInfo : public MCInstrInfo {
17651765
return true;
17661766
}
17671767

1768+
/// Return true if it's safe to move a machine instruction.
1769+
/// This allows the backend to prevent certain special instruction
1770+
/// sequences from being broken by instruction motion in optimization
1771+
/// passes.
1772+
/// By default, this returns true for every instruction.
1773+
virtual bool isSafeToMove(const MachineInstr &MI,
1774+
const MachineBasicBlock *MBB,
1775+
const MachineFunction &MF) const {
1776+
return true;
1777+
}
1778+
17681779
/// Test if the given instruction should be considered a scheduling boundary.
17691780
/// This primarily includes labels and terminators.
17701781
virtual bool isSchedulingBoundary(const MachineInstr &MI,

llvm/lib/CodeGen/BranchFolding.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1979,6 +1979,7 @@ bool BranchFolder::HoistCommonCodeInSuccs(MachineBasicBlock *MBB) {
19791979
MachineBasicBlock::iterator FIB = FBB->begin();
19801980
MachineBasicBlock::iterator TIE = TBB->end();
19811981
MachineBasicBlock::iterator FIE = FBB->end();
1982+
MachineFunction &MF = *TBB->getParent();
19821983
while (TIB != TIE && FIB != FIE) {
19831984
// Skip dbg_value instructions. These do not count.
19841985
TIB = skipDebugInstructionsForward(TIB, TIE, false);
@@ -1993,6 +1994,10 @@ bool BranchFolder::HoistCommonCodeInSuccs(MachineBasicBlock *MBB) {
19931994
// Hard to reason about register liveness with predicated instruction.
19941995
break;
19951996

1997+
if (!TII->isSafeToMove(*TIB, TBB, MF))
1998+
// Don't hoist the instruction if it isn't safe to move.
1999+
break;
2000+
19962001
bool IsSafe = true;
19972002
for (MachineOperand &MO : TIB->operands()) {
19982003
// Don't attempt to hoist instructions with register masks.

llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -378,12 +378,9 @@ bool LoongArchInstrInfo::isBranchOffsetInRange(unsigned BranchOp,
378378
}
379379
}
380380

381-
bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
382-
const MachineBasicBlock *MBB,
383-
const MachineFunction &MF) const {
384-
if (TargetInstrInfo::isSchedulingBoundary(MI, MBB, MF))
385-
return true;
386-
381+
bool LoongArchInstrInfo::isSafeToMove(const MachineInstr &MI,
382+
const MachineBasicBlock *MBB,
383+
const MachineFunction &MF) const {
387384
auto MII = MI.getIterator();
388385
auto MIE = MBB->end();
389386

@@ -429,25 +426,25 @@ bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
429426
auto MO2 = Lu32I->getOperand(2).getTargetFlags();
430427
if (MO0 == LoongArchII::MO_PCREL_HI && MO1 == LoongArchII::MO_PCREL_LO &&
431428
MO2 == LoongArchII::MO_PCREL64_LO)
432-
return true;
429+
return false;
433430
if ((MO0 == LoongArchII::MO_GOT_PC_HI || MO0 == LoongArchII::MO_LD_PC_HI ||
434431
MO0 == LoongArchII::MO_GD_PC_HI) &&
435432
MO1 == LoongArchII::MO_GOT_PC_LO && MO2 == LoongArchII::MO_GOT_PC64_LO)
436-
return true;
433+
return false;
437434
if (MO0 == LoongArchII::MO_IE_PC_HI && MO1 == LoongArchII::MO_IE_PC_LO &&
438435
MO2 == LoongArchII::MO_IE_PC64_LO)
439-
return true;
436+
return false;
440437
if (MO0 == LoongArchII::MO_DESC_PC_HI &&
441438
MO1 == LoongArchII::MO_DESC_PC_LO &&
442439
MO2 == LoongArchII::MO_DESC64_PC_LO)
443-
return true;
440+
return false;
444441
break;
445442
}
446443
case LoongArch::LU52I_D: {
447444
auto MO = MI.getOperand(2).getTargetFlags();
448445
if (MO == LoongArchII::MO_PCREL64_HI || MO == LoongArchII::MO_GOT_PC64_HI ||
449446
MO == LoongArchII::MO_IE_PC64_HI || MO == LoongArchII::MO_DESC64_PC_HI)
450-
return true;
447+
return false;
451448
break;
452449
}
453450
default:
@@ -487,7 +484,7 @@ bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
487484
auto MO1 = LoongArchII::getDirectFlags(SecondOp->getOperand(2));
488485
auto MO2 = LoongArchII::getDirectFlags(Ld->getOperand(2));
489486
if (MO1 == LoongArchII::MO_DESC_PC_LO && MO2 == LoongArchII::MO_DESC_LD)
490-
return true;
487+
return false;
491488
break;
492489
}
493490
if (SecondOp == MIE ||
@@ -496,41 +493,53 @@ bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
496493
auto MO1 = LoongArchII::getDirectFlags(SecondOp->getOperand(2));
497494
if (MO0 == LoongArchII::MO_PCREL_HI && SecondOp->getOpcode() == AddiOp &&
498495
MO1 == LoongArchII::MO_PCREL_LO)
499-
return true;
496+
return false;
500497
if (MO0 == LoongArchII::MO_GOT_PC_HI && SecondOp->getOpcode() == LdOp &&
501498
MO1 == LoongArchII::MO_GOT_PC_LO)
502-
return true;
499+
return false;
503500
if ((MO0 == LoongArchII::MO_LD_PC_HI ||
504501
MO0 == LoongArchII::MO_GD_PC_HI) &&
505502
SecondOp->getOpcode() == AddiOp && MO1 == LoongArchII::MO_GOT_PC_LO)
506-
return true;
503+
return false;
507504
break;
508505
}
509506
case LoongArch::ADDI_W:
510507
case LoongArch::ADDI_D: {
511508
auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));
512509
if (MO == LoongArchII::MO_PCREL_LO || MO == LoongArchII::MO_GOT_PC_LO)
513-
return true;
510+
return false;
514511
break;
515512
}
516513
case LoongArch::LD_W:
517514
case LoongArch::LD_D: {
518515
auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));
519516
if (MO == LoongArchII::MO_GOT_PC_LO)
520-
return true;
517+
return false;
521518
break;
522519
}
523520
case LoongArch::PseudoDESC_CALL: {
524521
auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));
525522
if (MO == LoongArchII::MO_DESC_CALL)
526-
return true;
523+
return false;
527524
break;
528525
}
529526
default:
530527
break;
531528
}
532529
}
533530

531+
return true;
532+
}
533+
534+
bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
535+
const MachineBasicBlock *MBB,
536+
const MachineFunction &MF) const {
537+
if (TargetInstrInfo::isSchedulingBoundary(MI, MBB, MF))
538+
return true;
539+
540+
if (!isSafeToMove(MI, MBB, MF))
541+
return true;
542+
534543
return false;
535544
}
536545

llvm/lib/Target/LoongArch/LoongArchInstrInfo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ class LoongArchInstrInfo : public LoongArchGenInstrInfo {
6666
bool isBranchOffsetInRange(unsigned BranchOpc,
6767
int64_t BrOffset) const override;
6868

69+
bool isSafeToMove(const MachineInstr &MI, const MachineBasicBlock *MBB,
70+
const MachineFunction &MF) const override;
71+
6972
bool isSchedulingBoundary(const MachineInstr &MI,
7073
const MachineBasicBlock *MBB,
7174
const MachineFunction &MF) const override;
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
2+
; RUN: llc --mtriple=loongarch64 -code-model=large --verify-machineinstrs < %s \
3+
; RUN: | FileCheck %s
4+
5+
@.str = external constant [1 x i8]
6+
7+
define void @caller(ptr %0) {
8+
; CHECK-LABEL: caller:
9+
; CHECK: # %bb.0:
10+
; CHECK-NEXT: addi.d $sp, $sp, -16
11+
; CHECK-NEXT: .cfi_def_cfa_offset 16
12+
; CHECK-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
13+
; CHECK-NEXT: .cfi_offset 1, -8
14+
; CHECK-NEXT: ld.w $a2, $zero, 0
15+
; CHECK-NEXT: ld.d $a1, $a0, 0
16+
; CHECK-NEXT: beqz $a2, .LBB0_2
17+
; CHECK-NEXT: # %bb.1:
18+
; CHECK-NEXT: pcalau12i $a0, %got_pc_hi20(.str)
19+
; CHECK-NEXT: addi.d $a2, $zero, %got_pc_lo12(.str)
20+
; CHECK-NEXT: lu32i.d $a2, %got64_pc_lo20(.str)
21+
; CHECK-NEXT: lu52i.d $a2, $a2, %got64_pc_hi12(.str)
22+
; CHECK-NEXT: ldx.d $a2, $a2, $a0
23+
; CHECK-NEXT: move $a0, $zero
24+
; CHECK-NEXT: jirl $ra, $zero, 0
25+
; CHECK-NEXT: b .LBB0_3
26+
; CHECK-NEXT: .LBB0_2:
27+
; CHECK-NEXT: pcalau12i $a0, %got_pc_hi20(.str)
28+
; CHECK-NEXT: addi.d $a2, $zero, %got_pc_lo12(.str)
29+
; CHECK-NEXT: lu32i.d $a2, %got64_pc_lo20(.str)
30+
; CHECK-NEXT: lu52i.d $a2, $a2, %got64_pc_hi12(.str)
31+
; CHECK-NEXT: ldx.d $a2, $a2, $a0
32+
; CHECK-NEXT: move $a0, $zero
33+
; CHECK-NEXT: move $a3, $zero
34+
; CHECK-NEXT: jirl $ra, $zero, 0
35+
; CHECK-NEXT: .LBB0_3:
36+
; CHECK-NEXT: st.d $zero, $zero, 0
37+
; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
38+
; CHECK-NEXT: addi.d $sp, $sp, 16
39+
; CHECK-NEXT: ret
40+
%2 = load i32, ptr null, align 4
41+
%3 = icmp eq i32 %2, 0
42+
%4 = load i64, ptr %0, align 8
43+
br i1 %3, label %6, label %5
44+
45+
5: ; preds = %1
46+
call void null(ptr null, i64 %4, ptr @.str)
47+
br label %7
48+
49+
6: ; preds = %1
50+
tail call void null(ptr null, i64 %4, ptr @.str, i32 0)
51+
br label %7
52+
53+
7: ; preds = %6, %5
54+
store ptr null, ptr null, align 8
55+
ret void
56+
}

0 commit comments

Comments
 (0)