Skip to content

Commit a832a52

Browse files
heiherdyung
authored andcommitted
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 (cherry picked from commit ea10026)
1 parent 2d631cc commit a832a52

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
@@ -1730,6 +1730,17 @@ class LLVM_ABI TargetInstrInfo : public MCInstrInfo {
17301730
return true;
17311731
}
17321732

1733+
/// Return true if it's safe to move a machine instruction.
1734+
/// This allows the backend to prevent certain special instruction
1735+
/// sequences from being broken by instruction motion in optimization
1736+
/// passes.
1737+
/// By default, this returns true for every instruction.
1738+
virtual bool isSafeToMove(const MachineInstr &MI,
1739+
const MachineBasicBlock *MBB,
1740+
const MachineFunction &MF) const {
1741+
return true;
1742+
}
1743+
17331744
/// Test if the given instruction should be considered a scheduling boundary.
17341745
/// This primarily includes labels and terminators.
17351746
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
@@ -1971,6 +1971,7 @@ bool BranchFolder::HoistCommonCodeInSuccs(MachineBasicBlock *MBB) {
19711971
MachineBasicBlock::iterator FIB = FBB->begin();
19721972
MachineBasicBlock::iterator TIE = TBB->end();
19731973
MachineBasicBlock::iterator FIE = FBB->end();
1974+
MachineFunction &MF = *TBB->getParent();
19741975
while (TIB != TIE && FIB != FIE) {
19751976
// Skip dbg_value instructions. These do not count.
19761977
TIB = skipDebugInstructionsForward(TIB, TIE, false);
@@ -1985,6 +1986,10 @@ bool BranchFolder::HoistCommonCodeInSuccs(MachineBasicBlock *MBB) {
19851986
// Hard to reason about register liveness with predicated instruction.
19861987
break;
19871988

1989+
if (!TII->isSafeToMove(*TIB, TBB, MF))
1990+
// Don't hoist the instruction if it isn't safe to move.
1991+
break;
1992+
19881993
bool IsSafe = true;
19891994
for (MachineOperand &MO : TIB->operands()) {
19901995
// 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
@@ -64,6 +64,9 @@ class LoongArchInstrInfo : public LoongArchGenInstrInfo {
6464
bool isBranchOffsetInRange(unsigned BranchOpc,
6565
int64_t BrOffset) const override;
6666

67+
bool isSafeToMove(const MachineInstr &MI, const MachineBasicBlock *MBB,
68+
const MachineFunction &MF) const override;
69+
6770
bool isSchedulingBoundary(const MachineInstr &MI,
6871
const MachineBasicBlock *MBB,
6972
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)