1218885Sdim//===-- ARMHazardRecognizer.cpp - ARM postra hazard recognizer ------------===//
2218885Sdim//
3218885Sdim//                     The LLVM Compiler Infrastructure
4218885Sdim//
5218885Sdim// This file is distributed under the University of Illinois Open Source
6218885Sdim// License. See LICENSE.TXT for details.
7218885Sdim//
8218885Sdim//===----------------------------------------------------------------------===//
9218885Sdim
10218885Sdim#include "ARMHazardRecognizer.h"
11218885Sdim#include "ARMBaseInstrInfo.h"
12218885Sdim#include "ARMBaseRegisterInfo.h"
13218885Sdim#include "ARMSubtarget.h"
14218885Sdim#include "llvm/CodeGen/MachineInstr.h"
15218885Sdim#include "llvm/CodeGen/ScheduleDAG.h"
16218885Sdim#include "llvm/Target/TargetRegisterInfo.h"
17218885Sdimusing namespace llvm;
18218885Sdim
19218885Sdimstatic bool hasRAWHazard(MachineInstr *DefMI, MachineInstr *MI,
20218885Sdim                         const TargetRegisterInfo &TRI) {
21218885Sdim  // FIXME: Detect integer instructions properly.
22224145Sdim  const MCInstrDesc &MCID = MI->getDesc();
23224145Sdim  unsigned Domain = MCID.TSFlags & ARMII::DomainMask;
24235633Sdim  if (MI->mayStore())
25218885Sdim    return false;
26224145Sdim  unsigned Opcode = MCID.getOpcode();
27219077Sdim  if (Opcode == ARM::VMOVRS || Opcode == ARM::VMOVRRD)
28219077Sdim    return false;
29219077Sdim  if ((Domain & ARMII::DomainVFP) || (Domain & ARMII::DomainNEON))
30219077Sdim    return MI->readsRegister(DefMI->getOperand(0).getReg(), &TRI);
31219077Sdim  return false;
32218885Sdim}
33218885Sdim
34218885SdimScheduleHazardRecognizer::HazardType
35218885SdimARMHazardRecognizer::getHazardType(SUnit *SU, int Stalls) {
36218885Sdim  assert(Stalls == 0 && "ARM hazards don't support scoreboard lookahead");
37218885Sdim
38218885Sdim  MachineInstr *MI = SU->getInstr();
39218885Sdim
40218885Sdim  if (!MI->isDebugValue()) {
41218885Sdim    // Look for special VMLA / VMLS hazards. A VMUL / VADD / VSUB following
42218885Sdim    // a VMLA / VMLS will cause 4 cycle stall.
43224145Sdim    const MCInstrDesc &MCID = MI->getDesc();
44224145Sdim    if (LastMI && (MCID.TSFlags & ARMII::DomainMask) != ARMII::DomainGeneral) {
45218885Sdim      MachineInstr *DefMI = LastMI;
46224145Sdim      const MCInstrDesc &LastMCID = LastMI->getDesc();
47263509Sdim      const TargetMachine &TM =
48263509Sdim        MI->getParent()->getParent()->getTarget();
49263509Sdim      const ARMBaseInstrInfo &TII =
50263509Sdim        *static_cast<const ARMBaseInstrInfo*>(TM.getInstrInfo());
51263509Sdim
52218885Sdim      // Skip over one non-VFP / NEON instruction.
53235633Sdim      if (!LastMI->isBarrier() &&
54221345Sdim          // On A9, AGU and NEON/FPU are muxed.
55263509Sdim          !(TII.getSubtarget().isLikeA9() &&
56263509Sdim            (LastMI->mayLoad() || LastMI->mayStore())) &&
57224145Sdim          (LastMCID.TSFlags & ARMII::DomainMask) == ARMII::DomainGeneral) {
58218885Sdim        MachineBasicBlock::iterator I = LastMI;
59218885Sdim        if (I != LastMI->getParent()->begin()) {
60218885Sdim          I = llvm::prior(I);
61218885Sdim          DefMI = &*I;
62218885Sdim        }
63218885Sdim      }
64218885Sdim
65218885Sdim      if (TII.isFpMLxInstruction(DefMI->getOpcode()) &&
66218885Sdim          (TII.canCauseFpMLxStall(MI->getOpcode()) ||
67263509Sdim           hasRAWHazard(DefMI, MI, TII.getRegisterInfo()))) {
68218885Sdim        // Try to schedule another instruction for the next 4 cycles.
69218885Sdim        if (FpMLxStalls == 0)
70218885Sdim          FpMLxStalls = 4;
71218885Sdim        return Hazard;
72218885Sdim      }
73218885Sdim    }
74218885Sdim  }
75218885Sdim
76218885Sdim  return ScoreboardHazardRecognizer::getHazardType(SU, Stalls);
77218885Sdim}
78218885Sdim
79218885Sdimvoid ARMHazardRecognizer::Reset() {
80218885Sdim  LastMI = 0;
81218885Sdim  FpMLxStalls = 0;
82218885Sdim  ScoreboardHazardRecognizer::Reset();
83218885Sdim}
84218885Sdim
85218885Sdimvoid ARMHazardRecognizer::EmitInstruction(SUnit *SU) {
86218885Sdim  MachineInstr *MI = SU->getInstr();
87218885Sdim  if (!MI->isDebugValue()) {
88218885Sdim    LastMI = MI;
89218885Sdim    FpMLxStalls = 0;
90218885Sdim  }
91218885Sdim
92218885Sdim  ScoreboardHazardRecognizer::EmitInstruction(SU);
93218885Sdim}
94218885Sdim
95218885Sdimvoid ARMHazardRecognizer::AdvanceCycle() {
96218885Sdim  if (FpMLxStalls && --FpMLxStalls == 0)
97218885Sdim    // Stalled for 4 cycles but still can't schedule any other instructions.
98218885Sdim    LastMI = 0;
99218885Sdim  ScoreboardHazardRecognizer::AdvanceCycle();
100218885Sdim}
101218885Sdim
102218885Sdimvoid ARMHazardRecognizer::RecedeCycle() {
103218885Sdim  llvm_unreachable("reverse ARM hazard checking unsupported");
104218885Sdim}
105