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() && LastMI->mayLoadOrStore()) &&
55          (LastMCID.TSFlags & ARMII::DomainMask) == ARMII::DomainGeneral) {
56        MachineBasicBlock::iterator I = LastMI;
57        if (I != LastMI->getParent()->begin()) {
58          I = std::prev(I);
59          DefMI = &*I;
60        }
61      }
62
63      if (TII.isFpMLxInstruction(DefMI->getOpcode()) &&
64          (TII.canCauseFpMLxStall(MI->getOpcode()) ||
65           hasRAWHazard(DefMI, MI, TII.getRegisterInfo()))) {
66        // Try to schedule another instruction for the next 4 cycles.
67        if (FpMLxStalls == 0)
68          FpMLxStalls = 4;
69        return Hazard;
70      }
71    }
72  }
73
74  return ScoreboardHazardRecognizer::getHazardType(SU, Stalls);
75}
76
77void ARMHazardRecognizer::Reset() {
78  LastMI = nullptr;
79  FpMLxStalls = 0;
80  ScoreboardHazardRecognizer::Reset();
81}
82
83void ARMHazardRecognizer::EmitInstruction(SUnit *SU) {
84  MachineInstr *MI = SU->getInstr();
85  if (!MI->isDebugValue()) {
86    LastMI = MI;
87    FpMLxStalls = 0;
88  }
89
90  ScoreboardHazardRecognizer::EmitInstruction(SU);
91}
92
93void ARMHazardRecognizer::AdvanceCycle() {
94  if (FpMLxStalls && --FpMLxStalls == 0)
95    // Stalled for 4 cycles but still can't schedule any other instructions.
96    LastMI = nullptr;
97  ScoreboardHazardRecognizer::AdvanceCycle();
98}
99
100void ARMHazardRecognizer::RecedeCycle() {
101  llvm_unreachable("reverse ARM hazard checking unsupported");
102}
103