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