xref: /llvm-project/llvm/lib/Target/Mips/MipsMulMulBugPass.cpp (revision 73e89cf66d4b88d568ff4c718ae7bf55588ef2be)
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