GlobOptBlockData.h 13 KB

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