GlobOptBlockData.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. class ExprAttributes
  7. {
  8. protected:
  9. uint32 attributes;
  10. public:
  11. ExprAttributes(const uint32 attributes = 0) : attributes(attributes)
  12. {
  13. }
  14. uint32 Attributes() const
  15. {
  16. return attributes;
  17. }
  18. private:
  19. static const uint32 BitMask(const uint index)
  20. {
  21. return 1u << index;
  22. }
  23. protected:
  24. void SetBitAttribute(const uint index, const bool bit)
  25. {
  26. if(bit)
  27. {
  28. attributes |= BitMask(index);
  29. }
  30. else
  31. {
  32. attributes &= ~BitMask(index);
  33. }
  34. }
  35. };
  36. class ExprHash
  37. {
  38. public:
  39. ExprHash() { this->opcode = 0; }
  40. ExprHash(int init) { Assert(init == 0); this->opcode = 0; }
  41. void Init(Js::OpCode opcode, ValueNumber src1Val, ValueNumber src2Val, ExprAttributes exprAttributes)
  42. {
  43. extern uint8 OpCodeToHash[(int)Js::OpCode::Count];
  44. uint32 opCodeHash = OpCodeToHash[(int)opcode];
  45. this->opcode = opCodeHash;
  46. this->src1Val = src1Val;
  47. this->src2Val = src2Val;
  48. this->attributes = exprAttributes.Attributes();
  49. // Assert too many opcodes...
  50. AssertMsg(this->opcode == (uint32)opCodeHash, "Opcode value too large for CSEs");
  51. AssertMsg(this->attributes == exprAttributes.Attributes(), "Not enough bits for expr attributes");
  52. // If value numbers are too large, just give up
  53. if (this->src1Val != src1Val || this->src2Val != src2Val)
  54. {
  55. this->opcode = 0;
  56. this->src1Val = 0;
  57. this->src2Val = 0;
  58. this->attributes = 0;
  59. }
  60. }
  61. Js::OpCode GetOpcode() { return (Js::OpCode)this->opcode; }
  62. ValueNumber GetSrc1ValueNumber() { return this->src1Val; }
  63. ValueNumber GetSrc2ValueNumber() { return this->src2Val; }
  64. ExprAttributes GetExprAttributes() { return this->attributes; }
  65. bool IsValid() { return this->opcode != 0; }
  66. operator uint() { return *(uint*)this; }
  67. private:
  68. uint32 opcode: 8;
  69. uint32 src1Val: 11;
  70. uint32 src2Val: 11;
  71. uint32 attributes: 2;
  72. };
  73. #include "GlobHashTable.h"
  74. typedef ValueHashTable<Sym *, Value *> GlobHashTable;
  75. typedef HashBucket<Sym *, Value *> GlobHashBucket;
  76. typedef ValueHashTable<ExprHash, Value *> ExprHashTable;
  77. typedef HashBucket<ExprHash, Value *> ExprHashBucket;
  78. typedef JsUtil::BaseHashSet<Value *, JitArenaAllocator> ValueSet;
  79. struct StackLiteralInitFldData
  80. {
  81. const Js::PropertyIdArray * propIds;
  82. uint currentInitFldCount;
  83. };
  84. typedef JsUtil::BaseDictionary<StackSym *, StackLiteralInitFldData, JitArenaAllocator> StackLiteralInitFldDataMap;
  85. typedef SList<GlobHashBucket*, JitArenaAllocator> PRECandidatesList;
  86. class GlobOptBlockData
  87. {
  88. friend class BasicBlock;
  89. public:
  90. GlobOptBlockData(Func *func) :
  91. symToValueMap(nullptr),
  92. exprToValueMap(nullptr),
  93. liveFields(nullptr),
  94. liveArrayValues(nullptr),
  95. maybeWrittenTypeSyms(nullptr),
  96. liveVarSyms(nullptr),
  97. liveInt32Syms(nullptr),
  98. liveLossyInt32Syms(nullptr),
  99. liveFloat64Syms(nullptr),
  100. #ifdef ENABLE_SIMDJS
  101. liveSimd128F4Syms(nullptr),
  102. liveSimd128I4Syms(nullptr),
  103. #endif
  104. hoistableFields(nullptr),
  105. argObjSyms(nullptr),
  106. maybeTempObjectSyms(nullptr),
  107. canStoreTempObjectSyms(nullptr),
  108. valuesToKillOnCalls(nullptr),
  109. inductionVariables(nullptr),
  110. availableIntBoundChecks(nullptr),
  111. startCallCount(0),
  112. argOutCount(0),
  113. totalOutParamCount(0),
  114. callSequence(nullptr),
  115. capturedValuesCandidate(nullptr),
  116. capturedValues(nullptr),
  117. changedSyms(nullptr),
  118. hasCSECandidates(false),
  119. curFunc(func),
  120. hasDataRef(nullptr),
  121. stackLiteralInitFldDataMap(nullptr),
  122. globOpt(nullptr)
  123. {
  124. }
  125. // Data
  126. GlobHashTable * symToValueMap;
  127. ExprHashTable * exprToValueMap;
  128. BVSparse<JitArenaAllocator> * liveFields;
  129. BVSparse<JitArenaAllocator> * liveArrayValues;
  130. BVSparse<JitArenaAllocator> * maybeWrittenTypeSyms;
  131. BVSparse<JitArenaAllocator> * isTempSrc;
  132. BVSparse<JitArenaAllocator> * liveVarSyms;
  133. BVSparse<JitArenaAllocator> * liveInt32Syms;
  134. // 'liveLossyInt32Syms' includes only syms that contain an int value that may not fully represent the value of the
  135. // equivalent var sym. The set (liveInt32Syms - liveLossyInt32Syms) includes only syms that contain an int value that fully
  136. // represents the value of the equivalent var sym, such as when (a + 1) is type-specialized. Among other things, this
  137. // bit-vector is used, based on the type of conversion that is needed, to determine whether conversion is necessary, and if
  138. // so, whether a bailout is needed. For instance, after type-specializing (a | 0), the int32 sym of 'a' cannot be reused in
  139. // (a + 1) during type-specialization. It needs to be converted again using a lossless conversion with a bailout.
  140. // Conversely, a lossless int32 sym can be reused to avoid a lossy conversion.
  141. BVSparse<JitArenaAllocator> * liveLossyInt32Syms;
  142. BVSparse<JitArenaAllocator> * liveFloat64Syms;
  143. #ifdef ENABLE_SIMDJS
  144. // SIMD_JS
  145. BVSparse<JitArenaAllocator> * liveSimd128F4Syms;
  146. BVSparse<JitArenaAllocator> * liveSimd128I4Syms;
  147. #endif
  148. BVSparse<JitArenaAllocator> * hoistableFields;
  149. BVSparse<JitArenaAllocator> * argObjSyms;
  150. BVSparse<JitArenaAllocator> * maybeTempObjectSyms;
  151. BVSparse<JitArenaAllocator> * canStoreTempObjectSyms;
  152. // This is the func that this block comes from, so the inlinee if from an inlined function
  153. Func * curFunc;
  154. // 'valuesToKillOnCalls' includes values whose value types need to be killed upon a call. Upon a call, the value types of
  155. // values in the set are updated and removed from the set as appropriate.
  156. ValueSet * valuesToKillOnCalls;
  157. InductionVariableSet * inductionVariables;
  158. IntBoundCheckSet * availableIntBoundChecks;
  159. // Bailout data
  160. uint startCallCount;
  161. uint argOutCount;
  162. uint totalOutParamCount;
  163. SListBase<IR::Opnd *> * callSequence;
  164. StackLiteralInitFldDataMap * stackLiteralInitFldDataMap;
  165. CapturedValues * capturedValuesCandidate;
  166. CapturedValues * capturedValues;
  167. BVSparse<JitArenaAllocator> * changedSyms;
  168. uint inlinedArgOutCount;
  169. bool hasCSECandidates;
  170. private:
  171. bool * hasDataRef;
  172. GlobOpt * globOpt;
  173. public:
  174. void OnDataInitialized(JitArenaAllocator *const allocator)
  175. {
  176. Assert(allocator);
  177. hasDataRef = JitAnew(allocator, bool, true);
  178. }
  179. void OnDataReused(GlobOptBlockData *const fromData)
  180. {
  181. // If a block's data is deleted, *hasDataRef will be set to false. Since these two blocks are pointing to the same data,
  182. // they also need to point to the same has-data info.
  183. hasDataRef = fromData->hasDataRef;
  184. }
  185. void OnDataUnreferenced()
  186. {
  187. // Other blocks may still be using the data, we should only un-reference the previous data
  188. hasDataRef = nullptr;
  189. }
  190. void OnDataDeleted()
  191. {
  192. if (hasDataRef)
  193. *hasDataRef = false;
  194. OnDataUnreferenced();
  195. }
  196. bool HasData()
  197. {
  198. if (!hasDataRef)
  199. return false;
  200. if (*hasDataRef)
  201. return true;
  202. OnDataUnreferenced();
  203. return false;
  204. }
  205. #ifdef ENABLE_SIMDJS
  206. // SIMD_JS
  207. BVSparse<JitArenaAllocator> * GetSimd128LivenessBV(IRType type)
  208. {
  209. switch (type)
  210. {
  211. case TySimd128F4:
  212. return liveSimd128F4Syms;
  213. case TySimd128I4:
  214. return liveSimd128I4Syms;
  215. default:
  216. Assert(UNREACHED);
  217. return nullptr;
  218. }
  219. }
  220. #endif
  221. // Functions pulled out of GlobOpt.cpp
  222. // Initialization/copying/moving
  223. public:
  224. void NullOutBlockData(GlobOpt* globOpt, Func* func);
  225. void InitBlockData(GlobOpt* globOpt, Func* func);
  226. void ReuseBlockData(GlobOptBlockData *fromData);
  227. void CopyBlockData(GlobOptBlockData *fromData);
  228. void DeleteBlockData();
  229. void CloneBlockData(BasicBlock *const toBlock, BasicBlock *const fromBlock);
  230. public:
  231. void RemoveUnavailableCandidates(PRECandidatesList *candidates);
  232. // Merging functions
  233. public:
  234. void MergeBlockData(BasicBlock *toBlockContext, BasicBlock *fromBlock, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge, bool forceTypeSpecOnLoopHeader);
  235. private:
  236. template <typename CaptureList, typename CapturedItemsAreEqual>
  237. void MergeCapturedValues(SListBase<CaptureList>* toList, SListBase<CaptureList> * fromList, CapturedItemsAreEqual itemsAreEqual);
  238. void MergeValueMaps(BasicBlock *toBlock, BasicBlock *fromBlock, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge);
  239. Value * MergeValues(Value *toDataValue, Value *fromDataValue, Sym *fromDataSym, bool isLoopBackEdge, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge);
  240. ValueInfo * MergeValueInfo(Value *toDataVal, Value *fromDataVal, Sym *fromDataSym, bool isLoopBackEdge, bool sameValueNumber, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge);
  241. JsTypeValueInfo * MergeJsTypeValueInfo(JsTypeValueInfo * toValueInfo, JsTypeValueInfo * fromValueInfo, bool isLoopBackEdge, bool sameValueNumber);
  242. ValueInfo * MergeArrayValueInfo(const ValueType mergedValueType, const ArrayValueInfo *const toDataValueInfo, const ArrayValueInfo *const fromDataValueInfo, Sym *const arraySym, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge);
  243. // Argument Tracking
  244. public:
  245. void TrackArgumentsSym(IR::RegOpnd const* opnd);
  246. void ClearArgumentsSym(IR::RegOpnd const* opnd);
  247. BOOL TestAnyArgumentsSym() const;
  248. BOOL IsArgumentsSymID(SymID id) const;
  249. BOOL IsArgumentsOpnd(IR::Opnd const* opnd) const;
  250. private:
  251. // Value Tracking
  252. public:
  253. Value * FindValue(Sym *sym);
  254. Value * FindValueFromMapDirect(SymID symId);
  255. Value * FindPropertyValue(SymID symId);
  256. Value * FindObjectTypeValue(StackSym* typeSym);
  257. Value * FindObjectTypeValue(SymID typeSymId);
  258. Value * FindObjectTypeValueNoLivenessCheck(StackSym* typeSym);
  259. Value * FindObjectTypeValueNoLivenessCheck(SymID typeSymId);
  260. Value * FindFuturePropertyValue(PropertySym *const propertySym);
  261. StackSym * GetCopyPropSym(Sym * sym, Value * val);
  262. Value * InsertNewValue(Value *val, IR::Opnd *opnd);
  263. Value * SetValue(Value *val, IR::Opnd *opnd);
  264. void SetValue(Value *val, Sym * sym);
  265. void ClearSymValue(Sym *sym);
  266. private:
  267. void SetValueToHashTable(GlobHashTable * valueNumberMap, Value *val, Sym *sym);
  268. // Temp Tracking
  269. public:
  270. void MarkTempLastUse(IR::Instr *instr, IR::RegOpnd *regOpnd);
  271. private:
  272. // Liveness Tracking
  273. public:
  274. void MakeLive(StackSym *sym, const bool lossy);
  275. // Checks if the symbol is live in this block under any type
  276. bool IsLive(Sym const * sym) const;
  277. bool IsTypeSpecialized(Sym const * sym) const;
  278. bool IsSwitchInt32TypeSpecialized(IR::Instr const * instr) const;
  279. bool IsInt32TypeSpecialized(Sym const * sym) const;
  280. bool IsFloat64TypeSpecialized(Sym const * sym) const;
  281. #ifdef ENABLE_SIMDJS
  282. // SIMD_JS
  283. bool IsSimd128TypeSpecialized(Sym const * sym) const;
  284. bool IsSimd128TypeSpecialized(IRType type, Sym const * sym) const;
  285. bool IsSimd128F4TypeSpecialized(Sym const * sym) const;
  286. bool IsSimd128I4TypeSpecialized(Sym const * sym) const;
  287. bool IsLiveAsSimd128(Sym const * sym) const;
  288. bool IsLiveAsSimd128F4(Sym const * sym) const;
  289. bool IsLiveAsSimd128I4(Sym const * sym) const;
  290. #endif
  291. // Changed Symbol Tracking
  292. public:
  293. void SetChangedSym(SymID symId);
  294. private:
  295. // Other
  296. public:
  297. void KillStateForGeneratorYield();
  298. // Debug
  299. public:
  300. void DumpSymToValueMap() const;
  301. private:
  302. static void DumpSym(Sym *sym);
  303. };