162c7b5bfSEvan Cheng //===-- MLxExpansionPass.cpp - Expand MLx instrs to avoid hazards ----------=// 262c7b5bfSEvan Cheng // 362c7b5bfSEvan Cheng // The LLVM Compiler Infrastructure 462c7b5bfSEvan Cheng // 562c7b5bfSEvan Cheng // This file is distributed under the University of Illinois Open Source 662c7b5bfSEvan Cheng // License. See LICENSE.TXT for details. 762c7b5bfSEvan Cheng // 862c7b5bfSEvan Cheng //===----------------------------------------------------------------------===// 962c7b5bfSEvan Cheng // 1062c7b5bfSEvan Cheng // Expand VFP / NEON floating point MLA / MLS instructions (each to a pair of 1162c7b5bfSEvan Cheng // multiple and add / sub instructions) when special VMLx hazards are detected. 1262c7b5bfSEvan Cheng // 1362c7b5bfSEvan Cheng //===----------------------------------------------------------------------===// 1462c7b5bfSEvan Cheng 1562c7b5bfSEvan Cheng #define DEBUG_TYPE "mlx-expansion" 1662c7b5bfSEvan Cheng #include "ARM.h" 1762c7b5bfSEvan Cheng #include "ARMBaseInstrInfo.h" 1862c7b5bfSEvan Cheng #include "llvm/CodeGen/MachineInstr.h" 1962c7b5bfSEvan Cheng #include "llvm/CodeGen/MachineInstrBuilder.h" 2062c7b5bfSEvan Cheng #include "llvm/CodeGen/MachineFunctionPass.h" 2162c7b5bfSEvan Cheng #include "llvm/CodeGen/MachineRegisterInfo.h" 2262c7b5bfSEvan Cheng #include "llvm/Target/TargetRegisterInfo.h" 2362c7b5bfSEvan Cheng #include "llvm/ADT/Statistic.h" 2462c7b5bfSEvan Cheng #include "llvm/Support/CommandLine.h" 2562c7b5bfSEvan Cheng #include "llvm/Support/Debug.h" 2662c7b5bfSEvan Cheng #include "llvm/Support/raw_ostream.h" 2762c7b5bfSEvan Cheng using namespace llvm; 2862c7b5bfSEvan Cheng 2962c7b5bfSEvan Cheng static cl::opt<bool> 3062c7b5bfSEvan Cheng ForceExapnd("expand-all-fp-mlx", cl::init(false), cl::Hidden); 3162c7b5bfSEvan Cheng static cl::opt<unsigned> 3262c7b5bfSEvan Cheng ExpandLimit("expand-limit", cl::init(~0U), cl::Hidden); 3362c7b5bfSEvan Cheng 3462c7b5bfSEvan Cheng STATISTIC(NumExpand, "Number of fp MLA / MLS instructions expanded"); 3562c7b5bfSEvan Cheng 3662c7b5bfSEvan Cheng namespace { 3762c7b5bfSEvan Cheng struct MLxExpansion : public MachineFunctionPass { 3862c7b5bfSEvan Cheng static char ID; 3962c7b5bfSEvan Cheng MLxExpansion() : MachineFunctionPass(ID) {} 4062c7b5bfSEvan Cheng 4162c7b5bfSEvan Cheng virtual bool runOnMachineFunction(MachineFunction &Fn); 4262c7b5bfSEvan Cheng 4362c7b5bfSEvan Cheng virtual const char *getPassName() const { 4462c7b5bfSEvan Cheng return "ARM MLA / MLS expansion pass"; 4562c7b5bfSEvan Cheng } 4662c7b5bfSEvan Cheng 4762c7b5bfSEvan Cheng private: 4862c7b5bfSEvan Cheng const ARMBaseInstrInfo *TII; 4962c7b5bfSEvan Cheng const TargetRegisterInfo *TRI; 5062c7b5bfSEvan Cheng MachineRegisterInfo *MRI; 5162c7b5bfSEvan Cheng 5262c7b5bfSEvan Cheng unsigned MIIdx; 5362c7b5bfSEvan Cheng MachineInstr* LastMIs[4]; 5462c7b5bfSEvan Cheng 5562c7b5bfSEvan Cheng void clearStack(); 5662c7b5bfSEvan Cheng void pushStack(MachineInstr *MI); 5762c7b5bfSEvan Cheng MachineInstr *getAccDefMI(MachineInstr *MI) const; 5862c7b5bfSEvan Cheng unsigned getDefReg(MachineInstr *MI) const; 5962c7b5bfSEvan Cheng bool hasRAWHazard(unsigned Reg, MachineInstr *MI) const; 6062c7b5bfSEvan Cheng bool FindMLxHazard(MachineInstr *MI) const; 6162c7b5bfSEvan Cheng void ExpandFPMLxInstruction(MachineBasicBlock &MBB, MachineInstr *MI, 6262c7b5bfSEvan Cheng unsigned MulOpc, unsigned AddSubOpc, 6362c7b5bfSEvan Cheng bool NegAcc, bool HasLane); 6462c7b5bfSEvan Cheng bool ExpandFPMLxInstructions(MachineBasicBlock &MBB); 6562c7b5bfSEvan Cheng }; 6662c7b5bfSEvan Cheng char MLxExpansion::ID = 0; 6762c7b5bfSEvan Cheng } 6862c7b5bfSEvan Cheng 6962c7b5bfSEvan Cheng void MLxExpansion::clearStack() { 7062c7b5bfSEvan Cheng std::fill(LastMIs, LastMIs + 4, (MachineInstr*)0); 7162c7b5bfSEvan Cheng MIIdx = 0; 7262c7b5bfSEvan Cheng } 7362c7b5bfSEvan Cheng 7462c7b5bfSEvan Cheng void MLxExpansion::pushStack(MachineInstr *MI) { 7562c7b5bfSEvan Cheng LastMIs[MIIdx] = MI; 7662c7b5bfSEvan Cheng if (++MIIdx == 4) 7762c7b5bfSEvan Cheng MIIdx = 0; 7862c7b5bfSEvan Cheng } 7962c7b5bfSEvan Cheng 8062c7b5bfSEvan Cheng MachineInstr *MLxExpansion::getAccDefMI(MachineInstr *MI) const { 8162c7b5bfSEvan Cheng // Look past COPY and INSERT_SUBREG instructions to find the 8262c7b5bfSEvan Cheng // real definition MI. This is important for _sfp instructions. 8362c7b5bfSEvan Cheng unsigned Reg = MI->getOperand(1).getReg(); 8462c7b5bfSEvan Cheng if (TargetRegisterInfo::isPhysicalRegister(Reg)) 8562c7b5bfSEvan Cheng return 0; 8662c7b5bfSEvan Cheng 8762c7b5bfSEvan Cheng MachineBasicBlock *MBB = MI->getParent(); 8862c7b5bfSEvan Cheng MachineInstr *DefMI = MRI->getVRegDef(Reg); 8962c7b5bfSEvan Cheng while (true) { 9062c7b5bfSEvan Cheng if (DefMI->getParent() != MBB) 9162c7b5bfSEvan Cheng break; 9262c7b5bfSEvan Cheng if (DefMI->isCopyLike()) { 9362c7b5bfSEvan Cheng Reg = DefMI->getOperand(1).getReg(); 9462c7b5bfSEvan Cheng if (TargetRegisterInfo::isVirtualRegister(Reg)) { 9562c7b5bfSEvan Cheng DefMI = MRI->getVRegDef(Reg); 9662c7b5bfSEvan Cheng continue; 9762c7b5bfSEvan Cheng } 9862c7b5bfSEvan Cheng } else if (DefMI->isInsertSubreg()) { 9962c7b5bfSEvan Cheng Reg = DefMI->getOperand(2).getReg(); 10062c7b5bfSEvan Cheng if (TargetRegisterInfo::isVirtualRegister(Reg)) { 10162c7b5bfSEvan Cheng DefMI = MRI->getVRegDef(Reg); 10262c7b5bfSEvan Cheng continue; 10362c7b5bfSEvan Cheng } 10462c7b5bfSEvan Cheng } 10562c7b5bfSEvan Cheng break; 10662c7b5bfSEvan Cheng } 10762c7b5bfSEvan Cheng return DefMI; 10862c7b5bfSEvan Cheng } 10962c7b5bfSEvan Cheng 11062c7b5bfSEvan Cheng unsigned MLxExpansion::getDefReg(MachineInstr *MI) const { 11162c7b5bfSEvan Cheng unsigned Reg = MI->getOperand(0).getReg(); 11262c7b5bfSEvan Cheng if (TargetRegisterInfo::isPhysicalRegister(Reg) || 11362c7b5bfSEvan Cheng !MRI->hasOneNonDBGUse(Reg)) 11462c7b5bfSEvan Cheng return Reg; 11562c7b5bfSEvan Cheng 11662c7b5bfSEvan Cheng MachineBasicBlock *MBB = MI->getParent(); 11762c7b5bfSEvan Cheng MachineInstr *UseMI = &*MRI->use_nodbg_begin(Reg); 11862c7b5bfSEvan Cheng if (UseMI->getParent() != MBB) 11962c7b5bfSEvan Cheng return Reg; 12062c7b5bfSEvan Cheng 12162c7b5bfSEvan Cheng while (UseMI->isCopy() || UseMI->isInsertSubreg()) { 12262c7b5bfSEvan Cheng Reg = UseMI->getOperand(0).getReg(); 12362c7b5bfSEvan Cheng if (TargetRegisterInfo::isPhysicalRegister(Reg) || 12462c7b5bfSEvan Cheng !MRI->hasOneNonDBGUse(Reg)) 12562c7b5bfSEvan Cheng return Reg; 12662c7b5bfSEvan Cheng UseMI = &*MRI->use_nodbg_begin(Reg); 12762c7b5bfSEvan Cheng if (UseMI->getParent() != MBB) 12862c7b5bfSEvan Cheng return Reg; 12962c7b5bfSEvan Cheng } 13062c7b5bfSEvan Cheng 13162c7b5bfSEvan Cheng return Reg; 13262c7b5bfSEvan Cheng } 13362c7b5bfSEvan Cheng 13462c7b5bfSEvan Cheng bool MLxExpansion::hasRAWHazard(unsigned Reg, MachineInstr *MI) const { 13562c7b5bfSEvan Cheng // FIXME: Detect integer instructions properly. 136*04ad35b5SEvan Cheng const TargetInstrDesc &TID = MI->getDesc(); 13762c7b5bfSEvan Cheng unsigned Domain = TID.TSFlags & ARMII::DomainMask; 138*04ad35b5SEvan Cheng if (TID.mayStore()) 139*04ad35b5SEvan Cheng return false; 14062c7b5bfSEvan Cheng unsigned Opcode = TID.getOpcode(); 141*04ad35b5SEvan Cheng if (Opcode == ARM::VMOVRS || Opcode == ARM::VMOVRRD) 14262c7b5bfSEvan Cheng return false; 143*04ad35b5SEvan Cheng if ((Domain & ARMII::DomainVFP) || (Domain & ARMII::DomainNEON)) 14462c7b5bfSEvan Cheng return MI->readsRegister(Reg, TRI); 14562c7b5bfSEvan Cheng return false; 14662c7b5bfSEvan Cheng } 14762c7b5bfSEvan Cheng 14862c7b5bfSEvan Cheng 14962c7b5bfSEvan Cheng bool MLxExpansion::FindMLxHazard(MachineInstr *MI) const { 15062c7b5bfSEvan Cheng if (NumExpand >= ExpandLimit) 15162c7b5bfSEvan Cheng return false; 15262c7b5bfSEvan Cheng 15362c7b5bfSEvan Cheng if (ForceExapnd) 15462c7b5bfSEvan Cheng return true; 15562c7b5bfSEvan Cheng 15662c7b5bfSEvan Cheng MachineInstr *DefMI = getAccDefMI(MI); 15762c7b5bfSEvan Cheng if (TII->isFpMLxInstruction(DefMI->getOpcode())) 15862c7b5bfSEvan Cheng // r0 = vmla 15962c7b5bfSEvan Cheng // r3 = vmla r0, r1, r2 16062c7b5bfSEvan Cheng // takes 16 - 17 cycles 16162c7b5bfSEvan Cheng // 16262c7b5bfSEvan Cheng // r0 = vmla 16362c7b5bfSEvan Cheng // r4 = vmul r1, r2 16462c7b5bfSEvan Cheng // r3 = vadd r0, r4 16562c7b5bfSEvan Cheng // takes about 14 - 15 cycles even with vmul stalling for 4 cycles. 16662c7b5bfSEvan Cheng return true; 16762c7b5bfSEvan Cheng 16862c7b5bfSEvan Cheng // If a VMLA.F is followed by an VADD.F or VMUL.F with no RAW hazard, the 16962c7b5bfSEvan Cheng // VADD.F or VMUL.F will stall 4 cycles before issue. The 4 cycle stall 17062c7b5bfSEvan Cheng // preserves the in-order retirement of the instructions. 17162c7b5bfSEvan Cheng // Look at the next few instructions, if *most* of them can cause hazards, 17262c7b5bfSEvan Cheng // then the scheduler can't *fix* this, we'd better break up the VMLA. 17362c7b5bfSEvan Cheng for (unsigned i = 1; i <= 4; ++i) { 17462c7b5bfSEvan Cheng int Idx = ((int)MIIdx - i + 4) % 4; 17562c7b5bfSEvan Cheng MachineInstr *NextMI = LastMIs[Idx]; 17662c7b5bfSEvan Cheng if (!NextMI) 17762c7b5bfSEvan Cheng continue; 17862c7b5bfSEvan Cheng 17962c7b5bfSEvan Cheng if (TII->canCauseFpMLxStall(NextMI->getOpcode())) 18062c7b5bfSEvan Cheng return true; 18162c7b5bfSEvan Cheng 18262c7b5bfSEvan Cheng // Look for VMLx RAW hazard. 18362c7b5bfSEvan Cheng if (hasRAWHazard(getDefReg(MI), NextMI)) 18462c7b5bfSEvan Cheng return true; 18562c7b5bfSEvan Cheng } 18662c7b5bfSEvan Cheng 18762c7b5bfSEvan Cheng return false; 18862c7b5bfSEvan Cheng } 18962c7b5bfSEvan Cheng 19062c7b5bfSEvan Cheng /// ExpandFPMLxInstructions - Expand a MLA / MLS instruction into a pair 19162c7b5bfSEvan Cheng /// of MUL + ADD / SUB instructions. 19262c7b5bfSEvan Cheng void 19362c7b5bfSEvan Cheng MLxExpansion::ExpandFPMLxInstruction(MachineBasicBlock &MBB, MachineInstr *MI, 19462c7b5bfSEvan Cheng unsigned MulOpc, unsigned AddSubOpc, 19562c7b5bfSEvan Cheng bool NegAcc, bool HasLane) { 19662c7b5bfSEvan Cheng unsigned DstReg = MI->getOperand(0).getReg(); 19762c7b5bfSEvan Cheng bool DstDead = MI->getOperand(0).isDead(); 19862c7b5bfSEvan Cheng unsigned AccReg = MI->getOperand(1).getReg(); 19962c7b5bfSEvan Cheng unsigned Src1Reg = MI->getOperand(2).getReg(); 20062c7b5bfSEvan Cheng unsigned Src2Reg = MI->getOperand(3).getReg(); 20162c7b5bfSEvan Cheng bool Src1Kill = MI->getOperand(2).isKill(); 20262c7b5bfSEvan Cheng bool Src2Kill = MI->getOperand(3).isKill(); 20362c7b5bfSEvan Cheng unsigned LaneImm = HasLane ? MI->getOperand(4).getImm() : 0; 20462c7b5bfSEvan Cheng unsigned NextOp = HasLane ? 5 : 4; 20562c7b5bfSEvan Cheng ARMCC::CondCodes Pred = (ARMCC::CondCodes)MI->getOperand(NextOp).getImm(); 20662c7b5bfSEvan Cheng unsigned PredReg = MI->getOperand(++NextOp).getReg(); 20762c7b5bfSEvan Cheng 20862c7b5bfSEvan Cheng const TargetInstrDesc &TID1 = TII->get(MulOpc); 20962c7b5bfSEvan Cheng const TargetInstrDesc &TID2 = TII->get(AddSubOpc); 21062c7b5bfSEvan Cheng unsigned TmpReg = MRI->createVirtualRegister(TID1.getRegClass(0, TRI)); 21162c7b5bfSEvan Cheng 21262c7b5bfSEvan Cheng MachineInstrBuilder MIB = BuildMI(MBB, *MI, MI->getDebugLoc(), TID1, TmpReg) 21362c7b5bfSEvan Cheng .addReg(Src1Reg, getKillRegState(Src1Kill)) 21462c7b5bfSEvan Cheng .addReg(Src2Reg, getKillRegState(Src2Kill)); 21562c7b5bfSEvan Cheng if (HasLane) 21662c7b5bfSEvan Cheng MIB.addImm(LaneImm); 21762c7b5bfSEvan Cheng MIB.addImm(Pred).addReg(PredReg); 21862c7b5bfSEvan Cheng 21962c7b5bfSEvan Cheng MIB = BuildMI(MBB, *MI, MI->getDebugLoc(), TID2) 22062c7b5bfSEvan Cheng .addReg(DstReg, getDefRegState(true) | getDeadRegState(DstDead)); 22162c7b5bfSEvan Cheng 22262c7b5bfSEvan Cheng if (NegAcc) { 22362c7b5bfSEvan Cheng bool AccKill = MRI->hasOneNonDBGUse(AccReg); 22462c7b5bfSEvan Cheng MIB.addReg(TmpReg, getKillRegState(true)) 22562c7b5bfSEvan Cheng .addReg(AccReg, getKillRegState(AccKill)); 22662c7b5bfSEvan Cheng } else { 22762c7b5bfSEvan Cheng MIB.addReg(AccReg).addReg(TmpReg, getKillRegState(true)); 22862c7b5bfSEvan Cheng } 22962c7b5bfSEvan Cheng MIB.addImm(Pred).addReg(PredReg); 23062c7b5bfSEvan Cheng 23162c7b5bfSEvan Cheng DEBUG({ 23262c7b5bfSEvan Cheng dbgs() << "Expanding: " << *MI; 23362c7b5bfSEvan Cheng dbgs() << " to:\n"; 23462c7b5bfSEvan Cheng MachineBasicBlock::iterator MII = MI; 23562c7b5bfSEvan Cheng MII = llvm::prior(MII); 23662c7b5bfSEvan Cheng MachineInstr &MI2 = *MII; 23762c7b5bfSEvan Cheng MII = llvm::prior(MII); 23862c7b5bfSEvan Cheng MachineInstr &MI1 = *MII; 23962c7b5bfSEvan Cheng dbgs() << " " << MI1; 24062c7b5bfSEvan Cheng dbgs() << " " << MI2; 24162c7b5bfSEvan Cheng }); 24262c7b5bfSEvan Cheng 24362c7b5bfSEvan Cheng MI->eraseFromParent(); 24462c7b5bfSEvan Cheng ++NumExpand; 24562c7b5bfSEvan Cheng } 24662c7b5bfSEvan Cheng 24762c7b5bfSEvan Cheng bool MLxExpansion::ExpandFPMLxInstructions(MachineBasicBlock &MBB) { 24862c7b5bfSEvan Cheng bool Changed = false; 24962c7b5bfSEvan Cheng 25062c7b5bfSEvan Cheng clearStack(); 25162c7b5bfSEvan Cheng 25262c7b5bfSEvan Cheng unsigned Skip = 0; 25362c7b5bfSEvan Cheng MachineBasicBlock::reverse_iterator MII = MBB.rbegin(), E = MBB.rend(); 25462c7b5bfSEvan Cheng while (MII != E) { 25562c7b5bfSEvan Cheng MachineInstr *MI = &*MII; 25662c7b5bfSEvan Cheng 25762c7b5bfSEvan Cheng if (MI->isLabel() || MI->isImplicitDef() || MI->isCopy()) { 25862c7b5bfSEvan Cheng ++MII; 25962c7b5bfSEvan Cheng continue; 26062c7b5bfSEvan Cheng } 26162c7b5bfSEvan Cheng 26262c7b5bfSEvan Cheng const TargetInstrDesc &TID = MI->getDesc(); 26362c7b5bfSEvan Cheng if (TID.isBarrier()) { 26462c7b5bfSEvan Cheng clearStack(); 26562c7b5bfSEvan Cheng Skip = 0; 26662c7b5bfSEvan Cheng ++MII; 26762c7b5bfSEvan Cheng continue; 26862c7b5bfSEvan Cheng } 26962c7b5bfSEvan Cheng 27062c7b5bfSEvan Cheng unsigned Domain = TID.TSFlags & ARMII::DomainMask; 27162c7b5bfSEvan Cheng if (Domain == ARMII::DomainGeneral) { 27262c7b5bfSEvan Cheng if (++Skip == 2) 27362c7b5bfSEvan Cheng // Assume dual issues of non-VFP / NEON instructions. 27462c7b5bfSEvan Cheng pushStack(0); 27562c7b5bfSEvan Cheng } else { 27662c7b5bfSEvan Cheng Skip = 0; 27762c7b5bfSEvan Cheng 27862c7b5bfSEvan Cheng unsigned MulOpc, AddSubOpc; 27962c7b5bfSEvan Cheng bool NegAcc, HasLane; 28062c7b5bfSEvan Cheng if (!TII->isFpMLxInstruction(TID.getOpcode(), 28162c7b5bfSEvan Cheng MulOpc, AddSubOpc, NegAcc, HasLane) || 28262c7b5bfSEvan Cheng !FindMLxHazard(MI)) 28362c7b5bfSEvan Cheng pushStack(MI); 28462c7b5bfSEvan Cheng else { 28562c7b5bfSEvan Cheng ExpandFPMLxInstruction(MBB, MI, MulOpc, AddSubOpc, NegAcc, HasLane); 28662c7b5bfSEvan Cheng E = MBB.rend(); // May have changed if MI was the 1st instruction. 28762c7b5bfSEvan Cheng Changed = true; 28862c7b5bfSEvan Cheng continue; 28962c7b5bfSEvan Cheng } 29062c7b5bfSEvan Cheng } 29162c7b5bfSEvan Cheng 29262c7b5bfSEvan Cheng ++MII; 29362c7b5bfSEvan Cheng } 29462c7b5bfSEvan Cheng 29562c7b5bfSEvan Cheng return Changed; 29662c7b5bfSEvan Cheng } 29762c7b5bfSEvan Cheng 29862c7b5bfSEvan Cheng bool MLxExpansion::runOnMachineFunction(MachineFunction &Fn) { 29962c7b5bfSEvan Cheng TII = static_cast<const ARMBaseInstrInfo*>(Fn.getTarget().getInstrInfo()); 30062c7b5bfSEvan Cheng TRI = Fn.getTarget().getRegisterInfo(); 30162c7b5bfSEvan Cheng MRI = &Fn.getRegInfo(); 30262c7b5bfSEvan Cheng 30362c7b5bfSEvan Cheng bool Modified = false; 30462c7b5bfSEvan Cheng for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E; 30562c7b5bfSEvan Cheng ++MFI) { 30662c7b5bfSEvan Cheng MachineBasicBlock &MBB = *MFI; 30762c7b5bfSEvan Cheng Modified |= ExpandFPMLxInstructions(MBB); 30862c7b5bfSEvan Cheng } 30962c7b5bfSEvan Cheng 31062c7b5bfSEvan Cheng return Modified; 31162c7b5bfSEvan Cheng } 31262c7b5bfSEvan Cheng 31362c7b5bfSEvan Cheng FunctionPass *llvm::createMLxExpansionPass() { 31462c7b5bfSEvan Cheng return new MLxExpansion(); 31562c7b5bfSEvan Cheng } 316