AgenPeeps.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "BackEnd.h"
  6. ///----------------------------------------------------------------------------
  7. ///
  8. /// AgenPeeps::PeepFunc
  9. ///
  10. /// Looks for AGEN dependencies between a MOV and another instruction. The heuristic works as follows:
  11. /// - Look for an AGEN dependency. If found, move the first instruction upwards in the BB as far as possible.
  12. /// - For subsequent dependencies (dep. chain), we move the instruction at least 3 slots from the previous instruction.
  13. /// - We assume no dependency between different dep. chains.
  14. /// Example:
  15. /// BB_start
  16. /// ...
  17. /// s2 = MOV [s1 + offset] ; start of dep chain. Move instruction up as far as possible
  18. /// s3 = MOV [s2] ; inside dep chain. Move instruction up at least 3 slots from prev. instruction
  19. /// s4 = MOV [s3 + offset] ; inside dep chain. Move instruction up at least 3 slots from prev. instruction
  20. /// ...
  21. /// s5 = MOV [xxxx] ; new dep chain. Move instruction up as far as possible
  22. /// s6 = MOV [s5 + offset]
  23. ///----------------------------------------------------------------------------
  24. void AgenPeeps::PeepFunc()
  25. {
  26. int distance = 0;
  27. IR::Instr *blockStart, *nextRealInstr;
  28. const uint stall_cycles = 3;
  29. if (AutoSystemInfo::Data.IsAtomPlatform())
  30. {
  31. // On Atom, always optimize unless phase is off
  32. if (PHASE_OFF(Js::AtomPhase, func) || PHASE_OFF(Js::AgenPeepsPhase, func))
  33. return;
  34. }
  35. else
  36. {
  37. // On other platforms, don't optimize unless phase is forced
  38. if (!PHASE_FORCE(Js::AtomPhase, func) && !PHASE_FORCE(Js::AgenPeepsPhase, func))
  39. return;
  40. }
  41. blockStart = nullptr;
  42. FOREACH_INSTR_IN_FUNC_EDITING(instr, instrNext, this->func)
  43. {
  44. if (!instr->IsRealInstr() && !instr->IsLabelInstr())
  45. continue;
  46. // BB boundary ?
  47. if (instr->EndsBasicBlock() || instr->StartsBasicBlock())
  48. {
  49. distance = 0;
  50. instrNext = blockStart = instr->GetNextRealInstr();
  51. continue;
  52. }
  53. nextRealInstr = instr->GetNextRealInstrOrLabel();
  54. // Check for AGEN dependency with the next instruction in the same BB
  55. if (!nextRealInstr->EndsBasicBlock() && !nextRealInstr->StartsBasicBlock() &&
  56. AgenDependentInstrs(instr, nextRealInstr))
  57. {
  58. Assert(blockStart);
  59. // Move instr up
  60. distance = MoveInstrUp(instr, blockStart, distance) - stall_cycles;
  61. } else
  62. distance = 0;
  63. } NEXT_INSTR_IN_FUNC_EDITING;
  64. }
  65. ///----------------------------------------------------------------------------
  66. ///
  67. /// AgenPeeps::MoveInstrUp
  68. ///
  69. /// Moves an instruction up in the BB up to a bound or until it hits
  70. /// a dependent instruction. If bound <= 0, move as far as possible.
  71. ///----------------------------------------------------------------------------
  72. int AgenPeeps::MoveInstrUp(IR::Instr *instrToMove, IR::Instr *blockStart, int bound)
  73. {
  74. AssertMsg(LowererMD::IsAssign(instrToMove), "We only reschedule move instructions for now");
  75. IR::Instr *instr;
  76. int i = 1;
  77. if (instrToMove == blockStart || DependentInstrs(instrToMove, instrToMove->GetPrevRealInstr()))
  78. return 0;
  79. instr = instrToMove->GetPrevRealInstr();
  80. instrToMove->Unlink();
  81. while (!DependentInstrs(instrToMove, instr))
  82. {
  83. if (instr == blockStart || (bound > 0 && i == bound))
  84. {
  85. instr->InsertBefore(instrToMove);
  86. return i;
  87. }
  88. instr = instr->GetPrevRealInstr();
  89. i++;
  90. }
  91. // Insert after dependent instruction
  92. instr->InsertAfter(instrToMove);
  93. return i - 1;
  94. }
  95. ///----------------------------------------------------------------------------
  96. ///
  97. /// AgenPeeps::AgenDependentInstr
  98. ///
  99. /// Determines if two instructions are Agen dependent
  100. ///
  101. ///----------------------------------------------------------------------------
  102. bool AgenPeeps::AgenDependentInstrs(IR::Instr *instr1, IR::Instr *instr2)
  103. {
  104. // We only deal with assign instructions for now.
  105. if (!LowererMD::IsAssign(instr1) || !DependentInstrs(instr1, instr2))
  106. return false;
  107. if (instr1->GetDst()->IsRegOpnd())
  108. {
  109. IR::IndirOpnd *src1 = (instr2->GetSrc1() && instr2->GetSrc1()->IsIndirOpnd()) ? instr2->GetSrc1()->AsIndirOpnd() : nullptr;
  110. IR::IndirOpnd *src2 = (instr2->GetSrc2() && instr2->GetSrc2()->IsIndirOpnd()) ? instr2->GetSrc2()->AsIndirOpnd() : nullptr;
  111. IR::IndirOpnd *dst = (instr2->GetDst() && instr2->GetDst()->IsIndirOpnd()) ? instr2->GetDst()->AsIndirOpnd() : nullptr;
  112. IR::RegOpnd *regOpnd = instr1->GetDst()->AsRegOpnd();
  113. IR::RegOpnd *base, *index;
  114. if (src1)
  115. {
  116. base = src1->GetBaseOpnd();
  117. index = src1->GetIndexOpnd();
  118. return (base && regOpnd->IsSameRegUntyped(base)) || (index && regOpnd->IsSameRegUntyped(index));
  119. }
  120. if (src2)
  121. {
  122. base = src2->GetBaseOpnd();
  123. index = src2->GetIndexOpnd();
  124. return (base && regOpnd->IsSameRegUntyped(base)) || (index && regOpnd->IsSameRegUntyped(index));
  125. }
  126. if (dst)
  127. {
  128. base = dst->GetBaseOpnd();
  129. index = dst->GetIndexOpnd();
  130. return (base && regOpnd->IsSameRegUntyped(base)) || (index && regOpnd->IsSameRegUntyped(index));
  131. }
  132. }
  133. return false;
  134. }
  135. ///----------------------------------------------------------------------------
  136. ///
  137. /// AgenPeeps::DependentInstr
  138. ///
  139. /// Determines if two instructions are dependent
  140. ///
  141. ///----------------------------------------------------------------------------
  142. bool AgenPeeps::DependentInstrs(IR::Instr *instr1, IR::Instr *instr2)
  143. {
  144. if (AlwaysDependent(instr1) || AlwaysDependent(instr2))
  145. return true;
  146. // Check for RAW, WAR and WAW dependence
  147. return \
  148. DependentOpnds(instr1->GetSrc1(), instr2->GetDst()) ||
  149. DependentOpnds(instr1->GetSrc2(), instr2->GetDst()) ||
  150. DependentOpnds(instr1->GetDst(), instr2->GetDst()) ||
  151. DependentOpnds(instr2->GetSrc1(), instr1->GetDst()) ||
  152. DependentOpnds(instr2->GetSrc2(), instr1->GetDst()) ||
  153. (instr1->m_opcode == Js::OpCode::XCHG && // XCHG's src2 is also a dst
  154. (DependentOpnds(instr2->GetSrc1(), instr1->GetSrc2()) ||
  155. DependentOpnds(instr2->GetSrc2(), instr1->GetSrc2()))) ||
  156. (instr2->m_opcode == Js::OpCode::XCHG && // XCHG's src2 is also a dst
  157. (DependentOpnds(instr1->GetSrc1(), instr2->GetSrc2()) ||
  158. DependentOpnds(instr1->GetSrc2(), instr2->GetSrc2())));
  159. }
  160. // Being conservative here about instructions that implicitly reads/writes memory/regs without explicit Opnds
  161. bool AgenPeeps::AlwaysDependent(IR::Instr *instr)
  162. {
  163. return LowererMD::IsCall(instr) ||
  164. instr->m_opcode == Js::OpCode::PUSH ||
  165. instr->m_opcode == Js::OpCode::POP ||
  166. instr->m_opcode == Js::OpCode::DIV ||
  167. instr->m_opcode == Js::OpCode::IDIV ||
  168. instr->m_opcode == Js::OpCode::IMUL;
  169. }
  170. ///----------------------------------------------------------------------------
  171. ///
  172. /// AgenPeeps::DependentOpnd
  173. ///
  174. /// Determines if two operands are dependent. This function is commutative.
  175. ///
  176. ///----------------------------------------------------------------------------
  177. bool AgenPeeps::DependentOpnds(IR::Opnd *opnd1, IR::Opnd *opnd2)
  178. {
  179. #if defined (_M_IX86)
  180. const RegNum baseReg = RegEBP;
  181. #elif defined (_M_X64)
  182. const RegNum baseReg = RegRBP;
  183. #else
  184. AssertMsg(false, "Optimization not supported for ARM");
  185. #endif
  186. if (!opnd1 || !opnd2)
  187. return false;
  188. // Memory dependence
  189. if (IsMemoryOpnd(opnd1) && IsMemoryOpnd(opnd2))
  190. {
  191. IR::SymOpnd *symOpnd1 = opnd1->IsSymOpnd() ? opnd1->AsSymOpnd() : nullptr;
  192. IR::SymOpnd *symOpnd2 = opnd2->IsSymOpnd() ? opnd2->AsSymOpnd() : nullptr;
  193. if (symOpnd1 || symOpnd2)
  194. {
  195. // SymOpnd do not alias with MemRefOpnd/IndirOpnd
  196. if (opnd1->IsMemRefOpnd() || opnd2->IsMemRefOpnd() || opnd1->IsIndirOpnd() || opnd2->IsIndirOpnd())
  197. return false;
  198. // Two symOpnds are dependent if they point to the same stack symbol
  199. if (symOpnd1 && symOpnd2 &&
  200. symOpnd1->m_sym->IsStackSym() && symOpnd2->m_sym->IsStackSym() )
  201. {
  202. return symOpnd1->m_sym->AsStackSym()->m_offset == symOpnd2->m_sym->AsStackSym()->m_offset;
  203. }
  204. }
  205. // all other memory operands are dependent
  206. return true;
  207. }
  208. IR::RegOpnd *regOpnd, *base, *index;
  209. // Register dependences
  210. if (opnd1->IsRegOpnd())
  211. {
  212. regOpnd = opnd1->AsRegOpnd();
  213. // reg-to-reg
  214. if (opnd2->IsRegOpnd() && regOpnd->IsSameRegUntyped(opnd2->AsRegOpnd()))
  215. return true;
  216. // opnd2 = [base + indx + offset] and (opnd1 = base or opnd1 = indx)
  217. if (opnd2->IsIndirOpnd())
  218. {
  219. base = opnd2->AsIndirOpnd()->GetBaseOpnd();
  220. index = opnd2->AsIndirOpnd()->GetIndexOpnd();
  221. if ( (base && regOpnd->IsSameRegUntyped(base)) || (index && regOpnd->IsSameRegUntyped(index)) )
  222. return true;
  223. }
  224. // opnd1 = ebp/rbp and opnd2 = [ebp/rbp + offset]
  225. if (opnd2->IsSymOpnd() && opnd2->AsSymOpnd()->m_sym->IsStackSym() && regOpnd->GetReg() == baseReg)
  226. return true;
  227. }
  228. if (opnd2->IsRegOpnd())
  229. {
  230. regOpnd = opnd2->AsRegOpnd();
  231. // opnd1 = [base + indx + offset] and (opnd2 = base or opnd2 = indx)
  232. if (opnd1->IsIndirOpnd())
  233. {
  234. base = opnd1->AsIndirOpnd()->GetBaseOpnd();
  235. index = opnd1->AsIndirOpnd()->GetIndexOpnd();
  236. if ( (base && regOpnd->IsSameRegUntyped(base)) || (index && regOpnd->IsSameRegUntyped(index)) )
  237. return true;
  238. }
  239. // opnd2 = ebp/rbp and opnd1 = [ebp/rbp + offset]
  240. if (opnd1->IsSymOpnd() && opnd1->AsSymOpnd()->m_sym->IsStackSym() && regOpnd->GetReg() == baseReg)
  241. return true;
  242. }
  243. return false;
  244. }
  245. bool AgenPeeps::IsMemoryOpnd(IR::Opnd *opnd)
  246. {
  247. return opnd->IsSymOpnd() || opnd->IsIndirOpnd() || opnd->IsMemRefOpnd();
  248. }