Skip to content

Commit cdc3cb2

Browse files
authored
[LoongArch] Add isSafeToMove hook to prevent unsafe instruction motion (#163725)
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. Fixes #163681
1 parent 3719c43 commit cdc3cb2

File tree

4 files changed

+46
-18
lines changed

4 files changed

+46
-18
lines changed

llvm/include/llvm/CodeGen/TargetInstrInfo.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1761,6 +1761,17 @@ class LLVM_ABI TargetInstrInfo : public MCInstrInfo {
17611761
return true;
17621762
}
17631763

1764+
/// Return true if it's safe to move a machine instruction.
1765+
/// This allows the backend to prevent certain special instruction
1766+
/// sequences from being broken by instruction motion in optimization
1767+
/// passes.
1768+
/// By default, this returns true for every instruction.
1769+
virtual bool isSafeToMove(const MachineInstr &MI,
1770+
const MachineBasicBlock *MBB,
1771+
const MachineFunction &MF) const {
1772+
return true;
1773+
}
1774+
17641775
/// Test if the given instruction should be considered a scheduling boundary.
17651776
/// This primarily includes labels and terminators.
17661777
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 = *MBB->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, MBB, 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
@@ -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;

0 commit comments

Comments
 (0)