BackwardPass.h 11 KB

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