ARMHazardRecognizer.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. //===-- ARMHazardRecognizer.cpp - ARM postra hazard recognizer ------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "ARMHazardRecognizer.h"
  9. #include "ARMBaseInstrInfo.h"
  10. #include "ARMBaseRegisterInfo.h"
  11. #include "ARMSubtarget.h"
  12. #include "llvm/Analysis/ValueTracking.h"
  13. #include "llvm/CodeGen/MachineFrameInfo.h"
  14. #include "llvm/CodeGen/MachineFunctionPass.h"
  15. #include "llvm/CodeGen/MachineInstr.h"
  16. #include "llvm/CodeGen/ScheduleDAG.h"
  17. #include "llvm/CodeGen/TargetRegisterInfo.h"
  18. #include "llvm/Support/CommandLine.h"
  19. using namespace llvm;
  20. static cl::opt<int> DataBankMask("arm-data-bank-mask", cl::init(-1),
  21. cl::Hidden);
  22. static cl::opt<bool> AssumeITCMConflict("arm-assume-itcm-bankconflict",
  23. cl::init(false), cl::Hidden);
  24. static bool hasRAWHazard(MachineInstr *DefMI, MachineInstr *MI,
  25. const TargetRegisterInfo &TRI) {
  26. // FIXME: Detect integer instructions properly.
  27. const MCInstrDesc &MCID = MI->getDesc();
  28. unsigned Domain = MCID.TSFlags & ARMII::DomainMask;
  29. if (MI->mayStore())
  30. return false;
  31. unsigned Opcode = MCID.getOpcode();
  32. if (Opcode == ARM::VMOVRS || Opcode == ARM::VMOVRRD)
  33. return false;
  34. if ((Domain & ARMII::DomainVFP) || (Domain & ARMII::DomainNEON))
  35. return MI->readsRegister(DefMI->getOperand(0).getReg(), &TRI);
  36. return false;
  37. }
  38. ScheduleHazardRecognizer::HazardType
  39. ARMHazardRecognizerFPMLx::getHazardType(SUnit *SU, int Stalls) {
  40. assert(Stalls == 0 && "ARM hazards don't support scoreboard lookahead");
  41. MachineInstr *MI = SU->getInstr();
  42. if (!MI->isDebugInstr()) {
  43. // Look for special VMLA / VMLS hazards. A VMUL / VADD / VSUB following
  44. // a VMLA / VMLS will cause 4 cycle stall.
  45. const MCInstrDesc &MCID = MI->getDesc();
  46. if (LastMI && (MCID.TSFlags & ARMII::DomainMask) != ARMII::DomainGeneral) {
  47. MachineInstr *DefMI = LastMI;
  48. const MCInstrDesc &LastMCID = LastMI->getDesc();
  49. const MachineFunction *MF = MI->getParent()->getParent();
  50. const ARMBaseInstrInfo &TII = *static_cast<const ARMBaseInstrInfo *>(
  51. MF->getSubtarget().getInstrInfo());
  52. // Skip over one non-VFP / NEON instruction.
  53. if (!LastMI->isBarrier() &&
  54. !(TII.getSubtarget().hasMuxedUnits() && 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. if (TII.isFpMLxInstruction(DefMI->getOpcode()) &&
  63. (TII.canCauseFpMLxStall(MI->getOpcode()) ||
  64. hasRAWHazard(DefMI, MI, TII.getRegisterInfo()))) {
  65. // Try to schedule another instruction for the next 4 cycles.
  66. if (FpMLxStalls == 0)
  67. FpMLxStalls = 4;
  68. return Hazard;
  69. }
  70. }
  71. }
  72. return NoHazard;
  73. }
  74. void ARMHazardRecognizerFPMLx::Reset() {
  75. LastMI = nullptr;
  76. FpMLxStalls = 0;
  77. }
  78. void ARMHazardRecognizerFPMLx::EmitInstruction(SUnit *SU) {
  79. MachineInstr *MI = SU->getInstr();
  80. if (!MI->isDebugInstr()) {
  81. LastMI = MI;
  82. FpMLxStalls = 0;
  83. }
  84. }
  85. void ARMHazardRecognizerFPMLx::AdvanceCycle() {
  86. if (FpMLxStalls && --FpMLxStalls == 0)
  87. // Stalled for 4 cycles but still can't schedule any other instructions.
  88. LastMI = nullptr;
  89. }
  90. void ARMHazardRecognizerFPMLx::RecedeCycle() {
  91. llvm_unreachable("reverse ARM hazard checking unsupported");
  92. }
  93. ///////// Bank conflicts handled as hazards //////////////
  94. static bool getBaseOffset(const MachineInstr &MI, const MachineOperand *&BaseOp,
  95. int64_t &Offset) {
  96. uint64_t TSFlags = MI.getDesc().TSFlags;
  97. unsigned AddrMode = (TSFlags & ARMII::AddrModeMask);
  98. unsigned IndexMode =
  99. (TSFlags & ARMII::IndexModeMask) >> ARMII::IndexModeShift;
  100. // Address mode tells us what we want to know about operands for T2
  101. // instructions (but not size). It tells us size (but not about operands)
  102. // for T1 instructions.
  103. switch (AddrMode) {
  104. default:
  105. return false;
  106. case ARMII::AddrModeT2_i8:
  107. // t2LDRBT, t2LDRB_POST, t2LDRB_PRE, t2LDRBi8,
  108. // t2LDRHT, t2LDRH_POST, t2LDRH_PRE, t2LDRHi8,
  109. // t2LDRSBT, t2LDRSB_POST, t2LDRSB_PRE, t2LDRSBi8,
  110. // t2LDRSHT, t2LDRSH_POST, t2LDRSH_PRE, t2LDRSHi8,
  111. // t2LDRT, t2LDR_POST, t2LDR_PRE, t2LDRi8
  112. BaseOp = &MI.getOperand(1);
  113. Offset = (IndexMode == ARMII::IndexModePost)
  114. ? 0
  115. : (IndexMode == ARMII::IndexModePre ||
  116. IndexMode == ARMII::IndexModeUpd)
  117. ? MI.getOperand(3).getImm()
  118. : MI.getOperand(2).getImm();
  119. return true;
  120. case ARMII::AddrModeT2_i12:
  121. // t2LDRBi12, t2LDRHi12
  122. // t2LDRSBi12, t2LDRSHi12
  123. // t2LDRi12
  124. BaseOp = &MI.getOperand(1);
  125. Offset = MI.getOperand(2).getImm();
  126. return true;
  127. case ARMII::AddrModeT2_i8s4:
  128. // t2LDRD_POST, t2LDRD_PRE, t2LDRDi8
  129. BaseOp = &MI.getOperand(2);
  130. Offset = (IndexMode == ARMII::IndexModePost)
  131. ? 0
  132. : (IndexMode == ARMII::IndexModePre ||
  133. IndexMode == ARMII::IndexModeUpd)
  134. ? MI.getOperand(4).getImm()
  135. : MI.getOperand(3).getImm();
  136. return true;
  137. case ARMII::AddrModeT1_1:
  138. // tLDRBi, tLDRBr (watch out!), TLDRSB
  139. case ARMII::AddrModeT1_2:
  140. // tLDRHi, tLDRHr (watch out!), TLDRSH
  141. case ARMII::AddrModeT1_4:
  142. // tLDRi, tLDRr (watch out!)
  143. BaseOp = &MI.getOperand(1);
  144. Offset = MI.getOperand(2).isImm() ? MI.getOperand(2).getImm() : 0;
  145. return MI.getOperand(2).isImm();
  146. }
  147. return false;
  148. }
  149. ARMBankConflictHazardRecognizer::ARMBankConflictHazardRecognizer(
  150. const ScheduleDAG *DAG, int64_t CPUBankMask, bool CPUAssumeITCMConflict)
  151. : MF(DAG->MF), DL(DAG->MF.getDataLayout()),
  152. DataMask(DataBankMask.getNumOccurrences() ? int64_t(DataBankMask)
  153. : CPUBankMask),
  154. AssumeITCMBankConflict(AssumeITCMConflict.getNumOccurrences()
  155. ? AssumeITCMConflict
  156. : CPUAssumeITCMConflict) {
  157. MaxLookAhead = 1;
  158. }
  159. ScheduleHazardRecognizer::HazardType
  160. ARMBankConflictHazardRecognizer::CheckOffsets(unsigned O0, unsigned O1) {
  161. return (((O0 ^ O1) & DataMask) != 0) ? NoHazard : Hazard;
  162. }
  163. ScheduleHazardRecognizer::HazardType
  164. ARMBankConflictHazardRecognizer::getHazardType(SUnit *SU, int Stalls) {
  165. MachineInstr &L0 = *SU->getInstr();
  166. if (!L0.mayLoad() || L0.mayStore() || L0.getNumMemOperands() != 1)
  167. return NoHazard;
  168. auto MO0 = *L0.memoperands().begin();
  169. auto BaseVal0 = MO0->getValue();
  170. auto BasePseudoVal0 = MO0->getPseudoValue();
  171. int64_t Offset0 = 0;
  172. if (MO0->getSize() > 4)
  173. return NoHazard;
  174. bool SPvalid = false;
  175. const MachineOperand *SP = nullptr;
  176. int64_t SPOffset0 = 0;
  177. for (auto L1 : Accesses) {
  178. auto MO1 = *L1->memoperands().begin();
  179. auto BaseVal1 = MO1->getValue();
  180. auto BasePseudoVal1 = MO1->getPseudoValue();
  181. int64_t Offset1 = 0;
  182. // Pointers to the same object
  183. if (BaseVal0 && BaseVal1) {
  184. const Value *Ptr0, *Ptr1;
  185. Ptr0 = GetPointerBaseWithConstantOffset(BaseVal0, Offset0, DL, true);
  186. Ptr1 = GetPointerBaseWithConstantOffset(BaseVal1, Offset1, DL, true);
  187. if (Ptr0 == Ptr1 && Ptr0)
  188. return CheckOffsets(Offset0, Offset1);
  189. }
  190. if (BasePseudoVal0 && BasePseudoVal1 &&
  191. BasePseudoVal0->kind() == BasePseudoVal1->kind() &&
  192. BasePseudoVal0->kind() == PseudoSourceValue::FixedStack) {
  193. // Spills/fills
  194. auto FS0 = cast<FixedStackPseudoSourceValue>(BasePseudoVal0);
  195. auto FS1 = cast<FixedStackPseudoSourceValue>(BasePseudoVal1);
  196. Offset0 = MF.getFrameInfo().getObjectOffset(FS0->getFrameIndex());
  197. Offset1 = MF.getFrameInfo().getObjectOffset(FS1->getFrameIndex());
  198. return CheckOffsets(Offset0, Offset1);
  199. }
  200. // Constant pools (likely in ITCM)
  201. if (BasePseudoVal0 && BasePseudoVal1 &&
  202. BasePseudoVal0->kind() == BasePseudoVal1->kind() &&
  203. BasePseudoVal0->isConstantPool() && AssumeITCMBankConflict)
  204. return Hazard;
  205. // Is this a stack pointer-relative access? We could in general try to
  206. // use "is this the same register and is it unchanged?", but the
  207. // memory operand tracking is highly likely to have already found that.
  208. // What we're after here is bank conflicts between different objects in
  209. // the stack frame.
  210. if (!SPvalid) { // set up SP
  211. if (!getBaseOffset(L0, SP, SPOffset0) || SP->getReg().id() != ARM::SP)
  212. SP = nullptr;
  213. SPvalid = true;
  214. }
  215. if (SP) {
  216. int64_t SPOffset1;
  217. const MachineOperand *SP1;
  218. if (getBaseOffset(*L1, SP1, SPOffset1) && SP1->getReg().id() == ARM::SP)
  219. return CheckOffsets(SPOffset0, SPOffset1);
  220. }
  221. }
  222. return NoHazard;
  223. }
  224. void ARMBankConflictHazardRecognizer::Reset() { Accesses.clear(); }
  225. void ARMBankConflictHazardRecognizer::EmitInstruction(SUnit *SU) {
  226. MachineInstr &MI = *SU->getInstr();
  227. if (!MI.mayLoad() || MI.mayStore() || MI.getNumMemOperands() != 1)
  228. return;
  229. auto MO = *MI.memoperands().begin();
  230. uint64_t Size1 = MO->getSize();
  231. if (Size1 > 4)
  232. return;
  233. Accesses.push_back(&MI);
  234. }
  235. void ARMBankConflictHazardRecognizer::AdvanceCycle() { Accesses.clear(); }
  236. void ARMBankConflictHazardRecognizer::RecedeCycle() { Accesses.clear(); }