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      // Skip over one non-VFP / NEON instruction.
48      if (!LastMI->isBarrier() &&
49          // On A9, AGU and NEON/FPU are muxed.
50          !(STI.isLikeA9() && (LastMI->mayLoad() || LastMI->mayStore())) &&
51          (LastMCID.TSFlags & ARMII::DomainMask) == ARMII::DomainGeneral) {
52        MachineBasicBlock::iterator I = LastMI;
53        if (I != LastMI->getParent()->begin()) {
54          I = llvm::prior(I);
55          DefMI = &*I;
56        }
57      }
58
59      if (TII.isFpMLxInstruction(DefMI->getOpcode()) &&
60          (TII.canCauseFpMLxStall(MI->getOpcode()) ||
61           hasRAWHazard(DefMI, MI, TRI))) {
62        // Try to schedule another instruction for the next 4 cycles.
63        if (FpMLxStalls == 0)
64          FpMLxStalls = 4;
65        return Hazard;
66      }
67    }
68  }
69
70  return ScoreboardHazardRecognizer::getHazardType(SU, Stalls);
71}
72
73void ARMHazardRecognizer::Reset() {
74  LastMI = 0;
75  FpMLxStalls = 0;
76  ScoreboardHazardRecognizer::Reset();
77}
78
79void ARMHazardRecognizer::EmitInstruction(SUnit *SU) {
80  MachineInstr *MI = SU->getInstr();
81  if (!MI->isDebugValue()) {
82    LastMI = MI;
83    FpMLxStalls = 0;
84  }
85
86  ScoreboardHazardRecognizer::EmitInstruction(SU);
87}
88
89void ARMHazardRecognizer::AdvanceCycle() {
90  if (FpMLxStalls && --FpMLxStalls == 0)
91    // Stalled for 4 cycles but still can't schedule any other instructions.
92    LastMI = 0;
93  ScoreboardHazardRecognizer::AdvanceCycle();
94}
95
96void ARMHazardRecognizer::RecedeCycle() {
97  llvm_unreachable("reverse ARM hazard checking unsupported");
98}
99