BackwardPass.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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. class BackwardPass
  6. {
  7. template <typename T>
  8. friend class TempTracker;
  9. friend class NumberTemp;
  10. friend class ObjectTemp;
  11. #if DBG
  12. friend class ObjectTempVerify;
  13. #endif
  14. public:
  15. BackwardPass(Func * func, GlobOpt * globOpt, Js::Phase tag);
  16. void Optimize();
  17. static bool DoDeadStore(Func* func, StackSym* sym);
  18. private:
  19. void CleanupBackwardPassInfoInFlowGraph();
  20. void OptBlock(BasicBlock * block);
  21. void MergeSuccBlocksInfo(BasicBlock * block);
  22. void ProcessLoopCollectionPass(BasicBlock *const lastBlock);
  23. void ProcessLoop(BasicBlock * lastBlock);
  24. void ProcessBlock(BasicBlock * block);
  25. bool IsFormalParamSym(Func * func, Sym * sym) const;
  26. bool CanDeadStoreInstrForScopeObjRemoval(Sym *sym = nullptr) const;
  27. void TraceDeadStoreOfInstrsForScopeObjectRemoval();
  28. IR::Instr * TryChangeInstrForStackArgOpt();
  29. void InsertArgInsForFormals();
  30. void ProcessBailOnStackArgsOutOfActualsRange();
  31. void MarkScopeObjSymUseForStackArgOpt();
  32. bool DeadStoreOrChangeInstrForScopeObjRemoval(IR::Instr ** pInstrPrev);
  33. void ProcessUse(IR::Opnd * opnd);
  34. bool ProcessDef(IR::Opnd * opnd);
  35. void ProcessTransfers(IR::Instr * instr);
  36. void ProcessFieldKills(IR::Instr * instr);
  37. template<typename T> void ClearBucketsOnFieldKill(IR::Instr *instr, HashTable<T> *table);
  38. void ProcessFieldHoistKills(IR::Instr * instr);
  39. bool ProcessBailOutInfo(IR::Instr * instr);
  40. void ProcessBailOutInfo(IR::Instr * instr, BailOutInfo * bailOutInfo);
  41. void ProcessPendingPreOpBailOutInfo(IR::Instr *const currentInstr);
  42. void ProcessBailOutArgObj(BailOutInfo * bailOutInfo, BVSparse<JitArenaAllocator> * byteCodeUpwardExposedUsed);
  43. void ProcessBailOutConstants(BailOutInfo * bailOutInfo, BVSparse<JitArenaAllocator> * byteCodeUpwardExposedUsed, BVSparse<JitArenaAllocator>* argSymsBv);
  44. void ProcessBailOutCopyProps(BailOutInfo * bailOutInfo, BVSparse<JitArenaAllocator> * byteCodeUpwardExposedUsed, BVSparse<JitArenaAllocator>* argSymsBv);
  45. bool ProcessStackSymUse(StackSym * sym, BOOLEAN isNonByteCodeUse);
  46. bool ProcessSymUse(Sym * sym, bool isRegOpndUse, BOOLEAN isNonByteCodeUse);
  47. bool MayPropertyBeWrittenTo(Js::PropertyId propertyId);
  48. void ProcessPropertySymOpndUse(IR::PropertySymOpnd *opnd);
  49. bool ProcessPropertySymUse(PropertySym *propertySym);
  50. void ProcessNewScObject(IR::Instr* instr);
  51. void MarkTemp(StackSym * sym);
  52. bool ProcessInlineeStart(IR::Instr* instr);
  53. void ProcessInlineeEnd(IR::Instr* instr);
  54. void MarkTempProcessInstr(IR::Instr * instr);
  55. void RemoveEmptyLoopAfterMemOp(Loop *loop);
  56. void RemoveEmptyLoops();
  57. bool IsEmptyLoopAfterMemOp(Loop *loop);
  58. void RestoreInductionVariableValuesAfterMemOp(Loop *loop);
  59. bool DoDeadStoreLdStForMemop(IR::Instr *instr);
  60. bool DeadStoreInstr(IR::Instr *instr);
  61. void CollectCloneStrCandidate(IR::Opnd *opnd);
  62. void InvalidateCloneStrCandidate(IR::Opnd *opnd);
  63. #if DBG_DUMP
  64. void DumpBlockData(BasicBlock * block);
  65. void DumpMarkTemp();
  66. #endif
  67. static bool UpdateImplicitCallBailOutKind(IR::Instr *const instr, bool needsBailOutOnImplicitCall);
  68. bool ProcessNoImplicitCallUses(IR::Instr *const instr);
  69. void ProcessNoImplicitCallDef(IR::Instr *const instr);
  70. template<class F> IR::Opnd *FindNoImplicitCallUse(IR::Instr *const instr, StackSym *const sym, const F IsCheckedUse, IR::Instr * *const noImplicitCallUsesInstrRef = nullptr);
  71. template<class F> IR::Opnd *FindNoImplicitCallUse(IR::Instr *const instr, IR::Opnd *const opnd, const F IsCheckedUse, IR::Instr * *const noImplicitCallUsesInstrRef = nullptr);
  72. void ProcessArrayRegOpndUse(IR::Instr *const instr, IR::ArrayRegOpnd *const arrayRegOpnd);
  73. void UpdateArrayValueTypes(IR::Instr *const instr, IR::Opnd *opnd);
  74. void UpdateArrayBailOutKind(IR::Instr *const instr);
  75. void TrackBitWiseOrNumberOp(IR::Instr *const instr);
  76. void SetSymIsNotUsedOnlyInBitOps(IR::Opnd *const opnd);
  77. void SetSymIsUsedOnlyInBitOpsIfLastUse(IR::Opnd *const opnd);
  78. void SetSymIsNotUsedOnlyInNumber(IR::Opnd *const opnd);
  79. void SetSymIsUsedOnlyInNumberIfLastUse(IR::Opnd *const opnd);
  80. void TrackIntUsage(IR::Instr *const instr);
  81. void RemoveNegativeZeroBailout(IR::Instr* instr);
  82. void SetNegativeZeroDoesNotMatterIfLastUse(IR::Opnd *const opnd);
  83. void SetNegativeZeroMatters(IR::Opnd *const opnd);
  84. void SetCouldRemoveNegZeroBailoutForDefIfLastUse(IR::Opnd *const opnd);
  85. void SetIntOverflowDoesNotMatterIfLastUse(IR::Opnd *const opnd);
  86. void SetIntOverflowMatters(IR::Opnd *const opnd);
  87. bool SetIntOverflowDoesNotMatterInRangeIfLastUse(IR::Opnd *const opnd, const int addSubUses);
  88. bool SetIntOverflowDoesNotMatterInRangeIfLastUse(StackSym *const stackSym, const int addSubUses);
  89. void SetIntOverflowMattersInRange(IR::Opnd *const opnd);
  90. void TransferCompoundedAddSubUsesToSrcs(IR::Instr *const instr, const int addSubUses);
  91. void EndIntOverflowDoesNotMatterRange();
  92. void TrackFloatSymEquivalence(IR::Instr *const instr);
  93. void DeadStoreImplicitCallBailOut(IR::Instr * instr, bool hasLiveFields);
  94. void DeadStoreTypeCheckBailOut(IR::Instr * instr);
  95. bool IsImplicitCallBailOutCurrentlyNeeded(IR::Instr * instr, bool mayNeedImplicitCallBailOut, bool hasLiveFields);
  96. bool TrackNoImplicitCallInlinees(IR::Instr *instr);
  97. bool ProcessBailOnNoProfile(IR::Instr *instr, BasicBlock *block);
  98. bool DoByteCodeUpwardExposedUsed() const;
  99. void DoSetDead(IR::Opnd * opnd, bool isDead) const;
  100. bool DoFieldHoistCandidates() const;
  101. bool DoFieldHoistCandidates(Loop * loop) const;
  102. bool DoMarkTempObjects() const;
  103. bool DoMarkTempNumbers() const;
  104. bool DoMarkTempNumbersOnTempObjects() const;
  105. #if DBG
  106. bool DoMarkTempObjectVerify() const;
  107. #endif
  108. static bool DoDeadStore(Func* func);
  109. bool DoDeadStore() const;
  110. bool DoDeadStoreSlots() const;
  111. bool DoTrackNegativeZero() const;
  112. bool DoTrackBitOpsOrNumber()const;
  113. bool DoTrackIntOverflow() const;
  114. bool DoTrackCompoundedIntOverflow() const;
  115. bool DoTrackNon32BitOverflow() const;
  116. #if DBG_DUMP
  117. bool IsTraceEnabled() const;
  118. #endif
  119. bool IsCollectionPass() const { return isCollectionPass; }
  120. bool IsPrePass() const { return this->currentPrePassLoop != nullptr; }
  121. void DeleteBlockData(BasicBlock * block);
  122. void TrackObjTypeSpecProperties(IR::PropertySymOpnd *opnd, BasicBlock *block);
  123. void TrackObjTypeSpecWriteGuards(IR::PropertySymOpnd *opnd, BasicBlock *block);
  124. void TrackAddPropertyTypes(IR::PropertySymOpnd *opnd, BasicBlock *block);
  125. void InsertTypeTransition(IR::Instr *instrInsertBefore, int symId, AddPropertyCacheBucket *data);
  126. void InsertTypeTransition(IR::Instr *instrInsertBefore, StackSym *objSym, AddPropertyCacheBucket *data);
  127. void InsertTypeTransitionAtBlock(BasicBlock *block, int symId, AddPropertyCacheBucket *data);
  128. void InsertTypeTransitionsAtPriorSuccessors(BasicBlock *block, BasicBlock *blockSucc, int symId, AddPropertyCacheBucket *data);
  129. void InsertTypeTransitionAfterInstr(IR::Instr *instr, int symId, AddPropertyCacheBucket *data);
  130. void InsertTypeTransitionsAtPotentialKills();
  131. bool TransitionUndoesObjectHeaderInlining(AddPropertyCacheBucket *data) const;
  132. template<class Fn> void ForEachAddPropertyCacheBucket(Fn fn);
  133. static ObjTypeGuardBucket MergeGuardedProperties(ObjTypeGuardBucket bucket1, ObjTypeGuardBucket bucket2);
  134. static ObjWriteGuardBucket MergeWriteGuards(ObjWriteGuardBucket bucket1, ObjWriteGuardBucket bucket2);
  135. bool ReverseCopyProp(IR::Instr *instr);
  136. bool FoldCmBool(IR::Instr *instr);
  137. void SetWriteThroughSymbolsSetForRegion(BasicBlock * catchBlock, Region * tryRegion);
  138. bool CheckWriteThroughSymInRegion(Region * region, StackSym * sym);
  139. private:
  140. // Javascript number values (64-bit floats) have 53 bits excluding the sign bit to precisely represent integers. If we have
  141. // compounded uses in add/sub, such as:
  142. // s1 = s0 + s0
  143. // s2 = s1 + s1
  144. // s3 = s2 + s2
  145. // ...
  146. // And s0 has a 32-bit (signed or unsigned) int value, then we can do 53 - 32 such add/sub operations and guarantee that the
  147. // final result does not overflow the 53 bits. So long as that is the case, and the final result is only used in operations
  148. // that convert their srcs to int32s (such as bitwise operations), then overflow checks can be omitted on these adds/subs.
  149. // Once the result overflows 53 bits, the semantics of converting that imprecisely represented float value to int32 changes
  150. // and is no longer equivalent to a simple truncate of the precise int value.
  151. static const int MaxCompoundedUsesInAddSubForIgnoringIntOverflow = 53 - 32;
  152. Func * const func;
  153. GlobOpt * globOpt;
  154. JitArenaAllocator * tempAlloc;
  155. Js::Phase tag;
  156. Loop * currentPrePassLoop;
  157. BasicBlock * currentBlock;
  158. Region * currentRegion;
  159. IR::Instr * currentInstr;
  160. IR::Instr * preOpBailOutInstrToProcess;
  161. BVSparse<JitArenaAllocator> * negativeZeroDoesNotMatterBySymId;
  162. BVSparse<JitArenaAllocator> * symUsedOnlyForBitOpsBySymId;
  163. BVSparse<JitArenaAllocator> * symUsedOnlyForNumberBySymId;
  164. BVSparse<JitArenaAllocator> * intOverflowDoesNotMatterBySymId;
  165. BVSparse<JitArenaAllocator> * intOverflowDoesNotMatterInRangeBySymId;
  166. BVSparse<JitArenaAllocator> * candidateSymsRequiredToBeInt;
  167. BVSparse<JitArenaAllocator> * candidateSymsRequiredToBeLossyInt;
  168. StackSym *considerSymAsRealUseInNoImplicitCallUses;
  169. bool intOverflowCurrentlyMattersInRange;
  170. bool isCollectionPass;
  171. class FloatSymEquivalenceClass
  172. {
  173. private:
  174. BVSparse<JitArenaAllocator> bv;
  175. bool requiresBailOnNotNumber;
  176. public:
  177. FloatSymEquivalenceClass(JitArenaAllocator *const allocator) : bv(allocator), requiresBailOnNotNumber(false)
  178. {
  179. }
  180. BVSparse<JitArenaAllocator> *Bv()
  181. {
  182. return &bv;
  183. }
  184. bool RequiresBailOnNotNumber() const
  185. {
  186. return requiresBailOnNotNumber;
  187. }
  188. void Set(const StackSym *const sym)
  189. {
  190. bv.Set(sym->m_id);
  191. if(sym->m_requiresBailOnNotNumber)
  192. {
  193. requiresBailOnNotNumber = true;
  194. }
  195. }
  196. void Or(const FloatSymEquivalenceClass *const other)
  197. {
  198. bv.Or(&other->bv);
  199. if(other->requiresBailOnNotNumber)
  200. {
  201. requiresBailOnNotNumber = true;
  202. }
  203. }
  204. };
  205. typedef JsUtil::BaseDictionary<SymID, FloatSymEquivalenceClass *, JitArenaAllocator> FloatSymEquivalenceMap;
  206. FloatSymEquivalenceMap *floatSymEquivalenceMap;
  207. // Use by numberTemp to keep track of the property sym that is used to represent a property, since we don't trace aliasing
  208. typedef JsUtil::BaseDictionary<Js::PropertyId, SymID, JitArenaAllocator> NumberTempRepresentativePropertySymMap;
  209. NumberTempRepresentativePropertySymMap * numberTempRepresentativePropertySym;
  210. #if DBG_DUMP
  211. uint32 numDeadStore;
  212. uint32 numMarkTempNumber;
  213. uint32 numMarkTempNumberTransferred;
  214. uint32 numMarkTempObject;
  215. #endif
  216. uint32 implicitCallBailouts;
  217. uint32 fieldOpts;
  218. };