BackwardPass.h 13 KB

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