1*0b57cec5SDimitry Andric //===-- ARMHazardRecognizer.cpp - ARM postra hazard recognizer ------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric 9*0b57cec5SDimitry Andric #include "ARMHazardRecognizer.h" 10*0b57cec5SDimitry Andric #include "ARMBaseInstrInfo.h" 11*0b57cec5SDimitry Andric #include "ARMBaseRegisterInfo.h" 12*0b57cec5SDimitry Andric #include "ARMSubtarget.h" 13*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 14*0b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDAG.h" 15*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 16*0b57cec5SDimitry Andric using namespace llvm; 17*0b57cec5SDimitry Andric 18*0b57cec5SDimitry Andric static bool hasRAWHazard(MachineInstr *DefMI, MachineInstr *MI, 19*0b57cec5SDimitry Andric const TargetRegisterInfo &TRI) { 20*0b57cec5SDimitry Andric // FIXME: Detect integer instructions properly. 21*0b57cec5SDimitry Andric const MCInstrDesc &MCID = MI->getDesc(); 22*0b57cec5SDimitry Andric unsigned Domain = MCID.TSFlags & ARMII::DomainMask; 23*0b57cec5SDimitry Andric if (MI->mayStore()) 24*0b57cec5SDimitry Andric return false; 25*0b57cec5SDimitry Andric unsigned Opcode = MCID.getOpcode(); 26*0b57cec5SDimitry Andric if (Opcode == ARM::VMOVRS || Opcode == ARM::VMOVRRD) 27*0b57cec5SDimitry Andric return false; 28*0b57cec5SDimitry Andric if ((Domain & ARMII::DomainVFP) || (Domain & ARMII::DomainNEON)) 29*0b57cec5SDimitry Andric return MI->readsRegister(DefMI->getOperand(0).getReg(), &TRI); 30*0b57cec5SDimitry Andric return false; 31*0b57cec5SDimitry Andric } 32*0b57cec5SDimitry Andric 33*0b57cec5SDimitry Andric ScheduleHazardRecognizer::HazardType 34*0b57cec5SDimitry Andric ARMHazardRecognizer::getHazardType(SUnit *SU, int Stalls) { 35*0b57cec5SDimitry Andric assert(Stalls == 0 && "ARM hazards don't support scoreboard lookahead"); 36*0b57cec5SDimitry Andric 37*0b57cec5SDimitry Andric MachineInstr *MI = SU->getInstr(); 38*0b57cec5SDimitry Andric 39*0b57cec5SDimitry Andric if (!MI->isDebugInstr()) { 40*0b57cec5SDimitry Andric // Look for special VMLA / VMLS hazards. A VMUL / VADD / VSUB following 41*0b57cec5SDimitry Andric // a VMLA / VMLS will cause 4 cycle stall. 42*0b57cec5SDimitry Andric const MCInstrDesc &MCID = MI->getDesc(); 43*0b57cec5SDimitry Andric if (LastMI && (MCID.TSFlags & ARMII::DomainMask) != ARMII::DomainGeneral) { 44*0b57cec5SDimitry Andric MachineInstr *DefMI = LastMI; 45*0b57cec5SDimitry Andric const MCInstrDesc &LastMCID = LastMI->getDesc(); 46*0b57cec5SDimitry Andric const MachineFunction *MF = MI->getParent()->getParent(); 47*0b57cec5SDimitry Andric const ARMBaseInstrInfo &TII = *static_cast<const ARMBaseInstrInfo *>( 48*0b57cec5SDimitry Andric MF->getSubtarget().getInstrInfo()); 49*0b57cec5SDimitry Andric 50*0b57cec5SDimitry Andric // Skip over one non-VFP / NEON instruction. 51*0b57cec5SDimitry Andric if (!LastMI->isBarrier() && 52*0b57cec5SDimitry Andric !(TII.getSubtarget().hasMuxedUnits() && LastMI->mayLoadOrStore()) && 53*0b57cec5SDimitry Andric (LastMCID.TSFlags & ARMII::DomainMask) == ARMII::DomainGeneral) { 54*0b57cec5SDimitry Andric MachineBasicBlock::iterator I = LastMI; 55*0b57cec5SDimitry Andric if (I != LastMI->getParent()->begin()) { 56*0b57cec5SDimitry Andric I = std::prev(I); 57*0b57cec5SDimitry Andric DefMI = &*I; 58*0b57cec5SDimitry Andric } 59*0b57cec5SDimitry Andric } 60*0b57cec5SDimitry Andric 61*0b57cec5SDimitry Andric if (TII.isFpMLxInstruction(DefMI->getOpcode()) && 62*0b57cec5SDimitry Andric (TII.canCauseFpMLxStall(MI->getOpcode()) || 63*0b57cec5SDimitry Andric hasRAWHazard(DefMI, MI, TII.getRegisterInfo()))) { 64*0b57cec5SDimitry Andric // Try to schedule another instruction for the next 4 cycles. 65*0b57cec5SDimitry Andric if (FpMLxStalls == 0) 66*0b57cec5SDimitry Andric FpMLxStalls = 4; 67*0b57cec5SDimitry Andric return Hazard; 68*0b57cec5SDimitry Andric } 69*0b57cec5SDimitry Andric } 70*0b57cec5SDimitry Andric } 71*0b57cec5SDimitry Andric 72*0b57cec5SDimitry Andric return ScoreboardHazardRecognizer::getHazardType(SU, Stalls); 73*0b57cec5SDimitry Andric } 74*0b57cec5SDimitry Andric 75*0b57cec5SDimitry Andric void ARMHazardRecognizer::Reset() { 76*0b57cec5SDimitry Andric LastMI = nullptr; 77*0b57cec5SDimitry Andric FpMLxStalls = 0; 78*0b57cec5SDimitry Andric ScoreboardHazardRecognizer::Reset(); 79*0b57cec5SDimitry Andric } 80*0b57cec5SDimitry Andric 81*0b57cec5SDimitry Andric void ARMHazardRecognizer::EmitInstruction(SUnit *SU) { 82*0b57cec5SDimitry Andric MachineInstr *MI = SU->getInstr(); 83*0b57cec5SDimitry Andric if (!MI->isDebugInstr()) { 84*0b57cec5SDimitry Andric LastMI = MI; 85*0b57cec5SDimitry Andric FpMLxStalls = 0; 86*0b57cec5SDimitry Andric } 87*0b57cec5SDimitry Andric 88*0b57cec5SDimitry Andric ScoreboardHazardRecognizer::EmitInstruction(SU); 89*0b57cec5SDimitry Andric } 90*0b57cec5SDimitry Andric 91*0b57cec5SDimitry Andric void ARMHazardRecognizer::AdvanceCycle() { 92*0b57cec5SDimitry Andric if (FpMLxStalls && --FpMLxStalls == 0) 93*0b57cec5SDimitry Andric // Stalled for 4 cycles but still can't schedule any other instructions. 94*0b57cec5SDimitry Andric LastMI = nullptr; 95*0b57cec5SDimitry Andric ScoreboardHazardRecognizer::AdvanceCycle(); 96*0b57cec5SDimitry Andric } 97*0b57cec5SDimitry Andric 98*0b57cec5SDimitry Andric void ARMHazardRecognizer::RecedeCycle() { 99*0b57cec5SDimitry Andric llvm_unreachable("reverse ARM hazard checking unsupported"); 100*0b57cec5SDimitry Andric } 101