12edcde00SRandom //===- MipsMulMulBugPass.cpp - Mips VR4300 mulmul bugfix pass -------------===// 22edcde00SRandom // 32edcde00SRandom // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42edcde00SRandom // See https://llvm.org/LICENSE.txt for license information. 52edcde00SRandom // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 62edcde00SRandom // 72edcde00SRandom //===----------------------------------------------------------------------===// 82edcde00SRandom // 92edcde00SRandom // Early revisions of the VR4300 have a hardware bug where two consecutive 102edcde00SRandom // multiplications can produce an incorrect result in the second multiply. 112edcde00SRandom // 122edcde00SRandom // This pass scans for mul instructions in each basic block and inserts 132edcde00SRandom // a nop whenever the following conditions are met: 142edcde00SRandom // 152edcde00SRandom // - The current instruction is a single or double-precision floating-point 162edcde00SRandom // mul instruction. 172edcde00SRandom // - The next instruction is either a mul instruction (any kind) 182edcde00SRandom // or a branch instruction. 192edcde00SRandom //===----------------------------------------------------------------------===// 202edcde00SRandom 212edcde00SRandom #include "Mips.h" 222edcde00SRandom #include "MipsInstrInfo.h" 232edcde00SRandom #include "MipsSubtarget.h" 242edcde00SRandom #include "llvm/CodeGen/MachineBasicBlock.h" 252edcde00SRandom #include "llvm/CodeGen/MachineFunction.h" 262edcde00SRandom #include "llvm/CodeGen/MachineFunctionPass.h" 272edcde00SRandom #include "llvm/Support/Debug.h" 282edcde00SRandom #include "llvm/Target/TargetMachine.h" 292edcde00SRandom 302edcde00SRandom #define DEBUG_TYPE "mips-vr4300-mulmul-fix" 312edcde00SRandom 322edcde00SRandom using namespace llvm; 332edcde00SRandom 342edcde00SRandom namespace { 352edcde00SRandom 362edcde00SRandom class MipsMulMulBugFix : public MachineFunctionPass { 372edcde00SRandom public: 382edcde00SRandom MipsMulMulBugFix() : MachineFunctionPass(ID) { 392edcde00SRandom initializeMipsMulMulBugFixPass(*PassRegistry::getPassRegistry()); 402edcde00SRandom } 412edcde00SRandom 422edcde00SRandom StringRef getPassName() const override { return "Mips VR4300 mulmul bugfix"; } 432edcde00SRandom 442edcde00SRandom MachineFunctionProperties getRequiredProperties() const override { 452edcde00SRandom return MachineFunctionProperties().set( 462edcde00SRandom MachineFunctionProperties::Property::NoVRegs); 472edcde00SRandom } 482edcde00SRandom 492edcde00SRandom bool runOnMachineFunction(MachineFunction &MF) override; 502edcde00SRandom 512edcde00SRandom static char ID; 522edcde00SRandom 532edcde00SRandom private: 542edcde00SRandom bool fixMulMulBB(MachineBasicBlock &MBB, const MipsInstrInfo &MipsII); 552edcde00SRandom }; 562edcde00SRandom 572edcde00SRandom } // namespace 582edcde00SRandom 592edcde00SRandom INITIALIZE_PASS(MipsMulMulBugFix, "mips-vr4300-mulmul-fix", 602edcde00SRandom "Mips VR4300 mulmul bugfix", false, false) 612edcde00SRandom 622edcde00SRandom char MipsMulMulBugFix::ID = 0; 632edcde00SRandom 642edcde00SRandom bool MipsMulMulBugFix::runOnMachineFunction(MachineFunction &MF) { 652edcde00SRandom const MipsInstrInfo &MipsII = 662edcde00SRandom *static_cast<const MipsInstrInfo *>(MF.getSubtarget().getInstrInfo()); 672edcde00SRandom 682edcde00SRandom bool Modified = false; 692edcde00SRandom 702edcde00SRandom for (auto &MBB : MF) 712edcde00SRandom Modified |= fixMulMulBB(MBB, MipsII); 722edcde00SRandom 732edcde00SRandom return Modified; 742edcde00SRandom } 752edcde00SRandom 762edcde00SRandom static bool isFirstMul(const MachineInstr &MI) { 772edcde00SRandom switch (MI.getOpcode()) { 782edcde00SRandom case Mips::FMUL_S: 792edcde00SRandom case Mips::FMUL_D: 802edcde00SRandom case Mips::FMUL_D32: 812edcde00SRandom case Mips::FMUL_D64: 822edcde00SRandom return true; 832edcde00SRandom default: 842edcde00SRandom return false; 852edcde00SRandom } 862edcde00SRandom } 872edcde00SRandom 882edcde00SRandom static bool isSecondMulOrBranch(const MachineInstr &MI) { 892edcde00SRandom if (MI.isBranch() || MI.isIndirectBranch() || MI.isCall()) 902edcde00SRandom return true; 912edcde00SRandom 922edcde00SRandom switch (MI.getOpcode()) { 932edcde00SRandom case Mips::MUL: 942edcde00SRandom case Mips::FMUL_S: 952edcde00SRandom case Mips::FMUL_D: 962edcde00SRandom case Mips::FMUL_D32: 972edcde00SRandom case Mips::FMUL_D64: 982edcde00SRandom case Mips::MULT: 992edcde00SRandom case Mips::MULTu: 1002edcde00SRandom case Mips::DMULT: 1012edcde00SRandom case Mips::DMULTu: 1022edcde00SRandom return true; 1032edcde00SRandom default: 1042edcde00SRandom return false; 1052edcde00SRandom } 1062edcde00SRandom } 1072edcde00SRandom 1082edcde00SRandom bool MipsMulMulBugFix::fixMulMulBB(MachineBasicBlock &MBB, 1092edcde00SRandom const MipsInstrInfo &MipsII) { 1102edcde00SRandom bool Modified = false; 1112edcde00SRandom 112*ee198df2SRandom06457 MachineBasicBlock::instr_iterator NextMII; 113*ee198df2SRandom06457 1142edcde00SRandom // Iterate through the instructions in the basic block 1152edcde00SRandom for (MachineBasicBlock::instr_iterator MII = MBB.instr_begin(), 1162edcde00SRandom E = MBB.instr_end(); 117*ee198df2SRandom06457 MII != E; MII = NextMII) { 1182edcde00SRandom 119*ee198df2SRandom06457 NextMII = next_nodbg(MII, E); 1202edcde00SRandom 1212edcde00SRandom // Trigger when the current instruction is a mul and the next instruction 1222edcde00SRandom // is either a mul or a branch in case the branch target start with a mul 1232edcde00SRandom if (NextMII != E && isFirstMul(*MII) && isSecondMulOrBranch(*NextMII)) { 124*ee198df2SRandom06457 LLVM_DEBUG(dbgs() << "Found mulmul!\n"); 1252edcde00SRandom 1262edcde00SRandom const MCInstrDesc &NewMCID = MipsII.get(Mips::NOP); 1272edcde00SRandom BuildMI(MBB, NextMII, DebugLoc(), NewMCID); 1282edcde00SRandom Modified = true; 1292edcde00SRandom } 1302edcde00SRandom } 1312edcde00SRandom 1322edcde00SRandom return Modified; 1332edcde00SRandom } 1342edcde00SRandom 1352edcde00SRandom FunctionPass *llvm::createMipsMulMulBugPass() { return new MipsMulMulBugFix(); } 136