GlobOptBlockData.cpp 63 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770
  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. #include "Backend.h"
  6. void
  7. GlobOptBlockData::NullOutBlockData(GlobOpt* globOpt, Func* func)
  8. {
  9. this->globOpt = globOpt;
  10. this->symToValueMap = nullptr;
  11. this->exprToValueMap = nullptr;
  12. this->liveFields = nullptr;
  13. this->maybeWrittenTypeSyms = nullptr;
  14. this->isTempSrc = nullptr;
  15. this->liveVarSyms = nullptr;
  16. this->liveInt32Syms = nullptr;
  17. this->liveLossyInt32Syms = nullptr;
  18. this->liveFloat64Syms = nullptr;
  19. this->argObjSyms = nullptr;
  20. this->maybeTempObjectSyms = nullptr;
  21. this->canStoreTempObjectSyms = nullptr;
  22. this->valuesToKillOnCalls = nullptr;
  23. this->inductionVariables = nullptr;
  24. this->availableIntBoundChecks = nullptr;
  25. this->callSequence = nullptr;
  26. this->startCallCount = 0;
  27. this->argOutCount = 0;
  28. this->totalOutParamCount = 0;
  29. this->inlinedArgOutSize = 0;
  30. this->hasCSECandidates = false;
  31. this->curFunc = func;
  32. this->stackLiteralInitFldDataMap = nullptr;
  33. if (this->capturedValues)
  34. {
  35. this->capturedValues->DecrementRefCount();
  36. }
  37. this->capturedValues = nullptr;
  38. this->changedSyms = nullptr;
  39. this->OnDataUnreferenced();
  40. }
  41. void
  42. GlobOptBlockData::InitBlockData(GlobOpt* globOpt, Func* func)
  43. {
  44. this->globOpt = globOpt;
  45. JitArenaAllocator *const alloc = this->globOpt->alloc;
  46. this->symToValueMap = GlobHashTable::New(alloc, 64);
  47. this->exprToValueMap = ExprHashTable::New(alloc, 64);
  48. this->liveFields = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  49. this->liveArrayValues = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  50. this->isTempSrc = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  51. this->liveVarSyms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  52. this->liveInt32Syms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  53. this->liveLossyInt32Syms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  54. this->liveFloat64Syms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  55. this->argObjSyms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  56. this->maybeTempObjectSyms = nullptr;
  57. this->canStoreTempObjectSyms = nullptr;
  58. this->valuesToKillOnCalls = JitAnew(alloc, ValueSet, alloc);
  59. if(this->globOpt->DoBoundCheckHoist())
  60. {
  61. this->inductionVariables = this->globOpt->IsLoopPrePass() ? JitAnew(alloc, InductionVariableSet, alloc) : nullptr;
  62. this->availableIntBoundChecks = JitAnew(alloc, IntBoundCheckSet, alloc);
  63. }
  64. this->maybeWrittenTypeSyms = nullptr;
  65. this->callSequence = nullptr;
  66. this->startCallCount = 0;
  67. this->argOutCount = 0;
  68. this->totalOutParamCount = 0;
  69. this->inlinedArgOutSize = 0;
  70. this->hasCSECandidates = false;
  71. this->curFunc = func;
  72. this->stackLiteralInitFldDataMap = nullptr;
  73. this->changedSyms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  74. this->OnDataInitialized(alloc);
  75. }
  76. void
  77. GlobOptBlockData::ReuseBlockData(GlobOptBlockData *fromData)
  78. {
  79. this->globOpt = fromData->globOpt;
  80. // Reuse dead map
  81. this->symToValueMap = fromData->symToValueMap;
  82. this->exprToValueMap = fromData->exprToValueMap;
  83. this->liveFields = fromData->liveFields;
  84. this->liveArrayValues = fromData->liveArrayValues;
  85. this->maybeWrittenTypeSyms = fromData->maybeWrittenTypeSyms;
  86. this->isTempSrc = fromData->isTempSrc;
  87. this->liveVarSyms = fromData->liveVarSyms;
  88. this->liveInt32Syms = fromData->liveInt32Syms;
  89. this->liveLossyInt32Syms = fromData->liveLossyInt32Syms;
  90. this->liveFloat64Syms = fromData->liveFloat64Syms;
  91. if (this->globOpt->TrackArgumentsObject())
  92. {
  93. this->argObjSyms = fromData->argObjSyms;
  94. }
  95. this->maybeTempObjectSyms = fromData->maybeTempObjectSyms;
  96. this->canStoreTempObjectSyms = fromData->canStoreTempObjectSyms;
  97. this->curFunc = fromData->curFunc;
  98. this->valuesToKillOnCalls = fromData->valuesToKillOnCalls;
  99. this->inductionVariables = fromData->inductionVariables;
  100. this->availableIntBoundChecks = fromData->availableIntBoundChecks;
  101. this->callSequence = fromData->callSequence;
  102. this->startCallCount = fromData->startCallCount;
  103. this->argOutCount = fromData->argOutCount;
  104. this->totalOutParamCount = fromData->totalOutParamCount;
  105. this->inlinedArgOutSize = fromData->inlinedArgOutSize;
  106. this->hasCSECandidates = fromData->hasCSECandidates;
  107. this->stackLiteralInitFldDataMap = fromData->stackLiteralInitFldDataMap;
  108. this->changedSyms = fromData->changedSyms;
  109. this->capturedValues = fromData->capturedValues;
  110. if (this->capturedValues)
  111. {
  112. this->capturedValues->IncrementRefCount();
  113. }
  114. this->OnDataReused(fromData);
  115. }
  116. void
  117. GlobOptBlockData::CopyBlockData(GlobOptBlockData *fromData)
  118. {
  119. this->globOpt = fromData->globOpt;
  120. this->symToValueMap = fromData->symToValueMap;
  121. this->exprToValueMap = fromData->exprToValueMap;
  122. this->liveFields = fromData->liveFields;
  123. this->liveArrayValues = fromData->liveArrayValues;
  124. this->maybeWrittenTypeSyms = fromData->maybeWrittenTypeSyms;
  125. this->isTempSrc = fromData->isTempSrc;
  126. this->liveVarSyms = fromData->liveVarSyms;
  127. this->liveInt32Syms = fromData->liveInt32Syms;
  128. this->liveLossyInt32Syms = fromData->liveLossyInt32Syms;
  129. this->liveFloat64Syms = fromData->liveFloat64Syms;
  130. this->argObjSyms = fromData->argObjSyms;
  131. this->maybeTempObjectSyms = fromData->maybeTempObjectSyms;
  132. this->canStoreTempObjectSyms = fromData->canStoreTempObjectSyms;
  133. this->curFunc = fromData->curFunc;
  134. this->valuesToKillOnCalls = fromData->valuesToKillOnCalls;
  135. this->inductionVariables = fromData->inductionVariables;
  136. this->availableIntBoundChecks = fromData->availableIntBoundChecks;
  137. this->callSequence = fromData->callSequence;
  138. this->startCallCount = fromData->startCallCount;
  139. this->argOutCount = fromData->argOutCount;
  140. this->totalOutParamCount = fromData->totalOutParamCount;
  141. this->inlinedArgOutSize = fromData->inlinedArgOutSize;
  142. this->hasCSECandidates = fromData->hasCSECandidates;
  143. this->changedSyms = fromData->changedSyms;
  144. this->capturedValues = fromData->capturedValues;
  145. this->stackLiteralInitFldDataMap = fromData->stackLiteralInitFldDataMap;
  146. this->OnDataReused(fromData);
  147. }
  148. void
  149. GlobOptBlockData::DeleteBlockData()
  150. {
  151. JitArenaAllocator *const alloc = this->globOpt->alloc;
  152. this->symToValueMap->Delete();
  153. this->exprToValueMap->Delete();
  154. JitAdelete(alloc, this->liveFields);
  155. JitAdelete(alloc, this->liveArrayValues);
  156. if (this->maybeWrittenTypeSyms)
  157. {
  158. JitAdelete(alloc, this->maybeWrittenTypeSyms);
  159. }
  160. JitAdelete(alloc, this->isTempSrc);
  161. JitAdelete(alloc, this->liveVarSyms);
  162. JitAdelete(alloc, this->liveInt32Syms);
  163. JitAdelete(alloc, this->liveLossyInt32Syms);
  164. JitAdelete(alloc, this->liveFloat64Syms);
  165. if (this->argObjSyms)
  166. {
  167. JitAdelete(alloc, this->argObjSyms);
  168. }
  169. if (this->maybeTempObjectSyms)
  170. {
  171. JitAdelete(alloc, this->maybeTempObjectSyms);
  172. if (this->canStoreTempObjectSyms)
  173. {
  174. JitAdelete(alloc, this->canStoreTempObjectSyms);
  175. }
  176. }
  177. else
  178. {
  179. Assert(!this->canStoreTempObjectSyms);
  180. }
  181. JitAdelete(alloc, this->valuesToKillOnCalls);
  182. if(this->inductionVariables)
  183. {
  184. JitAdelete(alloc, this->inductionVariables);
  185. }
  186. if(this->availableIntBoundChecks)
  187. {
  188. JitAdelete(alloc, this->availableIntBoundChecks);
  189. }
  190. if (this->stackLiteralInitFldDataMap)
  191. {
  192. JitAdelete(alloc, this->stackLiteralInitFldDataMap);
  193. }
  194. JitAdelete(alloc, this->changedSyms);
  195. this->changedSyms = nullptr;
  196. if (this->capturedValues && this->capturedValues->DecrementRefCount() == 0)
  197. {
  198. JitAdelete(this->curFunc->m_alloc, this->capturedValues);
  199. this->capturedValues = nullptr;
  200. }
  201. this->OnDataDeleted();
  202. }
  203. void GlobOptBlockData::CloneBlockData(BasicBlock *const toBlockContext, BasicBlock *const fromBlock)
  204. {
  205. GlobOptBlockData *const fromData = &fromBlock->globOptData;
  206. this->globOpt = fromData->globOpt;
  207. JitArenaAllocator *const alloc = this->globOpt->alloc;
  208. this->symToValueMap = fromData->symToValueMap->Copy();
  209. this->exprToValueMap = fromData->exprToValueMap->Copy();
  210. // Clone the values as well to allow for flow-sensitive ValueInfo
  211. this->globOpt->CloneValues(toBlockContext, this, fromData);
  212. if(this->globOpt->DoBoundCheckHoist())
  213. {
  214. this->globOpt->CloneBoundCheckHoistBlockData(toBlockContext, this, fromBlock, fromData);
  215. }
  216. this->liveFields = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  217. this->liveFields->Copy(fromData->liveFields);
  218. this->liveArrayValues = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  219. this->liveArrayValues->Copy(fromData->liveArrayValues);
  220. if (fromData->maybeWrittenTypeSyms)
  221. {
  222. this->maybeWrittenTypeSyms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  223. this->maybeWrittenTypeSyms->Copy(fromData->maybeWrittenTypeSyms);
  224. }
  225. this->isTempSrc = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  226. this->isTempSrc->Copy(fromData->isTempSrc);
  227. this->liveVarSyms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  228. this->liveVarSyms->Copy(fromData->liveVarSyms);
  229. this->liveInt32Syms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  230. this->liveInt32Syms->Copy(fromData->liveInt32Syms);
  231. this->liveLossyInt32Syms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  232. this->liveLossyInt32Syms->Copy(fromData->liveLossyInt32Syms);
  233. this->liveFloat64Syms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  234. this->liveFloat64Syms->Copy(fromData->liveFloat64Syms);
  235. if (this->globOpt->TrackArgumentsObject() && fromData->argObjSyms)
  236. {
  237. this->argObjSyms = fromData->argObjSyms->CopyNew(alloc);
  238. }
  239. if (fromData->maybeTempObjectSyms && !fromData->maybeTempObjectSyms->IsEmpty())
  240. {
  241. this->maybeTempObjectSyms = fromData->maybeTempObjectSyms->CopyNew(alloc);
  242. if (fromData->canStoreTempObjectSyms && !fromData->canStoreTempObjectSyms->IsEmpty())
  243. {
  244. this->canStoreTempObjectSyms = fromData->canStoreTempObjectSyms->CopyNew(alloc);
  245. }
  246. }
  247. else
  248. {
  249. Assert(fromData->canStoreTempObjectSyms == nullptr || fromData->canStoreTempObjectSyms->IsEmpty());
  250. }
  251. this->curFunc = fromData->curFunc;
  252. if (fromData->callSequence != nullptr)
  253. {
  254. this->callSequence = JitAnew(alloc, SListBase<IR::Opnd *>);
  255. fromData->callSequence->CopyTo(alloc, *(this->callSequence));
  256. }
  257. else
  258. {
  259. this->callSequence = nullptr;
  260. }
  261. this->startCallCount = fromData->startCallCount;
  262. this->argOutCount = fromData->argOutCount;
  263. this->totalOutParamCount = fromData->totalOutParamCount;
  264. this->inlinedArgOutSize = fromData->inlinedArgOutSize;
  265. this->hasCSECandidates = fromData->hasCSECandidates;
  266. // Although we don't need the data on loop pre pass, we need to do it for the loop header
  267. // because we capture the loop header bailout on loop prepass
  268. if (fromData->stackLiteralInitFldDataMap != nullptr &&
  269. (!this->globOpt->IsLoopPrePass() || (toBlockContext->isLoopHeader && toBlockContext->loop == this->globOpt->rootLoopPrePass)))
  270. {
  271. this->stackLiteralInitFldDataMap = fromData->stackLiteralInitFldDataMap->Clone();
  272. }
  273. else
  274. {
  275. this->stackLiteralInitFldDataMap = nullptr;
  276. }
  277. this->changedSyms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  278. this->changedSyms->Copy(fromData->changedSyms);
  279. this->capturedValues = fromData->capturedValues;
  280. if (this->capturedValues)
  281. {
  282. this->capturedValues->IncrementRefCount();
  283. }
  284. Assert(fromData->HasData());
  285. this->OnDataInitialized(alloc);
  286. }
  287. void GlobOptBlockData::RemoveUnavailableCandidates(PRECandidates * candidates)
  288. {
  289. // In case of multiple back-edges to the loop, make sure the candidates are still valid.
  290. FOREACH_SLIST_ENTRY_EDITING(GlobHashBucket*, candidate, candidates->candidatesList, iter)
  291. {
  292. Value *candidateValue = candidate->element;
  293. PropertySym *candidatePropertySym = candidate->value->AsPropertySym();
  294. ValueNumber valueNumber = candidateValue->GetValueNumber();
  295. Sym *symStore = candidateValue->GetValueInfo()->GetSymStore();
  296. Value *blockValue = this->FindValue(candidatePropertySym);
  297. if (blockValue && blockValue->GetValueNumber() == valueNumber
  298. && blockValue->GetValueInfo()->GetSymStore() == symStore)
  299. {
  300. Value *symStoreValue = this->FindValue(symStore);
  301. if (symStoreValue && symStoreValue->GetValueNumber() == valueNumber)
  302. {
  303. continue;
  304. }
  305. }
  306. iter.RemoveCurrent();
  307. Assert(candidates->candidatesToProcess->Test(candidatePropertySym->m_id));
  308. candidates->candidatesToProcess->Clear(candidatePropertySym->m_id);
  309. } NEXT_SLIST_ENTRY_EDITING;
  310. }
  311. template <typename CapturedList, typename CapturedItemsAreEqual>
  312. void
  313. GlobOptBlockData::MergeCapturedValues(
  314. SListBase<CapturedList> * toList,
  315. SListBase<CapturedList> * fromList,
  316. CapturedItemsAreEqual itemsAreEqual)
  317. {
  318. typename SListBase<CapturedList>::Iterator iterTo(toList);
  319. typename SListBase<CapturedList>::Iterator iterFrom(fromList);
  320. bool hasTo = iterTo.Next();
  321. bool hasFrom = fromList == nullptr ? false : iterFrom.Next();
  322. // to be conservative, only copy the captured value for common sym Ids
  323. // in from and to CapturedList, mark all non-common sym Ids for re-capture
  324. while (hasFrom && hasTo)
  325. {
  326. Sym * symFrom = iterFrom.Data().Key();
  327. Sym * symTo = iterTo.Data().Key();
  328. if (symFrom->m_id < symTo->m_id)
  329. {
  330. this->changedSyms->Set(symFrom->m_id);
  331. hasFrom = iterFrom.Next();
  332. }
  333. else if(symFrom->m_id > symTo->m_id)
  334. {
  335. this->changedSyms->Set(symTo->m_id);
  336. hasTo = iterTo.Next();
  337. }
  338. else
  339. {
  340. if (!itemsAreEqual(&iterFrom.Data(), &iterTo.Data()))
  341. {
  342. this->changedSyms->Set(symTo->m_id);
  343. }
  344. hasFrom = iterFrom.Next();
  345. hasTo = iterTo.Next();
  346. }
  347. }
  348. bool hasRemain = hasFrom || hasTo;
  349. if (hasRemain)
  350. {
  351. typename SListBase<CapturedList>::Iterator iterRemain(hasFrom ? iterFrom : iterTo);
  352. do
  353. {
  354. Sym * symRemain = iterRemain.Data().Key();
  355. this->changedSyms->Set(symRemain->m_id);
  356. hasRemain = iterRemain.Next();
  357. } while (hasRemain);
  358. }
  359. }
  360. void
  361. GlobOptBlockData::MergeBlockData(
  362. BasicBlock *toBlock,
  363. BasicBlock *fromBlock,
  364. BVSparse<JitArenaAllocator> *const symsRequiringCompensation,
  365. BVSparse<JitArenaAllocator> *const symsCreatedForMerge,
  366. bool forceTypeSpecOnLoopHeader)
  367. {
  368. GlobOptBlockData *fromData = &(fromBlock->globOptData);
  369. if(this->globOpt->DoBoundCheckHoist())
  370. {
  371. // Do this before merging values so that it can see whether a sym's value was changed on one side or the other
  372. this->globOpt->MergeBoundCheckHoistBlockData(toBlock, this, fromBlock, fromData);
  373. }
  374. bool isLoopBackEdge = toBlock->isLoopHeader;
  375. this->MergeValueMaps(toBlock, fromBlock, symsRequiringCompensation, symsCreatedForMerge);
  376. this->globOpt->InsertCloneStrs(toBlock, this, fromData);
  377. this->liveFields->And(fromData->liveFields);
  378. this->liveArrayValues->And(fromData->liveArrayValues);
  379. this->isTempSrc->And(fromData->isTempSrc);
  380. this->hasCSECandidates &= fromData->hasCSECandidates;
  381. this->changedSyms->Or(fromData->changedSyms);
  382. if (this->capturedValues == nullptr)
  383. {
  384. this->capturedValues = fromData->capturedValues;
  385. if (this->capturedValues)
  386. {
  387. this->capturedValues->IncrementRefCount();
  388. }
  389. }
  390. else
  391. {
  392. this->MergeCapturedValues(
  393. &this->capturedValues->constantValues,
  394. fromData->capturedValues == nullptr ? nullptr : &fromData->capturedValues->constantValues,
  395. [&](ConstantStackSymValue * symValueFrom, ConstantStackSymValue * symValueTo)
  396. {
  397. Assert(symValueFrom->Key()->m_id == symValueTo->Key()->m_id);
  398. return symValueFrom->Value().IsEqual(symValueTo->Value());
  399. });
  400. this->MergeCapturedValues(
  401. &this->capturedValues->copyPropSyms,
  402. fromData->capturedValues == nullptr ? nullptr : &fromData->capturedValues->copyPropSyms,
  403. [&](CopyPropSyms * copyPropSymFrom, CopyPropSyms * copyPropSymTo)
  404. {
  405. Assert(copyPropSymFrom->Key()->m_id == copyPropSymTo->Key()->m_id);
  406. if (copyPropSymFrom->Value()->m_id == copyPropSymTo->Value()->m_id)
  407. {
  408. Value * fromVal = fromData->FindValue(copyPropSymFrom->Key());
  409. Value * toVal = this->FindValue(copyPropSymFrom->Key());
  410. return fromVal && toVal && fromVal->IsEqualTo(toVal);
  411. }
  412. return false;
  413. });
  414. }
  415. if (fromData->maybeWrittenTypeSyms)
  416. {
  417. if (this->maybeWrittenTypeSyms == nullptr)
  418. {
  419. this->maybeWrittenTypeSyms = JitAnew(this->globOpt->alloc, BVSparse<JitArenaAllocator>, this->globOpt->alloc);
  420. this->maybeWrittenTypeSyms->Copy(fromData->maybeWrittenTypeSyms);
  421. }
  422. else
  423. {
  424. this->maybeWrittenTypeSyms->Or(fromData->maybeWrittenTypeSyms);
  425. }
  426. }
  427. {
  428. // - Keep the var sym live if any of the following is true:
  429. // - The var sym is live on both sides
  430. // - The var sym is the only live sym that contains the lossless value of the sym on a side (that is, the lossless
  431. // int32 sym is not live, and the float64 sym is not live on that side), and the sym of any type is live on the
  432. // other side
  433. // - On a side, the var and float64 syms are live, the lossless int32 sym is not live, the sym's merged value is
  434. // likely int, and the sym of any type is live on the other side. Since the value is likely int, it may be
  435. // int-specialized (with lossless conversion) later. Keeping only the float64 sym live requires doing a lossless
  436. // conversion from float64 to int32, with bailout if the value of the float is not a true 32-bit integer. Checking
  437. // that is costly, and if the float64 sym is converted back to var, it does not become a tagged int, causing a
  438. // guaranteed bailout if a lossless conversion to int happens later. Keep the var sym live to preserve its
  439. // tagged-ness so that it can be int-specialized while avoiding unnecessary bailouts.
  440. // - Keep the int32 sym live if it's live on both sides
  441. // - Mark the sym as lossy if it's lossy on any side
  442. // - Keep the float64 sym live if it's live on a side and the sym of a specialized lossless type is live on the other
  443. // side
  444. //
  445. // fromData.temp =
  446. // (fromData.var - (fromData.int32 - fromData.lossyInt32)) &
  447. // (this.var | this.int32 | this.float64)
  448. // this.temp =
  449. // (this.var - (this.int32 - this.lossyInt32)) &
  450. // (fromData.var | fromData.int32 | fromData.float64)
  451. // this.var =
  452. // (fromData.var & this.var) |
  453. // (fromData.temp - fromData.float64) |
  454. // (this.temp - this.float64) |
  455. // (fromData.temp & fromData.float64 | this.temp & this.float64) & (value ~ int)
  456. //
  457. // this.float64 =
  458. // fromData.float64 & ((this.int32 - this.lossyInt32) | this.float64) |
  459. // this.float64 & ((fromData.int32 - fromData.lossyInt32) | fromData.float64)
  460. // this.int32 &= fromData.int32
  461. // this.lossyInt32 = (fromData.lossyInt32 | this.lossyInt32) & this.int32
  462. BVSparse<JitArenaAllocator> tempBv1(this->globOpt->tempAlloc);
  463. BVSparse<JitArenaAllocator> tempBv2(this->globOpt->tempAlloc);
  464. if (isLoopBackEdge && forceTypeSpecOnLoopHeader)
  465. {
  466. Loop *const loop = toBlock->loop;
  467. // Force to lossless int32:
  468. // forceLosslessInt32 =
  469. // ((fromData.int32 - fromData.lossyInt32) - (this.int32 - this.lossyInt32)) &
  470. // loop.likelyIntSymsUsedBeforeDefined &
  471. // this.var
  472. tempBv1.Minus(fromData->liveInt32Syms, fromData->liveLossyInt32Syms);
  473. tempBv2.Minus(this->liveInt32Syms, this->liveLossyInt32Syms);
  474. tempBv1.Minus(&tempBv2);
  475. tempBv1.And(loop->likelyIntSymsUsedBeforeDefined);
  476. tempBv1.And(this->liveVarSyms);
  477. this->liveInt32Syms->Or(&tempBv1);
  478. this->liveLossyInt32Syms->Minus(&tempBv1);
  479. if(this->globOpt->DoLossyIntTypeSpec())
  480. {
  481. // Force to lossy int32:
  482. // forceLossyInt32 = (fromData.int32 - this.int32) & loop.symsUsedBeforeDefined & this.var
  483. tempBv1.Minus(fromData->liveInt32Syms, this->liveInt32Syms);
  484. tempBv1.And(loop->symsUsedBeforeDefined);
  485. tempBv1.And(this->liveVarSyms);
  486. this->liveInt32Syms->Or(&tempBv1);
  487. this->liveLossyInt32Syms->Or(&tempBv1);
  488. }
  489. // Force to float64:
  490. // forceFloat64 =
  491. // fromData.float64 & loop.forceFloat64 |
  492. // (fromData.float64 - this.float64) & loop.likelyNumberSymsUsedBeforeDefined
  493. tempBv1.And(fromData->liveFloat64Syms, loop->forceFloat64SymsOnEntry);
  494. this->liveFloat64Syms->Or(&tempBv1);
  495. tempBv1.Minus(fromData->liveFloat64Syms, this->liveFloat64Syms);
  496. tempBv1.And(loop->likelyNumberSymsUsedBeforeDefined);
  497. this->liveFloat64Syms->Or(&tempBv1);
  498. }
  499. {
  500. BVSparse<JitArenaAllocator> tempBv3(this->globOpt->tempAlloc);
  501. // fromData.temp =
  502. // (fromData.var - (fromData.int32 - fromData.lossyInt32)) &
  503. // (this.var | this.int32 | this.float64)
  504. tempBv2.Minus(fromData->liveInt32Syms, fromData->liveLossyInt32Syms);
  505. tempBv1.Minus(fromData->liveVarSyms, &tempBv2);
  506. tempBv2.Or(this->liveVarSyms, this->liveInt32Syms);
  507. tempBv2.Or(this->liveFloat64Syms);
  508. tempBv1.And(&tempBv2);
  509. // this.temp =
  510. // (this.var - (this.int32 - this.lossyInt32)) &
  511. // (fromData.var | fromData.int32 | fromData.float64)
  512. tempBv3.Minus(this->liveInt32Syms, this->liveLossyInt32Syms);
  513. tempBv2.Minus(this->liveVarSyms, &tempBv3);
  514. tempBv3.Or(fromData->liveVarSyms, fromData->liveInt32Syms);
  515. tempBv3.Or(fromData->liveFloat64Syms);
  516. tempBv2.And(&tempBv3);
  517. {
  518. BVSparse<JitArenaAllocator> tempBv4(this->globOpt->tempAlloc);
  519. // fromData.temp & fromData.float64 | this.temp & this.float64
  520. tempBv3.And(&tempBv1, fromData->liveFloat64Syms);
  521. tempBv4.And(&tempBv2, this->liveFloat64Syms);
  522. tempBv3.Or(&tempBv4);
  523. }
  524. // (fromData.temp - fromData.float64) |
  525. // (this.temp - this.float64)
  526. tempBv1.Minus(fromData->liveFloat64Syms);
  527. tempBv2.Minus(this->liveFloat64Syms);
  528. tempBv1.Or(&tempBv2);
  529. // this.var =
  530. // (fromData.var & this.var) |
  531. // (fromData.temp - fromData.float64) |
  532. // (this.temp - this.float64)
  533. this->liveVarSyms->And(fromData->liveVarSyms);
  534. this->liveVarSyms->Or(&tempBv1);
  535. // this.var |=
  536. // (fromData.temp & fromData.float64 | this.temp & this.float64) & (value ~ int)
  537. FOREACH_BITSET_IN_SPARSEBV(id, &tempBv3)
  538. {
  539. StackSym *const stackSym = this->globOpt->func->m_symTable->FindStackSym(id);
  540. Assert(stackSym);
  541. Value *const value = this->FindValue(stackSym);
  542. if(value)
  543. {
  544. ValueInfo *const valueInfo = value->GetValueInfo();
  545. if(valueInfo->IsInt() || (valueInfo->IsLikelyInt() && this->globOpt->DoAggressiveIntTypeSpec()))
  546. {
  547. this->liveVarSyms->Set(id);
  548. }
  549. }
  550. } NEXT_BITSET_IN_SPARSEBV;
  551. }
  552. // fromData.float64 & ((this.int32 - this.lossyInt32) | this.float64)
  553. tempBv1.Minus(this->liveInt32Syms, this->liveLossyInt32Syms);
  554. tempBv1.Or(this->liveFloat64Syms);
  555. tempBv1.And(fromData->liveFloat64Syms);
  556. // this.float64 & ((fromData.int32 - fromData.lossyInt32) | fromData.float64)
  557. tempBv2.Minus(fromData->liveInt32Syms, fromData->liveLossyInt32Syms);
  558. tempBv2.Or(fromData->liveFloat64Syms);
  559. tempBv2.And(this->liveFloat64Syms);
  560. // this.float64 =
  561. // fromData.float64 & ((this.int32 - this.lossyInt32) | this.float64) |
  562. // this.float64 & ((fromData.int32 - fromData.lossyInt32) | fromData.float64)
  563. this->liveFloat64Syms->Or(&tempBv1, &tempBv2);
  564. // this.int32 &= fromData.int32
  565. // this.lossyInt32 = (fromData.lossyInt32 | this.lossyInt32) & this.int32
  566. this->liveInt32Syms->And(fromData->liveInt32Syms);
  567. this->liveLossyInt32Syms->Or(fromData->liveLossyInt32Syms);
  568. this->liveLossyInt32Syms->And(this->liveInt32Syms);
  569. }
  570. if (this->globOpt->TrackArgumentsObject())
  571. {
  572. if (!this->argObjSyms->Equal(fromData->argObjSyms))
  573. {
  574. this->globOpt->CannotAllocateArgumentsObjectOnStack(nullptr);
  575. }
  576. }
  577. if (fromData->maybeTempObjectSyms && !fromData->maybeTempObjectSyms->IsEmpty())
  578. {
  579. if (this->maybeTempObjectSyms)
  580. {
  581. this->maybeTempObjectSyms->Or(fromData->maybeTempObjectSyms);
  582. }
  583. else
  584. {
  585. this->maybeTempObjectSyms = fromData->maybeTempObjectSyms->CopyNew(this->globOpt->alloc);
  586. }
  587. if (fromData->canStoreTempObjectSyms && !fromData->canStoreTempObjectSyms->IsEmpty())
  588. {
  589. if (this->canStoreTempObjectSyms)
  590. {
  591. // Both need to be temp object
  592. this->canStoreTempObjectSyms->And(fromData->canStoreTempObjectSyms);
  593. }
  594. }
  595. else if (this->canStoreTempObjectSyms)
  596. {
  597. this->canStoreTempObjectSyms->ClearAll();
  598. }
  599. }
  600. else
  601. {
  602. Assert(!fromData->canStoreTempObjectSyms || fromData->canStoreTempObjectSyms->IsEmpty());
  603. if (this->canStoreTempObjectSyms)
  604. {
  605. this->canStoreTempObjectSyms->ClearAll();
  606. }
  607. }
  608. Assert(this->curFunc == fromData->curFunc);
  609. Assert((this->callSequence == nullptr && fromData->callSequence == nullptr) || this->callSequence->Equals(*(fromData->callSequence)));
  610. Assert(this->startCallCount == fromData->startCallCount);
  611. Assert(this->argOutCount == fromData->argOutCount);
  612. Assert(this->totalOutParamCount == fromData->totalOutParamCount);
  613. Assert(this->inlinedArgOutSize == fromData->inlinedArgOutSize);
  614. // stackLiteralInitFldDataMap is a union of the stack literal from two path.
  615. // Although we don't need the data on loop prepass, we need to do it for the loop header
  616. // because we capture the loop header bailout on loop prepass.
  617. if (fromData->stackLiteralInitFldDataMap != nullptr &&
  618. (!this->globOpt->IsLoopPrePass() || (toBlock->isLoopHeader && toBlock->loop == this->globOpt->rootLoopPrePass)))
  619. {
  620. if (this->stackLiteralInitFldDataMap == nullptr)
  621. {
  622. this->stackLiteralInitFldDataMap = fromData->stackLiteralInitFldDataMap->Clone();
  623. }
  624. else
  625. {
  626. StackLiteralInitFldDataMap * toMap = this->stackLiteralInitFldDataMap;
  627. fromData->stackLiteralInitFldDataMap->Map([toMap](StackSym * stackSym, StackLiteralInitFldData const& data)
  628. {
  629. if (toMap->AddNew(stackSym, data) == -1)
  630. {
  631. // If there is an existing data for the stackSym, both path should match
  632. DebugOnly(StackLiteralInitFldData const * currentData);
  633. Assert(toMap->TryGetReference(stackSym, &currentData));
  634. Assert(currentData->currentInitFldCount == data.currentInitFldCount);
  635. Assert(currentData->propIds == data.propIds);
  636. }
  637. });
  638. }
  639. }
  640. }
  641. void
  642. GlobOptBlockData::MergeValueMaps(
  643. BasicBlock *toBlock,
  644. BasicBlock *fromBlock,
  645. BVSparse<JitArenaAllocator> *const symsRequiringCompensation,
  646. BVSparse<JitArenaAllocator> *const symsCreatedForMerge)
  647. {
  648. GlobOptBlockData *fromData = &(fromBlock->globOptData);
  649. bool isLoopBackEdge = toBlock->isLoopHeader;
  650. Loop *loop = toBlock->loop;
  651. bool isLoopPrepass = (loop && this->globOpt->prePassLoop == loop);
  652. Assert(this->globOpt->valuesCreatedForMerge->Count() == 0);
  653. DebugOnly(ValueSetByValueNumber mergedValues(this->globOpt->tempAlloc, 64));
  654. BVSparse<JitArenaAllocator> *const mergedValueTypesTrackedForKills = this->globOpt->tempBv;
  655. Assert(mergedValueTypesTrackedForKills->IsEmpty());
  656. this->valuesToKillOnCalls->Clear(); // the tracking will be reevaluated based on merged value types
  657. GlobHashTable *thisTable = this->symToValueMap;
  658. GlobHashTable *otherTable = fromData->symToValueMap;
  659. for (uint i = 0; i < thisTable->tableSize; i++)
  660. {
  661. SListBase<GlobHashBucket>::Iterator iter2(&otherTable->table[i]);
  662. iter2.Next();
  663. FOREACH_SLISTBASE_ENTRY_EDITING(GlobHashBucket, bucket, &thisTable->table[i], iter)
  664. {
  665. while (iter2.IsValid() && bucket.value->m_id < iter2.Data().value->m_id)
  666. {
  667. iter2.Next();
  668. }
  669. Value *newValue = nullptr;
  670. if (iter2.IsValid() && bucket.value->m_id == iter2.Data().value->m_id)
  671. {
  672. // Syms that are assigned to within the loop must have unique
  673. // value numbers in the loop header after merging; a single
  674. // prepass is not adequate to determine that sym values are
  675. // equivalent through all possible loop paths.
  676. bool forceUniqueValue =
  677. isLoopBackEdge &&
  678. !this->globOpt->IsLoopPrePass() &&
  679. loop &&
  680. loop->symsAssignedToInLoop->Test(bucket.value->m_id);
  681. newValue =
  682. this->MergeValues(
  683. bucket.element,
  684. iter2.Data().element,
  685. iter2.Data().value,
  686. isLoopBackEdge,
  687. forceUniqueValue,
  688. symsRequiringCompensation,
  689. symsCreatedForMerge);
  690. }
  691. if (newValue == nullptr)
  692. {
  693. iter.RemoveCurrent(thisTable->alloc);
  694. continue;
  695. }
  696. else
  697. {
  698. #if DBG
  699. // Ensure that only one value per value number is produced by merge. Byte-code constant values are reused in
  700. // multiple blocks without cloning, so exclude those value numbers.
  701. {
  702. Value *const previouslyMergedValue = mergedValues.Lookup(newValue->GetValueNumber());
  703. if (previouslyMergedValue)
  704. {
  705. if (!this->globOpt->byteCodeConstantValueNumbersBv->Test(newValue->GetValueNumber()))
  706. {
  707. Assert(newValue == previouslyMergedValue);
  708. }
  709. }
  710. else
  711. {
  712. mergedValues.Add(newValue);
  713. }
  714. }
  715. #endif
  716. this->globOpt->TrackMergedValueForKills(newValue, this, mergedValueTypesTrackedForKills);
  717. bucket.element = newValue;
  718. }
  719. iter2.Next();
  720. } NEXT_SLISTBASE_ENTRY_EDITING;
  721. if (isLoopPrepass && !this->globOpt->rootLoopPrePass->allFieldsKilled)
  722. {
  723. while (iter2.IsValid())
  724. {
  725. iter2.Next();
  726. }
  727. }
  728. }
  729. this->globOpt->valuesCreatedForMerge->Clear();
  730. DebugOnly(mergedValues.Reset());
  731. mergedValueTypesTrackedForKills->ClearAll();
  732. this->exprToValueMap->And(fromData->exprToValueMap);
  733. this->globOpt->ProcessValueKills(toBlock, this);
  734. bool isLastLoopBackEdge = false;
  735. if (isLoopBackEdge)
  736. {
  737. this->globOpt->ProcessValueKillsForLoopHeaderAfterBackEdgeMerge(toBlock, this);
  738. BasicBlock *lastBlock = nullptr;
  739. FOREACH_PREDECESSOR_BLOCK(pred, toBlock)
  740. {
  741. Assert(!lastBlock || pred->GetBlockNum() > lastBlock->GetBlockNum());
  742. lastBlock = pred;
  743. }NEXT_PREDECESSOR_BLOCK;
  744. isLastLoopBackEdge = (lastBlock == fromBlock);
  745. }
  746. }
  747. Value *
  748. GlobOptBlockData::MergeValues(
  749. Value *toDataValue,
  750. Value *fromDataValue,
  751. Sym *fromDataSym,
  752. bool isLoopBackEdge,
  753. bool forceUniqueValue,
  754. BVSparse<JitArenaAllocator> *const symsRequiringCompensation,
  755. BVSparse<JitArenaAllocator> *const symsCreatedForMerge)
  756. {
  757. // Same map
  758. if (toDataValue == fromDataValue)
  759. {
  760. return toDataValue;
  761. }
  762. const ValueNumberPair sourceValueNumberPair(toDataValue->GetValueNumber(), fromDataValue->GetValueNumber());
  763. const bool sameValueNumber = sourceValueNumberPair.First() == sourceValueNumberPair.Second();
  764. ValueInfo *newValueInfo =
  765. this->MergeValueInfo(
  766. toDataValue,
  767. fromDataValue,
  768. fromDataSym,
  769. isLoopBackEdge,
  770. sameValueNumber,
  771. symsRequiringCompensation,
  772. symsCreatedForMerge);
  773. if (newValueInfo == nullptr)
  774. {
  775. return nullptr;
  776. }
  777. if (sameValueNumber && newValueInfo == toDataValue->GetValueInfo())
  778. {
  779. return toDataValue;
  780. }
  781. Value *newValue = nullptr;
  782. if (forceUniqueValue)
  783. {
  784. newValue = this->globOpt->NewValue(newValueInfo);
  785. }
  786. else
  787. {
  788. // There may be other syms in toData that haven't been merged yet, referring to the current toData value for this sym. If
  789. // the merge produced a new value info, don't corrupt the value info for the other sym by changing the same value. Instead,
  790. // create one value per source value number pair per merge and reuse that for new value infos.
  791. newValue = this->globOpt->valuesCreatedForMerge->Lookup(sourceValueNumberPair, nullptr);
  792. if (newValue)
  793. {
  794. Assert(sameValueNumber == (newValue->GetValueNumber() == toDataValue->GetValueNumber()));
  795. // This is an exception where Value::SetValueInfo is called directly instead of GlobOpt::ChangeValueInfo, because we're
  796. // actually generating new value info through merges.
  797. newValue->SetValueInfo(newValueInfo);
  798. }
  799. else
  800. {
  801. newValue = this->globOpt->NewValue(sameValueNumber ? sourceValueNumberPair.First() : this->globOpt->NewValueNumber(), newValueInfo);
  802. this->globOpt->valuesCreatedForMerge->Add(sourceValueNumberPair, newValue);
  803. }
  804. }
  805. // Set symStore if same on both paths.
  806. if (toDataValue->GetValueInfo()->GetSymStore() == fromDataValue->GetValueInfo()->GetSymStore())
  807. {
  808. this->globOpt->SetSymStoreDirect(newValueInfo, toDataValue->GetValueInfo()->GetSymStore());
  809. }
  810. return newValue;
  811. }
  812. ValueInfo *
  813. GlobOptBlockData::MergeValueInfo(
  814. Value *toDataVal,
  815. Value *fromDataVal,
  816. Sym *fromDataSym,
  817. bool isLoopBackEdge,
  818. bool sameValueNumber,
  819. BVSparse<JitArenaAllocator> *const symsRequiringCompensation,
  820. BVSparse<JitArenaAllocator> *const symsCreatedForMerge)
  821. {
  822. ValueInfo *const toDataValueInfo = toDataVal->GetValueInfo();
  823. ValueInfo *const fromDataValueInfo = fromDataVal->GetValueInfo();
  824. if (toDataValueInfo->IsJsType() || fromDataValueInfo->IsJsType())
  825. {
  826. Assert(toDataValueInfo->IsJsType() && fromDataValueInfo->IsJsType());
  827. return this->MergeJsTypeValueInfo(toDataValueInfo->AsJsType(), fromDataValueInfo->AsJsType(), isLoopBackEdge, sameValueNumber);
  828. }
  829. // Same value
  830. if (toDataValueInfo == fromDataValueInfo)
  831. {
  832. return toDataValueInfo;
  833. }
  834. ValueType newValueType(toDataValueInfo->Type().Merge(fromDataValueInfo->Type()));
  835. if (newValueType.IsLikelyInt())
  836. {
  837. return ValueInfo::MergeLikelyIntValueInfo(this->globOpt->alloc, toDataVal, fromDataVal, newValueType);
  838. }
  839. if(newValueType.IsLikelyAnyOptimizedArray())
  840. {
  841. if(newValueType.IsLikelyArrayOrObjectWithArray() &&
  842. toDataValueInfo->IsLikelyArrayOrObjectWithArray() &&
  843. fromDataValueInfo->IsLikelyArrayOrObjectWithArray())
  844. {
  845. // Value type merge for missing values is aggressive by default (for profile data) - if either side likely has no
  846. // missing values, then the merged value type also likely has no missing values. This is because arrays often start
  847. // off having missing values but are eventually filled up. In GlobOpt however, we need to be conservative because
  848. // the existence of a value type that likely has missing values indicates that it is more likely for it to have
  849. // missing values than not. Also, StElems that are likely to create missing values are tracked in profile data and
  850. // will update value types to say they are now likely to have missing values, and that needs to be propagated
  851. // conservatively.
  852. newValueType =
  853. newValueType.SetHasNoMissingValues(
  854. toDataValueInfo->HasNoMissingValues() && fromDataValueInfo->HasNoMissingValues());
  855. if(toDataValueInfo->HasIntElements() != fromDataValueInfo->HasIntElements() ||
  856. toDataValueInfo->HasFloatElements() != fromDataValueInfo->HasFloatElements())
  857. {
  858. // When merging arrays with different native storage types, make the merged value type a likely version to force
  859. // array checks to be done again and cause a conversion and/or bailout as necessary
  860. newValueType = newValueType.ToLikely();
  861. }
  862. }
  863. if(!(newValueType.IsObject() && toDataValueInfo->IsArrayValueInfo() && fromDataValueInfo->IsArrayValueInfo()))
  864. {
  865. return ValueInfo::New(this->globOpt->alloc, newValueType);
  866. }
  867. return
  868. this->MergeArrayValueInfo(
  869. newValueType,
  870. toDataValueInfo->AsArrayValueInfo(),
  871. fromDataValueInfo->AsArrayValueInfo(),
  872. fromDataSym,
  873. symsRequiringCompensation,
  874. symsCreatedForMerge,
  875. isLoopBackEdge);
  876. }
  877. // Consider: If both values are VarConstantValueInfo with the same value, we could
  878. // merge them preserving the value.
  879. return ValueInfo::New(this->globOpt->alloc, newValueType);
  880. }
  881. JsTypeValueInfo*
  882. GlobOptBlockData::MergeJsTypeValueInfo(JsTypeValueInfo * toValueInfo, JsTypeValueInfo * fromValueInfo, bool isLoopBackEdge, bool sameValueNumber)
  883. {
  884. // On loop back edges we must be conservative and only consider type values which are invariant throughout the loop.
  885. // That's because in dead store pass we can't correctly track object pointer assignments (o = p), and we may not
  886. // be able to register correct type checks for the right properties upstream. If we ever figure out how to enhance
  887. // the dead store pass to track this info we could go more aggressively, as below.
  888. if (isLoopBackEdge && !sameValueNumber)
  889. {
  890. return nullptr;
  891. }
  892. if (toValueInfo == fromValueInfo)
  893. {
  894. return toValueInfo;
  895. }
  896. const JITTypeHolder toType = toValueInfo->GetJsType();
  897. const JITTypeHolder fromType = fromValueInfo->GetJsType();
  898. const JITTypeHolder mergedType = toType == fromType ? toType : JITTypeHolder(nullptr);
  899. Js::EquivalentTypeSet* toTypeSet = toValueInfo->GetJsTypeSet();
  900. Js::EquivalentTypeSet* fromTypeSet = fromValueInfo->GetJsTypeSet();
  901. Js::EquivalentTypeSet* mergedTypeSet = (toTypeSet != nullptr && fromTypeSet != nullptr && Js::EquivalentTypeSet::AreIdentical(toTypeSet, fromTypeSet)) ? toTypeSet : nullptr;
  902. #if DBG_DUMP
  903. if (PHASE_TRACE(Js::ObjTypeSpecPhase, this->globOpt->func) || PHASE_TRACE(Js::EquivObjTypeSpecPhase, this->globOpt->func))
  904. {
  905. Output::Print(_u("ObjTypeSpec: Merging type value info:\n"));
  906. Output::Print(_u(" from (shared %d): "), fromValueInfo->GetIsShared());
  907. fromValueInfo->Dump();
  908. Output::Print(_u("\n to (shared %d): "), toValueInfo->GetIsShared());
  909. toValueInfo->Dump();
  910. }
  911. #endif
  912. if (mergedType == toType && mergedTypeSet == toTypeSet)
  913. {
  914. #if DBG_DUMP
  915. if (PHASE_TRACE(Js::ObjTypeSpecPhase, this->globOpt->func) || PHASE_TRACE(Js::EquivObjTypeSpecPhase, this->globOpt->func))
  916. {
  917. Output::Print(_u("\n result (shared %d): "), toValueInfo->GetIsShared());
  918. toValueInfo->Dump();
  919. Output::Print(_u("\n"));
  920. }
  921. #endif
  922. return toValueInfo;
  923. }
  924. if (mergedType == nullptr && mergedTypeSet == nullptr)
  925. {
  926. // No info, so don't bother making a value.
  927. return nullptr;
  928. }
  929. if (toValueInfo->GetIsShared())
  930. {
  931. JsTypeValueInfo* mergedValueInfo = JsTypeValueInfo::New(this->globOpt->alloc, mergedType, mergedTypeSet);
  932. #if DBG_DUMP
  933. if (PHASE_TRACE(Js::ObjTypeSpecPhase, this->globOpt->func) || PHASE_TRACE(Js::EquivObjTypeSpecPhase, this->globOpt->func))
  934. {
  935. Output::Print(_u("\n result (shared %d): "), mergedValueInfo->GetIsShared());
  936. mergedValueInfo->Dump();
  937. Output::Print(_u("\n"));
  938. }
  939. #endif
  940. return mergedValueInfo;
  941. }
  942. else
  943. {
  944. toValueInfo->SetJsType(mergedType);
  945. toValueInfo->SetJsTypeSet(mergedTypeSet);
  946. #if DBG_DUMP
  947. if (PHASE_TRACE(Js::ObjTypeSpecPhase, this->globOpt->func) || PHASE_TRACE(Js::EquivObjTypeSpecPhase, this->globOpt->func))
  948. {
  949. Output::Print(_u("\n result (shared %d): "), toValueInfo->GetIsShared());
  950. toValueInfo->Dump();
  951. Output::Print(_u("\n"));
  952. }
  953. #endif
  954. return toValueInfo;
  955. }
  956. }
  957. ValueInfo *GlobOptBlockData::MergeArrayValueInfo(
  958. const ValueType mergedValueType,
  959. const ArrayValueInfo *const toDataValueInfo,
  960. const ArrayValueInfo *const fromDataValueInfo,
  961. Sym *const arraySym,
  962. BVSparse<JitArenaAllocator> *const symsRequiringCompensation,
  963. BVSparse<JitArenaAllocator> *const symsCreatedForMerge,
  964. bool isLoopBackEdge)
  965. {
  966. Assert(mergedValueType.IsAnyOptimizedArray());
  967. Assert(toDataValueInfo);
  968. Assert(fromDataValueInfo);
  969. Assert(toDataValueInfo != fromDataValueInfo);
  970. Assert(arraySym);
  971. Assert(!symsRequiringCompensation == this->globOpt->IsLoopPrePass());
  972. Assert(!symsCreatedForMerge == this->globOpt->IsLoopPrePass());
  973. // Merge the segment and segment length syms. If we have the segment and/or the segment length syms available on both sides
  974. // but in different syms, create a new sym and record that the array sym requires compensation. Compensation will be
  975. // inserted later to initialize this new sym from all predecessors of the merged block.
  976. StackSym *newHeadSegmentSym = nullptr;
  977. if(toDataValueInfo->HeadSegmentSym() && fromDataValueInfo->HeadSegmentSym())
  978. {
  979. if(toDataValueInfo->HeadSegmentSym() == fromDataValueInfo->HeadSegmentSym())
  980. {
  981. newHeadSegmentSym = toDataValueInfo->HeadSegmentSym();
  982. }
  983. else
  984. {
  985. if (!this->globOpt->IsLoopPrePass() && !isLoopBackEdge)
  986. {
  987. // Adding compensation code in the prepass won't help, as the symstores would again be different in the main pass.
  988. Assert(symsRequiringCompensation);
  989. symsRequiringCompensation->Set(arraySym->m_id);
  990. Assert(symsCreatedForMerge);
  991. if (symsCreatedForMerge->Test(toDataValueInfo->HeadSegmentSym()->m_id))
  992. {
  993. newHeadSegmentSym = toDataValueInfo->HeadSegmentSym();
  994. }
  995. else
  996. {
  997. newHeadSegmentSym = StackSym::New(TyMachPtr, this->globOpt->func);
  998. symsCreatedForMerge->Set(newHeadSegmentSym->m_id);
  999. }
  1000. }
  1001. }
  1002. }
  1003. StackSym *newHeadSegmentLengthSym = nullptr;
  1004. if(toDataValueInfo->HeadSegmentLengthSym() && fromDataValueInfo->HeadSegmentLengthSym())
  1005. {
  1006. if(toDataValueInfo->HeadSegmentLengthSym() == fromDataValueInfo->HeadSegmentLengthSym())
  1007. {
  1008. newHeadSegmentLengthSym = toDataValueInfo->HeadSegmentLengthSym();
  1009. }
  1010. else
  1011. {
  1012. if (!this->globOpt->IsLoopPrePass() && !isLoopBackEdge)
  1013. {
  1014. Assert(symsRequiringCompensation);
  1015. symsRequiringCompensation->Set(arraySym->m_id);
  1016. Assert(symsCreatedForMerge);
  1017. if (symsCreatedForMerge->Test(toDataValueInfo->HeadSegmentLengthSym()->m_id))
  1018. {
  1019. newHeadSegmentLengthSym = toDataValueInfo->HeadSegmentLengthSym();
  1020. }
  1021. else
  1022. {
  1023. newHeadSegmentLengthSym = StackSym::New(TyUint32, this->globOpt->func);
  1024. symsCreatedForMerge->Set(newHeadSegmentLengthSym->m_id);
  1025. }
  1026. }
  1027. }
  1028. }
  1029. StackSym *newLengthSym = nullptr;
  1030. if(toDataValueInfo->LengthSym() && fromDataValueInfo->LengthSym())
  1031. {
  1032. if(toDataValueInfo->LengthSym() == fromDataValueInfo->LengthSym())
  1033. {
  1034. newLengthSym = toDataValueInfo->LengthSym();
  1035. }
  1036. else
  1037. {
  1038. if (!this->globOpt->IsLoopPrePass() && !isLoopBackEdge)
  1039. {
  1040. Assert(symsRequiringCompensation);
  1041. symsRequiringCompensation->Set(arraySym->m_id);
  1042. Assert(symsCreatedForMerge);
  1043. if (symsCreatedForMerge->Test(toDataValueInfo->LengthSym()->m_id))
  1044. {
  1045. newLengthSym = toDataValueInfo->LengthSym();
  1046. }
  1047. else
  1048. {
  1049. newLengthSym = StackSym::New(TyUint32, this->globOpt->func);
  1050. symsCreatedForMerge->Set(newLengthSym->m_id);
  1051. }
  1052. }
  1053. }
  1054. }
  1055. if(newHeadSegmentSym || newHeadSegmentLengthSym || newLengthSym)
  1056. {
  1057. return ArrayValueInfo::New(this->globOpt->alloc, mergedValueType, newHeadSegmentSym, newHeadSegmentLengthSym, newLengthSym);
  1058. }
  1059. if(symsRequiringCompensation)
  1060. {
  1061. symsRequiringCompensation->Clear(arraySym->m_id);
  1062. }
  1063. return ValueInfo::New(this->globOpt->alloc, mergedValueType);
  1064. }
  1065. void
  1066. GlobOptBlockData::TrackArgumentsSym(IR::RegOpnd const* opnd)
  1067. {
  1068. if(!this->curFunc->argObjSyms)
  1069. {
  1070. this->curFunc->argObjSyms = JitAnew(this->globOpt->alloc, BVSparse<JitArenaAllocator>, this->globOpt->alloc);
  1071. }
  1072. this->curFunc->argObjSyms->Set(opnd->m_sym->m_id);
  1073. this->argObjSyms->Set(opnd->m_sym->m_id);
  1074. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  1075. if (PHASE_TESTTRACE(Js::StackArgOptPhase, this->globOpt->func))
  1076. {
  1077. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  1078. char16 debugStringBuffer2[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  1079. Output::Print(_u("Created a new alias s%d for arguments object in function %s(%s) topFunc %s(%s)\n"),
  1080. opnd->m_sym->m_id,
  1081. this->curFunc->GetJITFunctionBody()->GetDisplayName(),
  1082. this->curFunc->GetDebugNumberSet(debugStringBuffer),
  1083. this->globOpt->func->GetJITFunctionBody()->GetDisplayName(),
  1084. this->globOpt->func->GetDebugNumberSet(debugStringBuffer2)
  1085. );
  1086. Output::Flush();
  1087. }
  1088. #endif
  1089. }
  1090. void
  1091. GlobOptBlockData::ClearArgumentsSym(IR::RegOpnd const* opnd)
  1092. {
  1093. // We blindly clear so need to check func has argObjSyms
  1094. if (this->curFunc->argObjSyms)
  1095. {
  1096. this->curFunc->argObjSyms->Clear(opnd->m_sym->m_id);
  1097. }
  1098. this->argObjSyms->Clear(opnd->m_sym->m_id);
  1099. }
  1100. BOOL
  1101. GlobOptBlockData::TestAnyArgumentsSym() const
  1102. {
  1103. return this->argObjSyms->TestEmpty();
  1104. }
  1105. BOOL
  1106. GlobOptBlockData::IsArgumentsSymID(SymID id) const
  1107. {
  1108. return this->argObjSyms->Test(id);
  1109. }
  1110. BOOL
  1111. GlobOptBlockData::IsArgumentsOpnd(IR::Opnd const* opnd) const
  1112. {
  1113. SymID id = 0;
  1114. if (opnd->IsRegOpnd())
  1115. {
  1116. id = opnd->AsRegOpnd()->m_sym->m_id;
  1117. return this->IsArgumentsSymID(id);
  1118. }
  1119. else if (opnd->IsSymOpnd())
  1120. {
  1121. Sym const *sym = opnd->AsSymOpnd()->m_sym;
  1122. if (sym && sym->IsPropertySym())
  1123. {
  1124. PropertySym const *propertySym = sym->AsPropertySym();
  1125. id = propertySym->m_stackSym->m_id;
  1126. return this->IsArgumentsSymID(id);
  1127. }
  1128. return false;
  1129. }
  1130. else if (opnd->IsIndirOpnd())
  1131. {
  1132. IR::RegOpnd const *indexOpnd = opnd->AsIndirOpnd()->GetIndexOpnd();
  1133. IR::RegOpnd const *baseOpnd = opnd->AsIndirOpnd()->GetBaseOpnd();
  1134. return this->IsArgumentsSymID(baseOpnd->m_sym->m_id) || (indexOpnd && this->IsArgumentsSymID(indexOpnd->m_sym->m_id));
  1135. }
  1136. AssertMsg(false, "Unknown type");
  1137. return false;
  1138. }
  1139. Value*
  1140. GlobOptBlockData::FindValue(Sym *sym)
  1141. {
  1142. Assert(this->symToValueMap);
  1143. if (sym->IsStackSym() && sym->AsStackSym()->IsTypeSpec())
  1144. {
  1145. sym = sym->AsStackSym()->GetVarEquivSym(this->globOpt->func);
  1146. }
  1147. else if (sym->IsPropertySym())
  1148. {
  1149. return this->FindPropertyValue(sym->m_id);
  1150. }
  1151. if (sym->IsStackSym() && sym->AsStackSym()->IsFromByteCodeConstantTable())
  1152. {
  1153. return this->globOpt->byteCodeConstantValueArray->Get(sym->m_id);
  1154. }
  1155. else
  1156. {
  1157. return FindValueFromMapDirect(sym->m_id);
  1158. }
  1159. }
  1160. Value *
  1161. GlobOptBlockData::FindPropertyValue(SymID symId)
  1162. {
  1163. Assert(this->globOpt->func->m_symTable->Find(symId)->IsPropertySym());
  1164. if (!this->liveFields->Test(symId))
  1165. {
  1166. return nullptr;
  1167. }
  1168. return FindValueFromMapDirect(symId);
  1169. }
  1170. Value *
  1171. GlobOptBlockData::FindObjectTypeValue(SymID typeSymId)
  1172. {
  1173. Assert(this->globOpt->func->m_symTable->Find(typeSymId)->IsStackSym());
  1174. if (!this->liveFields->Test(typeSymId))
  1175. {
  1176. return nullptr;
  1177. }
  1178. return FindObjectTypeValueNoLivenessCheck(typeSymId);
  1179. }
  1180. Value *
  1181. GlobOptBlockData::FindObjectTypeValueNoLivenessCheck(StackSym* typeSym)
  1182. {
  1183. return FindObjectTypeValueNoLivenessCheck(typeSym->m_id);
  1184. }
  1185. Value *
  1186. GlobOptBlockData::FindObjectTypeValueNoLivenessCheck(SymID typeSymId)
  1187. {
  1188. Value* value = this->FindValueFromMapDirect(typeSymId);
  1189. Assert(value == nullptr || value->GetValueInfo()->IsJsType());
  1190. return value;
  1191. }
  1192. Value *
  1193. GlobOptBlockData::FindObjectTypeValue(StackSym* typeSym)
  1194. {
  1195. return FindObjectTypeValue(typeSym->m_id);
  1196. }
  1197. Value *
  1198. GlobOptBlockData::FindFuturePropertyValue(PropertySym *const propertySym)
  1199. {
  1200. Assert(propertySym);
  1201. // Try a direct lookup based on this sym
  1202. Value *const value = this->FindValue(propertySym);
  1203. if(value)
  1204. {
  1205. return value;
  1206. }
  1207. if(PHASE_OFF(Js::CopyPropPhase, this->globOpt->func))
  1208. {
  1209. // Need to use copy-prop info to backtrack
  1210. return nullptr;
  1211. }
  1212. // Try to get the property object's value
  1213. StackSym *const objectSym = propertySym->m_stackSym;
  1214. Value *objectValue = this->FindValue(objectSym);
  1215. if(!objectValue)
  1216. {
  1217. if(!objectSym->IsSingleDef())
  1218. {
  1219. return nullptr;
  1220. }
  1221. switch(objectSym->m_instrDef->m_opcode)
  1222. {
  1223. case Js::OpCode::Ld_A:
  1224. case Js::OpCode::LdSlotArr:
  1225. case Js::OpCode::LdSlot:
  1226. // Allow only these op-codes for tracking the object sym's value transfer backwards. Other transfer op-codes
  1227. // could be included here if this function is used in scenarios that need them.
  1228. break;
  1229. default:
  1230. return nullptr;
  1231. }
  1232. // Try to get the property object's value from the src of the definition
  1233. IR::Opnd *const objectTransferSrc = objectSym->m_instrDef->GetSrc1();
  1234. if(!objectTransferSrc)
  1235. {
  1236. return nullptr;
  1237. }
  1238. if(objectTransferSrc->IsRegOpnd())
  1239. {
  1240. objectValue = this->FindValue(objectTransferSrc->AsRegOpnd()->m_sym);
  1241. }
  1242. else if(objectTransferSrc->IsSymOpnd())
  1243. {
  1244. Sym *const objectTransferSrcSym = objectTransferSrc->AsSymOpnd()->m_sym;
  1245. if(objectTransferSrcSym->IsStackSym())
  1246. {
  1247. objectValue = this->FindValue(objectTransferSrcSym);
  1248. }
  1249. else
  1250. {
  1251. // About to make a recursive call, so when jitting in the foreground, probe the stack
  1252. if(!this->globOpt->func->IsBackgroundJIT())
  1253. {
  1254. PROBE_STACK_NO_DISPOSE(this->globOpt->func->GetScriptContext(), Js::Constants::MinStackDefault);
  1255. }
  1256. objectValue = FindFuturePropertyValue(objectTransferSrcSym->AsPropertySym());
  1257. }
  1258. }
  1259. else
  1260. {
  1261. return nullptr;
  1262. }
  1263. if(!objectValue)
  1264. {
  1265. return nullptr;
  1266. }
  1267. }
  1268. // Try to use the property object's copy-prop sym and the property ID to find a mapped property sym, and get its value
  1269. StackSym *const objectCopyPropSym = this->GetCopyPropSym(nullptr, objectValue);
  1270. if(!objectCopyPropSym)
  1271. {
  1272. return nullptr;
  1273. }
  1274. PropertySym *const propertyCopyPropSym = PropertySym::Find(objectCopyPropSym->m_id, propertySym->m_propertyId, this->globOpt->func);
  1275. if(!propertyCopyPropSym)
  1276. {
  1277. return nullptr;
  1278. }
  1279. return this->FindValue(propertyCopyPropSym);
  1280. }
  1281. Value *
  1282. GlobOptBlockData::FindValueFromMapDirect(SymID symId)
  1283. {
  1284. Value ** valuePtr = this->symToValueMap->Get(symId);
  1285. if (valuePtr == nullptr)
  1286. {
  1287. return 0;
  1288. }
  1289. return (*valuePtr);
  1290. }
  1291. StackSym *
  1292. GlobOptBlockData::GetCopyPropSym(Sym * sym, Value * value)
  1293. {
  1294. ValueInfo *valueInfo = value->GetValueInfo();
  1295. Sym * copySym = valueInfo->GetSymStore();
  1296. if (!copySym)
  1297. {
  1298. return nullptr;
  1299. }
  1300. // Only copy prop stackSym, as a propertySym wouldn't improve anything.
  1301. // SingleDef info isn't flow sensitive, so make sure the symbol is actually live.
  1302. if (copySym->IsStackSym() && copySym != sym)
  1303. {
  1304. Assert(!copySym->AsStackSym()->IsTypeSpec());
  1305. Value *copySymVal = this->FindValue(valueInfo->GetSymStore());
  1306. if (copySymVal && copySymVal->GetValueNumber() == value->GetValueNumber())
  1307. {
  1308. if (valueInfo->IsVarConstant() && !this->IsLive(copySym))
  1309. {
  1310. // Because the addrConstantToValueMap isn't flow-based, the symStore of
  1311. // varConstants may not be live.
  1312. return nullptr;
  1313. }
  1314. return copySym->AsStackSym();
  1315. }
  1316. }
  1317. return nullptr;
  1318. }
  1319. void
  1320. GlobOptBlockData::ClearSymValue(Sym* sym)
  1321. {
  1322. this->symToValueMap->Clear(sym->m_id);
  1323. }
  1324. void
  1325. GlobOptBlockData::MarkTempLastUse(IR::Instr *instr, IR::RegOpnd *regOpnd)
  1326. {
  1327. if (OpCodeAttr::NonTempNumberSources(instr->m_opcode))
  1328. {
  1329. // Turn off bit if opcode could cause the src to be aliased.
  1330. this->isTempSrc->Clear(regOpnd->m_sym->m_id);
  1331. }
  1332. else if (this->isTempSrc->Test(regOpnd->m_sym->m_id))
  1333. {
  1334. // We just mark things that are temp in the globopt phase.
  1335. // The backwards phase will turn this off if it is not the last use.
  1336. // The isTempSrc is freed at the end of each block, which is why the backwards phase can't
  1337. // just use it.
  1338. if (!PHASE_OFF(Js::BackwardPhase, this->globOpt->func) && !this->globOpt->IsLoopPrePass())
  1339. {
  1340. regOpnd->m_isTempLastUse = true;
  1341. }
  1342. }
  1343. }
  1344. Value *
  1345. GlobOptBlockData::InsertNewValue(Value *val, IR::Opnd *opnd)
  1346. {
  1347. return this->SetValue(val, opnd);
  1348. }
  1349. void
  1350. GlobOptBlockData::SetChangedSym(SymID symId)
  1351. {
  1352. // this->currentBlock might not be the one which contain the changing symId,
  1353. // like hoisting invariant, but more changed symId is overly conservative and safe.
  1354. // symId in the hoisted to block is marked as JITOptimizedReg so it does't affect bailout.
  1355. if (this->changedSyms)
  1356. {
  1357. this->changedSyms->Set(symId);
  1358. if (this->capturedValuesCandidate != nullptr)
  1359. {
  1360. this->globOpt->changedSymsAfterIncBailoutCandidate->Set(symId);
  1361. }
  1362. }
  1363. // else could be hit only in MergeValues and it is handled by MergeCapturedValues
  1364. }
  1365. void
  1366. GlobOptBlockData::SetChangedSym(Sym* sym)
  1367. {
  1368. if (sym && sym->IsStackSym() && sym->AsStackSym()->HasByteCodeRegSlot())
  1369. {
  1370. SetChangedSym(sym->m_id);
  1371. }
  1372. }
  1373. void
  1374. GlobOptBlockData::SetValue(Value *val, Sym * sym)
  1375. {
  1376. ValueInfo *valueInfo = val->GetValueInfo();
  1377. sym = this->globOpt->SetSymStore(valueInfo, sym);
  1378. bool isStackSym = sym->IsStackSym();
  1379. if (isStackSym && sym->AsStackSym()->IsFromByteCodeConstantTable())
  1380. {
  1381. // Put the constants in a global array. This will minimize the per-block info.
  1382. this->globOpt->byteCodeConstantValueArray->Set(sym->m_id, val);
  1383. this->globOpt->byteCodeConstantValueNumbersBv->Set(val->GetValueNumber());
  1384. }
  1385. else
  1386. {
  1387. this->SetValueToHashTable(this->symToValueMap, val, sym);
  1388. this->SetChangedSym(sym);
  1389. }
  1390. }
  1391. Value *
  1392. GlobOptBlockData::SetValue(Value *val, IR::Opnd *opnd)
  1393. {
  1394. if (opnd)
  1395. {
  1396. Sym *sym;
  1397. switch (opnd->GetKind())
  1398. {
  1399. case IR::OpndKindSym:
  1400. sym = opnd->AsSymOpnd()->m_sym;
  1401. break;
  1402. case IR::OpndKindReg:
  1403. sym = opnd->AsRegOpnd()->m_sym;
  1404. break;
  1405. default:
  1406. sym = nullptr;
  1407. }
  1408. if (sym)
  1409. {
  1410. this->SetValue(val, sym);
  1411. }
  1412. }
  1413. return val;
  1414. }
  1415. void
  1416. GlobOptBlockData::SetValueToHashTable(GlobHashTable *valueNumberMap, Value *val, Sym *sym)
  1417. {
  1418. Value **pValue = valueNumberMap->FindOrInsertNew(sym);
  1419. *pValue = val;
  1420. }
  1421. void
  1422. GlobOptBlockData::MakeLive(StackSym *sym, const bool lossy)
  1423. {
  1424. Assert(sym);
  1425. Assert(this);
  1426. if(sym->IsTypeSpec())
  1427. {
  1428. const SymID varSymId = sym->GetVarEquivSym(this->globOpt->func)->m_id;
  1429. if(sym->IsInt32())
  1430. {
  1431. this->liveInt32Syms->Set(varSymId);
  1432. if(lossy)
  1433. {
  1434. this->liveLossyInt32Syms->Set(varSymId);
  1435. }
  1436. else
  1437. {
  1438. this->liveLossyInt32Syms->Clear(varSymId);
  1439. }
  1440. return;
  1441. }
  1442. if (sym->IsFloat64())
  1443. {
  1444. this->liveFloat64Syms->Set(varSymId);
  1445. return;
  1446. }
  1447. }
  1448. this->liveVarSyms->Set(sym->m_id);
  1449. }
  1450. bool
  1451. GlobOptBlockData::IsLive(Sym const * sym) const
  1452. {
  1453. sym = StackSym::GetVarEquivStackSym_NoCreate(sym);
  1454. return
  1455. sym &&
  1456. (
  1457. this->liveVarSyms->Test(sym->m_id) ||
  1458. this->liveInt32Syms->Test(sym->m_id) ||
  1459. this->liveFloat64Syms->Test(sym->m_id)
  1460. );
  1461. }
  1462. bool
  1463. GlobOptBlockData::IsTypeSpecialized(Sym const * sym) const
  1464. {
  1465. return this->IsInt32TypeSpecialized(sym) || this->IsFloat64TypeSpecialized(sym);
  1466. }
  1467. bool
  1468. GlobOptBlockData::IsSwitchInt32TypeSpecialized(IR::Instr const * instr) const
  1469. {
  1470. return GlobOpt::IsSwitchOptEnabledForIntTypeSpec(instr->m_func->GetTopFunc())
  1471. && instr->GetSrc1()->IsRegOpnd()
  1472. && this->IsInt32TypeSpecialized(instr->GetSrc1()->AsRegOpnd()->m_sym);
  1473. }
  1474. bool
  1475. GlobOptBlockData::IsInt32TypeSpecialized(Sym const * sym) const
  1476. {
  1477. sym = StackSym::GetVarEquivStackSym_NoCreate(sym);
  1478. return sym && this->liveInt32Syms->Test(sym->m_id) && !this->liveLossyInt32Syms->Test(sym->m_id);
  1479. }
  1480. bool
  1481. GlobOptBlockData::IsFloat64TypeSpecialized(Sym const * sym) const
  1482. {
  1483. sym = StackSym::GetVarEquivStackSym_NoCreate(sym);
  1484. return sym && this->liveFloat64Syms->Test(sym->m_id);
  1485. }
  1486. void
  1487. GlobOptBlockData::KillStateForGeneratorYield(IR::Instr* yieldInstr)
  1488. {
  1489. this->liveInt32Syms->Minus(this->liveVarSyms);
  1490. this->globOpt->ToVar(liveInt32Syms, this->globOpt->currentBlock, yieldInstr /* insertBeforeInstr */);
  1491. this->liveInt32Syms->ClearAll();
  1492. this->liveFloat64Syms->Minus(this->liveVarSyms);
  1493. this->globOpt->ToVar(liveFloat64Syms, this->globOpt->currentBlock, yieldInstr /* insertBeforeInstr */);
  1494. this->liveFloat64Syms->ClearAll();
  1495. this->liveLossyInt32Syms->ClearAll();
  1496. // Keep this->liveVarSyms as is
  1497. // Keep this->argObjSyms as is
  1498. this->hasCSECandidates = false;
  1499. // No need to clear `isTempSrc` (used for in-place string concat)
  1500. this->exprToValueMap->ClearAll();
  1501. this->KillSymToValueMapForGeneratorYield();
  1502. }
  1503. void
  1504. GlobOptBlockData::KillSymToValueMapForGeneratorYield()
  1505. {
  1506. // Remove illegal symToValueMap entries whose symstores don't have bytecode registers
  1507. // Hash table bucket key-value visualization: { bucket.value: bucket.element }
  1508. //
  1509. // Idea:
  1510. // Multiple symbols can map to the same value which has a symstore
  1511. // (multiple keys map to same value).
  1512. // Since the symstore might not have a bytecode register, our first pass
  1513. // through the map attemps to use the symbol (key) as a symstore for that value.
  1514. // This allows us to still retain such entries.
  1515. // After the first pass, any symToValueMap entries whose symstores don't have
  1516. // bytecode registers will be cleared.
  1517. FOREACH_VALUEHASHTABLE_ENTRY(GlobHashBucket, bucket, this->symToValueMap)
  1518. {
  1519. if (bucket.element == nullptr)
  1520. {
  1521. continue;
  1522. }
  1523. Sym* symStore = bucket.element->GetValueInfo()->GetSymStore();
  1524. if (symStore != nullptr && symStore->IsStackSym() && symStore->AsStackSym()->HasByteCodeRegSlot())
  1525. {
  1526. continue;
  1527. }
  1528. Sym* sym = bucket.value;
  1529. if (sym != nullptr && sym->IsStackSym() && sym->AsStackSym()->HasByteCodeRegSlot())
  1530. {
  1531. bucket.element->GetValueInfo()->SetSymStore(sym);
  1532. }
  1533. }
  1534. NEXT_VALUEHASHTABLE_ENTRY;
  1535. // Remove illegal entries
  1536. FOREACH_VALUEHASHTABLE_ENTRY_EDITING(GlobHashBucket, bucket, this->symToValueMap, iter)
  1537. {
  1538. Value* value = bucket.element;
  1539. if (value == nullptr)
  1540. {
  1541. iter.RemoveCurrent(this->symToValueMap->alloc);
  1542. }
  1543. else
  1544. {
  1545. Sym* symStore = value->GetValueInfo()->GetSymStore();
  1546. if (symStore == nullptr || !symStore->IsStackSym() || !symStore->AsStackSym()->HasByteCodeRegSlot())
  1547. {
  1548. iter.RemoveCurrent(this->symToValueMap->alloc);
  1549. }
  1550. }
  1551. }
  1552. NEXT_VALUEHASHTABLE_ENTRY_EDITING;
  1553. }
  1554. #if DBG_DUMP
  1555. void
  1556. GlobOptBlockData::DumpSymToValueMap() const
  1557. {
  1558. if (this->symToValueMap != nullptr)
  1559. {
  1560. this->symToValueMap->Dump(GlobOptBlockData::DumpSym);
  1561. }
  1562. }
  1563. void
  1564. GlobOptBlockData::DumpSym(Sym *sym)
  1565. {
  1566. ((Sym const*)sym)->Dump();
  1567. }
  1568. #endif