1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
//===- MipsMulMulBugPass.cpp - Mips VR4300 mulmul bugfix pass -------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Early revisions of the VR4300 have a hardware bug where two consecutive
// multiplications can produce an incorrect result in the second multiply.
//
// This pass scans for mul instructions in each basic block and inserts
// a nop whenever the following conditions are met:
//
// - The current instruction is a single or double-precision floating-point
// mul instruction.
// - The next instruction is either a mul instruction (any kind)
// or a branch instruction.
//===----------------------------------------------------------------------===//
#include "Mips.h"
#include "MipsInstrInfo.h"
#include "MipsSubtarget.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetMachine.h"
#define DEBUG_TYPE "mips-vr4300-mulmul-fix"
using namespace llvm;
namespace {
class MipsMulMulBugFix : public MachineFunctionPass {
public:
MipsMulMulBugFix() : MachineFunctionPass(ID) {
initializeMipsMulMulBugFixPass(*PassRegistry::getPassRegistry());
}
StringRef getPassName() const override { return "Mips VR4300 mulmul bugfix"; }
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
MachineFunctionProperties::Property::NoVRegs);
}
bool runOnMachineFunction(MachineFunction &MF) override;
static char ID;
private:
bool fixMulMulBB(MachineBasicBlock &MBB, const MipsInstrInfo &MipsII);
};
} // namespace
INITIALIZE_PASS(MipsMulMulBugFix, "mips-vr4300-mulmul-fix",
"Mips VR4300 mulmul bugfix", false, false)
char MipsMulMulBugFix::ID = 0;
bool MipsMulMulBugFix::runOnMachineFunction(MachineFunction &MF) {
const MipsInstrInfo &MipsII =
*static_cast<const MipsInstrInfo *>(MF.getSubtarget().getInstrInfo());
bool Modified = false;
for (auto &MBB : MF)
Modified |= fixMulMulBB(MBB, MipsII);
return Modified;
}
static bool isFirstMul(const MachineInstr &MI) {
switch (MI.getOpcode()) {
case Mips::FMUL_S:
case Mips::FMUL_D:
case Mips::FMUL_D32:
case Mips::FMUL_D64:
return true;
default:
return false;
}
}
static bool isSecondMulOrBranch(const MachineInstr &MI) {
if (MI.isBranch() || MI.isIndirectBranch() || MI.isCall())
return true;
switch (MI.getOpcode()) {
case Mips::MUL:
case Mips::FMUL_S:
case Mips::FMUL_D:
case Mips::FMUL_D32:
case Mips::FMUL_D64:
case Mips::MULT:
case Mips::MULTu:
case Mips::DMULT:
case Mips::DMULTu:
return true;
default:
return false;
}
}
bool MipsMulMulBugFix::fixMulMulBB(MachineBasicBlock &MBB,
const MipsInstrInfo &MipsII) {
bool Modified = false;
MachineBasicBlock::instr_iterator NextMII;
// Iterate through the instructions in the basic block
for (MachineBasicBlock::instr_iterator MII = MBB.instr_begin(),
E = MBB.instr_end();
MII != E; MII = NextMII) {
NextMII = next_nodbg(MII, E);
// Trigger when the current instruction is a mul and the next instruction
// is either a mul or a branch in case the branch target start with a mul
if (NextMII != E && isFirstMul(*MII) && isSecondMulOrBranch(*NextMII)) {
LLVM_DEBUG(dbgs() << "Found mulmul!\n");
const MCInstrDesc &NewMCID = MipsII.get(Mips::NOP);
BuildMI(MBB, NextMII, DebugLoc(), NewMCID);
Modified = true;
}
}
return Modified;
}
FunctionPass *llvm::createMipsMulMulBugPass() { return new MipsMulMulBugFix(); }
|