GlobOptBlockData.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  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. liveSimd128F4Syms(nullptr),
  101. liveSimd128I4Syms(nullptr),
  102. hoistableFields(nullptr),
  103. argObjSyms(nullptr),
  104. maybeTempObjectSyms(nullptr),
  105. canStoreTempObjectSyms(nullptr),
  106. valuesToKillOnCalls(nullptr),
  107. inductionVariables(nullptr),
  108. availableIntBoundChecks(nullptr),
  109. startCallCount(0),
  110. argOutCount(0),
  111. totalOutParamCount(0),
  112. callSequence(nullptr),
  113. capturedValuesCandidate(nullptr),
  114. capturedValues(nullptr),
  115. changedSyms(nullptr),
  116. hasCSECandidates(false),
  117. curFunc(func),
  118. hasDataRef(nullptr),
  119. stackLiteralInitFldDataMap(nullptr),
  120. globOpt(nullptr)
  121. {
  122. }
  123. // Data
  124. GlobHashTable * symToValueMap;
  125. ExprHashTable * exprToValueMap;
  126. BVSparse<JitArenaAllocator> * liveFields;
  127. BVSparse<JitArenaAllocator> * liveArrayValues;
  128. BVSparse<JitArenaAllocator> * maybeWrittenTypeSyms;
  129. BVSparse<JitArenaAllocator> * isTempSrc;
  130. BVSparse<JitArenaAllocator> * liveVarSyms;
  131. BVSparse<JitArenaAllocator> * liveInt32Syms;
  132. // 'liveLossyInt32Syms' includes only syms that contain an int value that may not fully represent the value of the
  133. // equivalent var sym. The set (liveInt32Syms - liveLossyInt32Syms) includes only syms that contain an int value that fully
  134. // represents the value of the equivalent var sym, such as when (a + 1) is type-specialized. Among other things, this
  135. // bit-vector is used, based on the type of conversion that is needed, to determine whether conversion is necessary, and if
  136. // so, whether a bailout is needed. For instance, after type-specializing (a | 0), the int32 sym of 'a' cannot be reused in
  137. // (a + 1) during type-specialization. It needs to be converted again using a lossless conversion with a bailout.
  138. // Conversely, a lossless int32 sym can be reused to avoid a lossy conversion.
  139. BVSparse<JitArenaAllocator> * liveLossyInt32Syms;
  140. BVSparse<JitArenaAllocator> * liveFloat64Syms;
  141. // SIMD_JS
  142. BVSparse<JitArenaAllocator> * liveSimd128F4Syms;
  143. BVSparse<JitArenaAllocator> * liveSimd128I4Syms;
  144. BVSparse<JitArenaAllocator> * hoistableFields;
  145. BVSparse<JitArenaAllocator> * argObjSyms;
  146. BVSparse<JitArenaAllocator> * maybeTempObjectSyms;
  147. BVSparse<JitArenaAllocator> * canStoreTempObjectSyms;
  148. // This is the func that this block comes from, so the inlinee if from an inlined function
  149. Func * curFunc;
  150. // 'valuesToKillOnCalls' includes values whose value types need to be killed upon a call. Upon a call, the value types of
  151. // values in the set are updated and removed from the set as appropriate.
  152. ValueSet * valuesToKillOnCalls;
  153. InductionVariableSet * inductionVariables;
  154. IntBoundCheckSet * availableIntBoundChecks;
  155. // Bailout data
  156. uint startCallCount;
  157. uint argOutCount;
  158. uint totalOutParamCount;
  159. SListBase<IR::Opnd *> * callSequence;
  160. StackLiteralInitFldDataMap * stackLiteralInitFldDataMap;
  161. CapturedValues * capturedValuesCandidate;
  162. CapturedValues * capturedValues;
  163. BVSparse<JitArenaAllocator> * changedSyms;
  164. uint inlinedArgOutCount;
  165. bool hasCSECandidates;
  166. private:
  167. bool * hasDataRef;
  168. GlobOpt * globOpt;
  169. public:
  170. void OnDataInitialized(JitArenaAllocator *const allocator)
  171. {
  172. Assert(allocator);
  173. hasDataRef = JitAnew(allocator, bool, true);
  174. }
  175. void OnDataReused(GlobOptBlockData *const fromData)
  176. {
  177. // If a block's data is deleted, *hasDataRef will be set to false. Since these two blocks are pointing to the same data,
  178. // they also need to point to the same has-data info.
  179. hasDataRef = fromData->hasDataRef;
  180. }
  181. void OnDataUnreferenced()
  182. {
  183. // Other blocks may still be using the data, we should only un-reference the previous data
  184. hasDataRef = nullptr;
  185. }
  186. void OnDataDeleted()
  187. {
  188. if (hasDataRef)
  189. *hasDataRef = false;
  190. OnDataUnreferenced();
  191. }
  192. bool HasData()
  193. {
  194. if (!hasDataRef)
  195. return false;
  196. if (*hasDataRef)
  197. return true;
  198. OnDataUnreferenced();
  199. return false;
  200. }
  201. // SIMD_JS
  202. BVSparse<JitArenaAllocator> * GetSimd128LivenessBV(IRType type)
  203. {
  204. switch (type)
  205. {
  206. case TySimd128F4:
  207. return liveSimd128F4Syms;
  208. case TySimd128I4:
  209. return liveSimd128I4Syms;
  210. default:
  211. Assert(UNREACHED);
  212. return nullptr;
  213. }
  214. }
  215. // Functions pulled out of GlobOpt.cpp
  216. // Initialization/copying/moving
  217. public:
  218. void NullOutBlockData(GlobOpt* globOpt, Func* func);
  219. void InitBlockData(GlobOpt* globOpt, Func* func);
  220. void ReuseBlockData(GlobOptBlockData *fromData);
  221. void CopyBlockData(GlobOptBlockData *fromData);
  222. void DeleteBlockData();
  223. void CloneBlockData(BasicBlock *const toBlock, BasicBlock *const fromBlock);
  224. public:
  225. void RemoveUnavailableCandidates(PRECandidatesList *candidates);
  226. // Merging functions
  227. public:
  228. void MergeBlockData(BasicBlock *toBlockContext, BasicBlock *fromBlock, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge, bool forceTypeSpecOnLoopHeader);
  229. private:
  230. template <typename CaptureList, typename CapturedItemsAreEqual>
  231. void MergeCapturedValues(SListBase<CaptureList>* toList, SListBase<CaptureList> * fromList, CapturedItemsAreEqual itemsAreEqual);
  232. void MergeValueMaps(BasicBlock *toBlock, BasicBlock *fromBlock, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge);
  233. Value * MergeValues(Value *toDataValue, Value *fromDataValue, Sym *fromDataSym, bool isLoopBackEdge, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge);
  234. ValueInfo * MergeValueInfo(Value *toDataVal, Value *fromDataVal, Sym *fromDataSym, bool isLoopBackEdge, bool sameValueNumber, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge);
  235. JsTypeValueInfo * MergeJsTypeValueInfo(JsTypeValueInfo * toValueInfo, JsTypeValueInfo * fromValueInfo, bool isLoopBackEdge, bool sameValueNumber);
  236. ValueInfo * MergeArrayValueInfo(const ValueType mergedValueType, const ArrayValueInfo *const toDataValueInfo, const ArrayValueInfo *const fromDataValueInfo, Sym *const arraySym, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge);
  237. // Argument Tracking
  238. public:
  239. void TrackArgumentsSym(IR::RegOpnd const* opnd);
  240. void ClearArgumentsSym(IR::RegOpnd const* opnd);
  241. BOOL TestAnyArgumentsSym() const;
  242. BOOL IsArgumentsSymID(SymID id) const;
  243. BOOL IsArgumentsOpnd(IR::Opnd const* opnd) const;
  244. private:
  245. // Value Tracking
  246. public:
  247. Value * FindValue(Sym *sym);
  248. Value * FindValueFromMapDirect(SymID symId);
  249. Value * FindPropertyValue(SymID symId);
  250. Value * FindObjectTypeValue(StackSym* typeSym);
  251. Value * FindObjectTypeValue(SymID typeSymId);
  252. Value * FindFuturePropertyValue(PropertySym *const propertySym);
  253. StackSym * GetCopyPropSym(Sym * sym, Value * val);
  254. Value * InsertNewValue(Value *val, IR::Opnd *opnd);
  255. Value * SetValue(Value *val, IR::Opnd *opnd);
  256. void SetValue(Value *val, Sym * sym);
  257. void ClearSymValue(Sym *sym);
  258. private:
  259. void SetValueToHashTable(GlobHashTable * valueNumberMap, Value *val, Sym *sym);
  260. // Temp Tracking
  261. public:
  262. void MarkTempLastUse(IR::Instr *instr, IR::RegOpnd *regOpnd);
  263. private:
  264. // Liveness Tracking
  265. public:
  266. void MakeLive(StackSym *sym, const bool lossy);
  267. // Checks if the symbol is live in this block under any type
  268. bool IsLive(Sym const * sym) const;
  269. bool IsTypeSpecialized(Sym const * sym) const;
  270. bool IsSwitchInt32TypeSpecialized(IR::Instr const * instr) const;
  271. bool IsInt32TypeSpecialized(Sym const * sym) const;
  272. bool IsFloat64TypeSpecialized(Sym const * sym) const;
  273. // SIMD_JS
  274. bool IsSimd128TypeSpecialized(Sym const * sym) const;
  275. bool IsSimd128TypeSpecialized(IRType type, Sym const * sym) const;
  276. bool IsSimd128F4TypeSpecialized(Sym const * sym) const;
  277. bool IsSimd128I4TypeSpecialized(Sym const * sym) const;
  278. bool IsLiveAsSimd128(Sym const * sym) const;
  279. bool IsLiveAsSimd128F4(Sym const * sym) const;
  280. bool IsLiveAsSimd128I4(Sym const * sym) const;
  281. // Changed Symbol Tracking
  282. public:
  283. void SetChangedSym(SymID symId);
  284. private:
  285. // Other
  286. public:
  287. void KillStateForGeneratorYield();
  288. // Debug
  289. public:
  290. void DumpSymToValueMap() const;
  291. private:
  292. static void DumpSym(Sym *sym);
  293. };