//===-- ARMHazardRecognizer.cpp - ARM postra hazard recognizer ------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "ARMHazardRecognizer.h" #include "ARMBaseInstrInfo.h" #include "ARMBaseRegisterInfo.h" #include "ARMSubtarget.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/ScheduleDAG.h" #include "llvm/Target/TargetRegisterInfo.h" using namespace llvm; static bool hasRAWHazard(MachineInstr *DefMI, MachineInstr *MI, const TargetRegisterInfo &TRI) { // FIXME: Detect integer instructions properly. const MCInstrDesc &MCID = MI->getDesc(); unsigned Domain = MCID.TSFlags & ARMII::DomainMask; if (MCID.mayStore()) return false; unsigned Opcode = MCID.getOpcode(); if (Opcode == ARM::VMOVRS || Opcode == ARM::VMOVRRD) return false; if ((Domain & ARMII::DomainVFP) || (Domain & ARMII::DomainNEON)) return MI->readsRegister(DefMI->getOperand(0).getReg(), &TRI); return false; } ScheduleHazardRecognizer::HazardType ARMHazardRecognizer::getHazardType(SUnit *SU, int Stalls) { assert(Stalls == 0 && "ARM hazards don't support scoreboard lookahead"); MachineInstr *MI = SU->getInstr(); if (!MI->isDebugValue()) { if (ITBlockSize && MI != ITBlockMIs[ITBlockSize-1]) return Hazard; // Look for special VMLA / VMLS hazards. A VMUL / VADD / VSUB following // a VMLA / VMLS will cause 4 cycle stall. const MCInstrDesc &MCID = MI->getDesc(); if (LastMI && (MCID.TSFlags & ARMII::DomainMask) != ARMII::DomainGeneral) { MachineInstr *DefMI = LastMI; const MCInstrDesc &LastMCID = LastMI->getDesc(); // Skip over one non-VFP / NEON instruction. if (!LastMCID.isBarrier() && // On A9, AGU and NEON/FPU are muxed. !(STI.isCortexA9() && (LastMCID.mayLoad() || LastMCID.mayStore())) && (LastMCID.TSFlags & ARMII::DomainMask) == ARMII::DomainGeneral) { MachineBasicBlock::iterator I = LastMI; if (I != LastMI->getParent()->begin()) { I = llvm::prior(I); DefMI = &*I; } } if (TII.isFpMLxInstruction(DefMI->getOpcode()) && (TII.canCauseFpMLxStall(MI->getOpcode()) || hasRAWHazard(DefMI, MI, TRI))) { // Try to schedule another instruction for the next 4 cycles. if (FpMLxStalls == 0) FpMLxStalls = 4; return Hazard; } } } return ScoreboardHazardRecognizer::getHazardType(SU, Stalls); } void ARMHazardRecognizer::Reset() { LastMI = 0; FpMLxStalls = 0; ITBlockSize = 0; ScoreboardHazardRecognizer::Reset(); } void ARMHazardRecognizer::EmitInstruction(SUnit *SU) { MachineInstr *MI = SU->getInstr(); unsigned Opcode = MI->getOpcode(); if (ITBlockSize) { --ITBlockSize; } else if (Opcode == ARM::t2IT) { unsigned Mask = MI->getOperand(1).getImm(); unsigned NumTZ = CountTrailingZeros_32(Mask); assert(NumTZ <= 3 && "Invalid IT mask!"); ITBlockSize = 4 - NumTZ; MachineBasicBlock::iterator I = MI; for (unsigned i = 0; i < ITBlockSize; ++i) { // Advance to the next instruction, skipping any dbg_value instructions. do { ++I; } while (I->isDebugValue()); ITBlockMIs[ITBlockSize-1-i] = &*I; } } if (!MI->isDebugValue()) { LastMI = MI; FpMLxStalls = 0; } ScoreboardHazardRecognizer::EmitInstruction(SU); } void ARMHazardRecognizer::AdvanceCycle() { if (FpMLxStalls && --FpMLxStalls == 0) // Stalled for 4 cycles but still can't schedule any other instructions. LastMI = 0; ScoreboardHazardRecognizer::AdvanceCycle(); } void ARMHazardRecognizer::RecedeCycle() { llvm_unreachable("reverse ARM hazard checking unsupported"); }