Skip to content

Commit 4e7d114

Browse files
committed
[Mips] Fix mfhi/mflo hazard miscompilation about div and mult
Fix issue1: In mips1-4, require a minimum of 2 instructions between a mflo/mfhi and the next mul/dmult/div/ddiv/divu/ddivu instruction. Fix issue2: In mips1-4, should not put mflo into the delay slot for the return. Fix #81291
1 parent ef0291e commit 4e7d114

File tree

10 files changed

+531
-12
lines changed

10 files changed

+531
-12
lines changed

llvm/lib/Target/Mips/Mips.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@
1717
#include "MCTargetDesc/MipsMCTargetDesc.h"
1818
#include "llvm/Target/TargetMachine.h"
1919

20+
#define IsMFLOMFHI(instr) \
21+
(instr == Mips::MFLO || instr == Mips::MFLO64 || instr == Mips::MFHI || \
22+
instr == Mips::MFHI64)
23+
#define IsDIVMULT(instr) \
24+
(instr == Mips::SDIV || instr == Mips::PseudoSDIV || instr == Mips::DSDIV || \
25+
instr == Mips::PseudoDSDIV || instr == Mips::UDIV || \
26+
instr == Mips::PseudoUDIV || instr == Mips::DUDIV || \
27+
instr == Mips::PseudoDUDIV || instr == Mips::MULT || \
28+
instr == Mips::PseudoMULT || instr == Mips::DMULT || \
29+
instr == Mips::PseudoDMULT)
30+
2031
namespace llvm {
2132
class FunctionPass;
2233
class InstructionSelector;

llvm/lib/Target/Mips/MipsBranchExpansion.cpp

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ class MipsBranchExpansion : public MachineFunctionPass {
167167
bool handleFPUDelaySlot();
168168
bool handleLoadDelaySlot();
169169
bool handlePossibleLongBranch();
170+
bool handleMFLO();
170171

171172
const MipsSubtarget *STI;
172173
const MipsInstrInfo *TII;
@@ -744,13 +745,15 @@ static void emitGPDisp(MachineFunction &F, const MipsInstrInfo *TII) {
744745
template <typename Pred, typename Safe>
745746
bool MipsBranchExpansion::handleSlot(Pred Predicate, Safe SafeInSlot) {
746747
bool Changed = false;
748+
bool hasPendingMFLO = false;
747749

748750
for (MachineFunction::iterator FI = MFp->begin(); FI != MFp->end(); ++FI) {
749751
for (Iter I = FI->begin(); I != FI->end(); ++I) {
750752

751753
// Delay slot hazard handling. Use lookahead over state.
752-
if (!Predicate(*I))
754+
if (!Predicate(*I) && !hasPendingMFLO) {
753755
continue;
756+
}
754757

755758
Iter IInSlot;
756759
bool LastInstInFunction =
@@ -766,17 +769,40 @@ bool MipsBranchExpansion::handleSlot(Pred Predicate, Safe SafeInSlot) {
766769
if (std::next(Iit) == FI->end() ||
767770
std::next(Iit)->getOpcode() != Mips::NOP) {
768771
Changed = true;
769-
TII->insertNop(*(I->getParent()), std::next(I), I->getDebugLoc())
770-
->bundleWithPred();
771-
NumInsertedNops++;
772+
if (Predicate(*I) ||
773+
(!LastInstInFunction && !SafeInSlot(*IInSlot, *I))) {
774+
TII->insertNop(*(I->getParent()), std::next(I), I->getDebugLoc())
775+
->bundleWithPred();
776+
NumInsertedNops++;
777+
}
778+
if (IsMFLOMFHI(I->getOpcode()) && !LastInstInFunction &&
779+
IsDIVMULT(IInSlot->getOpcode())) {
780+
TII->insertNop(*(I->getParent()), std::next(I), I->getDebugLoc())
781+
->bundleWithPred();
782+
NumInsertedNops++;
783+
}
772784
}
785+
} else if (IsMFLOMFHI(I->getOpcode())) {
786+
hasPendingMFLO = true;
773787
}
774788
}
775789
}
776790

777791
return Changed;
778792
}
779793

794+
bool MipsBranchExpansion::handleMFLO() {
795+
// mips1-4 require a minimum of 2 instructions between a mflo/mfhi
796+
// and the next mul/div instruction.
797+
if (STI->hasMips32() || STI->hasMips5())
798+
return false;
799+
800+
return handleSlot([this](auto &I) -> bool { return TII->IsMfloOrMfhi(I); },
801+
[this](auto &IInSlot, auto &I) -> bool {
802+
return TII->SafeAfterMflo(IInSlot);
803+
});
804+
}
805+
780806
bool MipsBranchExpansion::handleForbiddenSlot() {
781807
// Forbidden slot hazards are only defined for MIPSR6 but not microMIPSR6.
782808
if (!STI->hasMips32r6() || STI->inMicroMipsMode())
@@ -893,16 +919,19 @@ bool MipsBranchExpansion::runOnMachineFunction(MachineFunction &MF) {
893919
bool forbiddenSlotChanged = handleForbiddenSlot();
894920
bool fpuDelaySlotChanged = handleFPUDelaySlot();
895921
bool loadDelaySlotChanged = handleLoadDelaySlot();
922+
bool MfloChanged = handleMFLO();
896923

897924
bool Changed = longBranchChanged || forbiddenSlotChanged ||
898-
fpuDelaySlotChanged || loadDelaySlotChanged;
925+
fpuDelaySlotChanged || loadDelaySlotChanged || MfloChanged;
899926

900927
// Then run them alternatively while there are changes.
901928
while (forbiddenSlotChanged) {
902929
longBranchChanged = handlePossibleLongBranch();
903930
fpuDelaySlotChanged = handleFPUDelaySlot();
904931
loadDelaySlotChanged = handleLoadDelaySlot();
905-
if (!longBranchChanged && !fpuDelaySlotChanged && !loadDelaySlotChanged)
932+
MfloChanged = handleMFLO();
933+
if (!longBranchChanged && !fpuDelaySlotChanged && !loadDelaySlotChanged &&
934+
!MfloChanged)
906935
break;
907936
forbiddenSlotChanged = handleForbiddenSlot();
908937
}

llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,12 @@ bool MipsDelaySlotFiller::searchRange(MachineBasicBlock &MBB, IterTy Begin,
743743
bool InMicroMipsMode = STI.inMicroMipsMode();
744744
const MipsInstrInfo *TII = STI.getInstrInfo();
745745
unsigned Opcode = (*Slot).getOpcode();
746+
747+
if ((CurrI->getOpcode() == Mips::MFLO ||
748+
CurrI->getOpcode() == Mips::MFLO64) &&
749+
(!STI.hasMips32() && !STI.hasMips5()))
750+
continue;
751+
746752
// This is complicated by the tail call optimization. For non-PIC code
747753
// there is only a 32bit sized unconditional branch which can be assumed
748754
// to be able to reach the target. b16 only has a range of +/- 1 KB.

llvm/lib/Target/Mips/MipsInstrInfo.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "MipsInstrInfo.h"
1414
#include "MCTargetDesc/MipsBaseInfo.h"
1515
#include "MCTargetDesc/MipsMCTargetDesc.h"
16+
#include "Mips.h"
1617
#include "MipsSubtarget.h"
1718
#include "llvm/ADT/SmallVector.h"
1819
#include "llvm/CodeGen/MachineBasicBlock.h"
@@ -571,6 +572,13 @@ unsigned MipsInstrInfo::getEquivalentCompactForm(
571572
return 0;
572573
}
573574

575+
bool MipsInstrInfo::SafeAfterMflo(const MachineInstr &MI) const {
576+
if (IsDIVMULT(MI.getOpcode()))
577+
return false;
578+
579+
return true;
580+
}
581+
574582
/// Predicate for distingushing between control transfer instructions and all
575583
/// other instructions for handling forbidden slots. Consider inline assembly
576584
/// as unsafe as well.
@@ -623,6 +631,13 @@ bool MipsInstrInfo::SafeInLoadDelaySlot(const MachineInstr &MIInSlot,
623631
});
624632
}
625633

634+
bool MipsInstrInfo::IsMfloOrMfhi(const MachineInstr &MI) const {
635+
if (IsMFLOMFHI(MI.getOpcode()))
636+
return true;
637+
638+
return false;
639+
}
640+
626641
/// Predicate for distingushing instructions that have forbidden slots.
627642
bool MipsInstrInfo::HasForbiddenSlot(const MachineInstr &MI) const {
628643
return (MI.getDesc().TSFlags & MipsII::HasForbiddenSlot) != 0;

llvm/lib/Target/Mips/MipsInstrInfo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ class MipsInstrInfo : public MipsGenInstrInfo {
8989
bool isBranchOffsetInRange(unsigned BranchOpc,
9090
int64_t BrOffset) const override;
9191

92+
bool SafeAfterMflo(const MachineInstr &MI) const;
93+
9294
/// Predicate to determine if an instruction can go in a forbidden slot.
9395
bool SafeInForbiddenSlot(const MachineInstr &MI) const;
9496

@@ -100,6 +102,8 @@ class MipsInstrInfo : public MipsGenInstrInfo {
100102
bool SafeInLoadDelaySlot(const MachineInstr &MIInSlot,
101103
const MachineInstr &LoadMI) const;
102104

105+
bool IsMfloOrMfhi(const MachineInstr &MI) const;
106+
103107
/// Predicate to determine if an instruction has a forbidden slot.
104108
bool HasForbiddenSlot(const MachineInstr &MI) const;
105109

0 commit comments

Comments
 (0)