Skip to content

Commit 677177b

Browse files
authored
[Mips] Fix mfhi/mflo hazard miscompilation about div and mult (#91449)
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 85220a0 commit 677177b

14 files changed

+1224
-14
lines changed

llvm/lib/Target/Mips/Mips.h

+11
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

+68-2
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,9 @@ class MipsBranchExpansion : public MachineFunctionPass {
167167
bool handleFPUDelaySlot();
168168
bool handleLoadDelaySlot();
169169
bool handlePossibleLongBranch();
170+
bool handleMFLO();
171+
template <typename Pred, typename Safe>
172+
bool handleMFLOSlot(Pred Predicate, Safe SafeInSlot);
170173

171174
const MipsSubtarget *STI;
172175
const MipsInstrInfo *TII;
@@ -741,6 +744,53 @@ static void emitGPDisp(MachineFunction &F, const MipsInstrInfo *TII) {
741744
MBB.removeLiveIn(Mips::V0);
742745
}
743746

747+
template <typename Pred, typename Safe>
748+
bool MipsBranchExpansion::handleMFLOSlot(Pred Predicate, Safe SafeInSlot) {
749+
bool Changed = false;
750+
bool hasPendingMFLO = false;
751+
752+
for (MachineFunction::iterator FI = MFp->begin(); FI != MFp->end(); ++FI) {
753+
for (Iter I = FI->begin(); I != FI->end(); ++I) {
754+
755+
if (!Predicate(*I) && !hasPendingMFLO) {
756+
continue;
757+
}
758+
759+
Iter IInSlot;
760+
bool LastInstInFunction =
761+
std::next(I) == FI->end() && std::next(FI) == MFp->end();
762+
// We need process several situations:
763+
// mflo is last instruction, do not process;
764+
// mflo + div, add two nop between them;
765+
// mflo + none-div + none-div, do not process;
766+
// mflo + none-div + div, add nop between none-div and div.
767+
if (!LastInstInFunction) {
768+
std::pair<Iter, bool> Res = getNextMachineInstr(std::next(I), &*FI);
769+
LastInstInFunction |= Res.second;
770+
IInSlot = Res.first;
771+
if (!SafeInSlot(*IInSlot, *I)) {
772+
Changed = true;
773+
TII->insertNop(*(I->getParent()), std::next(I), I->getDebugLoc())
774+
->bundleWithPred();
775+
NumInsertedNops++;
776+
if (IsMFLOMFHI(I->getOpcode())) {
777+
TII->insertNop(*(I->getParent()), std::next(I), I->getDebugLoc())
778+
->bundleWithPred();
779+
NumInsertedNops++;
780+
}
781+
if (hasPendingMFLO)
782+
hasPendingMFLO = false;
783+
} else if (hasPendingMFLO)
784+
hasPendingMFLO = false;
785+
else if (IsMFLOMFHI(I->getOpcode()))
786+
hasPendingMFLO = true;
787+
}
788+
}
789+
}
790+
791+
return Changed;
792+
}
793+
744794
template <typename Pred, typename Safe>
745795
bool MipsBranchExpansion::handleSlot(Pred Predicate, Safe SafeInSlot) {
746796
bool Changed = false;
@@ -777,6 +827,19 @@ bool MipsBranchExpansion::handleSlot(Pred Predicate, Safe SafeInSlot) {
777827
return Changed;
778828
}
779829

830+
bool MipsBranchExpansion::handleMFLO() {
831+
// mips1-4 require a minimum of 2 instructions between a mflo/mfhi
832+
// and the next mul/div instruction.
833+
if (STI->hasMips32() || STI->hasMips5())
834+
return false;
835+
836+
return handleMFLOSlot(
837+
[this](auto &I) -> bool { return TII->IsMfloOrMfhi(I); },
838+
[this](auto &IInSlot, auto &I) -> bool {
839+
return TII->SafeAfterMflo(IInSlot);
840+
});
841+
}
842+
780843
bool MipsBranchExpansion::handleForbiddenSlot() {
781844
// Forbidden slot hazards are only defined for MIPSR6 but not microMIPSR6.
782845
if (!STI->hasMips32r6() || STI->inMicroMipsMode())
@@ -893,16 +956,19 @@ bool MipsBranchExpansion::runOnMachineFunction(MachineFunction &MF) {
893956
bool forbiddenSlotChanged = handleForbiddenSlot();
894957
bool fpuDelaySlotChanged = handleFPUDelaySlot();
895958
bool loadDelaySlotChanged = handleLoadDelaySlot();
959+
bool MfloChanged = handleMFLO();
896960

897961
bool Changed = longBranchChanged || forbiddenSlotChanged ||
898-
fpuDelaySlotChanged || loadDelaySlotChanged;
962+
fpuDelaySlotChanged || loadDelaySlotChanged || MfloChanged;
899963

900964
// Then run them alternatively while there are changes.
901965
while (forbiddenSlotChanged) {
902966
longBranchChanged = handlePossibleLongBranch();
903967
fpuDelaySlotChanged = handleFPUDelaySlot();
904968
loadDelaySlotChanged = handleLoadDelaySlot();
905-
if (!longBranchChanged && !fpuDelaySlotChanged && !loadDelaySlotChanged)
969+
MfloChanged = handleMFLO();
970+
if (!longBranchChanged && !fpuDelaySlotChanged && !loadDelaySlotChanged &&
971+
!MfloChanged)
906972
break;
907973
forbiddenSlotChanged = handleForbiddenSlot();
908974
}

llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,12 @@ bool MipsDelaySlotFiller::searchRange(MachineBasicBlock &MBB, IterTy Begin,
744744
bool InMicroMipsMode = STI.inMicroMipsMode();
745745
const MipsInstrInfo *TII = STI.getInstrInfo();
746746
unsigned Opcode = (*Slot).getOpcode();
747+
748+
// In mips1-4, should not put mflo into the delay slot for the return.
749+
if ((IsMFLOMFHI(CurrI->getOpcode())) &&
750+
(!STI.hasMips32() && !STI.hasMips5()))
751+
continue;
752+
747753
// This is complicated by the tail call optimization. For non-PIC code
748754
// there is only a 32bit sized unconditional branch which can be assumed
749755
// to be able to reach the target. b16 only has a range of +/- 1 KB.

llvm/lib/Target/Mips/MipsInstrInfo.cpp

+15
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

+4
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)