GlobOptIntBounds.cpp 133 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "Backend.h"
  6. #if ENABLE_DEBUG_CONFIG_OPTIONS && DBG_DUMP
  7. #define TRACE_PHASE_VERBOSE(phase, indent, ...) \
  8. if(PHASE_VERBOSE_TRACE(phase, this->func)) \
  9. { \
  10. for(int i = 0; i < static_cast<int>(indent); ++i) \
  11. { \
  12. Output::Print(_u(" ")); \
  13. } \
  14. Output::Print(__VA_ARGS__); \
  15. Output::Flush(); \
  16. }
  17. #else
  18. #define TRACE_PHASE_VERBOSE(phase, indent, ...)
  19. #endif
  20. void GlobOpt::AddSubConstantInfo::Set(
  21. StackSym *const srcSym,
  22. Value *const srcValue,
  23. const bool srcValueIsLikelyConstant,
  24. const int32 offset)
  25. {
  26. Assert(srcSym);
  27. Assert(!srcSym->IsTypeSpec());
  28. Assert(srcValue);
  29. Assert(srcValue->GetValueInfo()->IsLikelyInt());
  30. this->srcSym = srcSym;
  31. this->srcValue = srcValue;
  32. this->srcValueIsLikelyConstant = srcValueIsLikelyConstant;
  33. this->offset = offset;
  34. }
  35. void GlobOpt::ArrayLowerBoundCheckHoistInfo::SetCompatibleBoundCheck(
  36. BasicBlock *const compatibleBoundCheckBlock,
  37. StackSym *const indexSym,
  38. const int offset,
  39. const ValueNumber indexValueNumber)
  40. {
  41. Assert(!Loop());
  42. Assert(compatibleBoundCheckBlock);
  43. Assert(indexSym);
  44. Assert(!indexSym->IsTypeSpec());
  45. Assert(indexValueNumber != InvalidValueNumber);
  46. this->compatibleBoundCheckBlock = compatibleBoundCheckBlock;
  47. this->indexSym = indexSym;
  48. this->offset = offset;
  49. this->indexValueNumber = indexValueNumber;
  50. }
  51. void GlobOpt::ArrayLowerBoundCheckHoistInfo::SetLoop(
  52. ::Loop *const loop,
  53. const int indexConstantValue,
  54. const bool isLoopCountBasedBound)
  55. {
  56. Assert(!CompatibleBoundCheckBlock());
  57. Assert(loop);
  58. this->loop = loop;
  59. indexSym = nullptr;
  60. offset = 0;
  61. indexValue = nullptr;
  62. indexConstantBounds = IntConstantBounds(indexConstantValue, indexConstantValue);
  63. this->isLoopCountBasedBound = isLoopCountBasedBound;
  64. loopCount = nullptr;
  65. }
  66. void GlobOpt::ArrayLowerBoundCheckHoistInfo::SetLoop(
  67. ::Loop *const loop,
  68. StackSym *const indexSym,
  69. const int offset,
  70. Value *const indexValue,
  71. const IntConstantBounds &indexConstantBounds,
  72. const bool isLoopCountBasedBound)
  73. {
  74. Assert(!CompatibleBoundCheckBlock());
  75. Assert(loop);
  76. Assert(indexSym);
  77. Assert(!indexSym->IsTypeSpec());
  78. Assert(indexValue);
  79. this->loop = loop;
  80. this->indexSym = indexSym;
  81. this->offset = offset;
  82. this->indexValueNumber = indexValue->GetValueNumber();
  83. this->indexValue = indexValue;
  84. this->indexConstantBounds = indexConstantBounds;
  85. this->isLoopCountBasedBound = isLoopCountBasedBound;
  86. loopCount = nullptr;
  87. }
  88. void GlobOpt::ArrayLowerBoundCheckHoistInfo::SetLoopCount(::LoopCount *const loopCount, const int maxMagnitudeChange)
  89. {
  90. Assert(Loop());
  91. Assert(loopCount);
  92. Assert(maxMagnitudeChange != 0);
  93. this->loopCount = loopCount;
  94. this->maxMagnitudeChange = maxMagnitudeChange;
  95. }
  96. void GlobOpt::ArrayUpperBoundCheckHoistInfo::SetCompatibleBoundCheck(
  97. BasicBlock *const compatibleBoundCheckBlock,
  98. const int indexConstantValue)
  99. {
  100. Assert(!Loop());
  101. Assert(compatibleBoundCheckBlock);
  102. this->compatibleBoundCheckBlock = compatibleBoundCheckBlock;
  103. indexSym = nullptr;
  104. offset = -1; // simulate < instead of <=
  105. indexConstantBounds = IntConstantBounds(indexConstantValue, indexConstantValue);
  106. }
  107. void GlobOpt::ArrayUpperBoundCheckHoistInfo::SetLoop(
  108. ::Loop *const loop,
  109. const int indexConstantValue,
  110. Value *const headSegmentLengthValue,
  111. const IntConstantBounds &headSegmentLengthConstantBounds,
  112. const bool isLoopCountBasedBound)
  113. {
  114. Assert(!CompatibleBoundCheckBlock());
  115. Assert(loop);
  116. Assert(headSegmentLengthValue);
  117. SetLoop(loop, indexConstantValue, isLoopCountBasedBound);
  118. offset = -1; // simulate < instead of <=
  119. this->headSegmentLengthValue = headSegmentLengthValue;
  120. this->headSegmentLengthConstantBounds = headSegmentLengthConstantBounds;
  121. }
  122. void GlobOpt::ArrayUpperBoundCheckHoistInfo::SetLoop(
  123. ::Loop *const loop,
  124. StackSym *const indexSym,
  125. const int offset,
  126. Value *const indexValue,
  127. const IntConstantBounds &indexConstantBounds,
  128. Value *const headSegmentLengthValue,
  129. const IntConstantBounds &headSegmentLengthConstantBounds,
  130. const bool isLoopCountBasedBound)
  131. {
  132. Assert(headSegmentLengthValue);
  133. SetLoop(loop, indexSym, offset, indexValue, indexConstantBounds, isLoopCountBasedBound);
  134. this->headSegmentLengthValue = headSegmentLengthValue;
  135. this->headSegmentLengthConstantBounds = headSegmentLengthConstantBounds;
  136. }
  137. bool ValueInfo::HasIntConstantValue(const bool includeLikelyInt) const
  138. {
  139. int32 constantValue;
  140. return TryGetIntConstantValue(&constantValue, includeLikelyInt);
  141. }
  142. bool ValueInfo::TryGetIntConstantValue(int32 *const intValueRef, const bool includeLikelyInt) const
  143. {
  144. Assert(intValueRef);
  145. if(!(includeLikelyInt ? IsLikelyInt() : IsInt()))
  146. {
  147. return false;
  148. }
  149. switch(structureKind)
  150. {
  151. case ValueStructureKind::IntConstant:
  152. if(!includeLikelyInt || IsInt())
  153. {
  154. *intValueRef = AsIntConstant()->IntValue();
  155. return true;
  156. }
  157. break;
  158. case ValueStructureKind::IntRange:
  159. Assert(includeLikelyInt && !IsInt() || !AsIntRange()->IsConstant());
  160. break;
  161. case ValueStructureKind::IntBounded:
  162. {
  163. const IntConstantBounds bounds(AsIntBounded()->Bounds()->ConstantBounds());
  164. if(bounds.IsConstant())
  165. {
  166. *intValueRef = bounds.LowerBound();
  167. return true;
  168. }
  169. break;
  170. }
  171. }
  172. return false;
  173. }
  174. bool ValueInfo::TryGetIntConstantLowerBound(int32 *const intConstantBoundRef, const bool includeLikelyInt) const
  175. {
  176. Assert(intConstantBoundRef);
  177. if(!(includeLikelyInt ? IsLikelyInt() : IsInt()))
  178. {
  179. return false;
  180. }
  181. switch(structureKind)
  182. {
  183. case ValueStructureKind::IntConstant:
  184. if(!includeLikelyInt || IsInt())
  185. {
  186. *intConstantBoundRef = AsIntConstant()->IntValue();
  187. return true;
  188. }
  189. break;
  190. case ValueStructureKind::IntRange:
  191. if(!includeLikelyInt || IsInt())
  192. {
  193. *intConstantBoundRef = AsIntRange()->LowerBound();
  194. return true;
  195. }
  196. break;
  197. case ValueStructureKind::IntBounded:
  198. *intConstantBoundRef = AsIntBounded()->Bounds()->ConstantLowerBound();
  199. return true;
  200. }
  201. *intConstantBoundRef = IsTaggedInt() ? Js::Constants::Int31MinValue : IntConstMin;
  202. return true;
  203. }
  204. bool ValueInfo::TryGetIntConstantUpperBound(int32 *const intConstantBoundRef, const bool includeLikelyInt) const
  205. {
  206. Assert(intConstantBoundRef);
  207. if(!(includeLikelyInt ? IsLikelyInt() : IsInt()))
  208. {
  209. return false;
  210. }
  211. switch(structureKind)
  212. {
  213. case ValueStructureKind::IntConstant:
  214. if(!includeLikelyInt || IsInt())
  215. {
  216. *intConstantBoundRef = AsIntConstant()->IntValue();
  217. return true;
  218. }
  219. break;
  220. case ValueStructureKind::IntRange:
  221. if(!includeLikelyInt || IsInt())
  222. {
  223. *intConstantBoundRef = AsIntRange()->UpperBound();
  224. return true;
  225. }
  226. break;
  227. case ValueStructureKind::IntBounded:
  228. *intConstantBoundRef = AsIntBounded()->Bounds()->ConstantUpperBound();
  229. return true;
  230. }
  231. *intConstantBoundRef = IsTaggedInt() ? Js::Constants::Int31MaxValue : IntConstMax;
  232. return true;
  233. }
  234. bool ValueInfo::TryGetIntConstantBounds(IntConstantBounds *const intConstantBoundsRef, const bool includeLikelyInt) const
  235. {
  236. Assert(intConstantBoundsRef);
  237. if(!(includeLikelyInt ? IsLikelyInt() : IsInt()))
  238. {
  239. return false;
  240. }
  241. switch(structureKind)
  242. {
  243. case ValueStructureKind::IntConstant:
  244. if(!includeLikelyInt || IsInt())
  245. {
  246. const int32 intValue = AsIntConstant()->IntValue();
  247. *intConstantBoundsRef = IntConstantBounds(intValue, intValue);
  248. return true;
  249. }
  250. break;
  251. case ValueStructureKind::IntRange:
  252. if(!includeLikelyInt || IsInt())
  253. {
  254. *intConstantBoundsRef = *AsIntRange();
  255. return true;
  256. }
  257. break;
  258. case ValueStructureKind::IntBounded:
  259. *intConstantBoundsRef = AsIntBounded()->Bounds()->ConstantBounds();
  260. return true;
  261. }
  262. *intConstantBoundsRef =
  263. IsTaggedInt()
  264. ? IntConstantBounds(Js::Constants::Int31MinValue, Js::Constants::Int31MaxValue)
  265. : IntConstantBounds(INT32_MIN, INT32_MAX);
  266. return true;
  267. }
  268. bool ValueInfo::WasNegativeZeroPreventedByBailout() const
  269. {
  270. if(!IsInt())
  271. {
  272. return false;
  273. }
  274. switch(structureKind)
  275. {
  276. case ValueStructureKind::IntRange:
  277. return AsIntRange()->WasNegativeZeroPreventedByBailout();
  278. case ValueStructureKind::IntBounded:
  279. return AsIntBounded()->WasNegativeZeroPreventedByBailout();
  280. }
  281. return false;
  282. }
  283. bool ValueInfo::IsEqualTo(
  284. const Value *const src1Value,
  285. const int32 min1,
  286. const int32 max1,
  287. const Value *const src2Value,
  288. const int32 min2,
  289. const int32 max2)
  290. {
  291. const bool result =
  292. IsEqualTo_NoConverse(src1Value, min1, max1, src2Value, min2, max2) ||
  293. IsEqualTo_NoConverse(src2Value, min2, max2, src1Value, min1, max1);
  294. Assert(!result || !IsNotEqualTo_NoConverse(src1Value, min1, max1, src2Value, min2, max2));
  295. Assert(!result || !IsNotEqualTo_NoConverse(src2Value, min2, max2, src1Value, min1, max1));
  296. return result;
  297. }
  298. bool ValueInfo::IsNotEqualTo(
  299. const Value *const src1Value,
  300. const int32 min1,
  301. const int32 max1,
  302. const Value *const src2Value,
  303. const int32 min2,
  304. const int32 max2)
  305. {
  306. const bool result =
  307. IsNotEqualTo_NoConverse(src1Value, min1, max1, src2Value, min2, max2) ||
  308. IsNotEqualTo_NoConverse(src2Value, min2, max2, src1Value, min1, max1);
  309. Assert(!result || !IsEqualTo_NoConverse(src1Value, min1, max1, src2Value, min2, max2));
  310. Assert(!result || !IsEqualTo_NoConverse(src2Value, min2, max2, src1Value, min1, max1));
  311. return result;
  312. }
  313. bool ValueInfo::IsEqualTo_NoConverse(
  314. const Value *const src1Value,
  315. const int32 min1,
  316. const int32 max1,
  317. const Value *const src2Value,
  318. const int32 min2,
  319. const int32 max2)
  320. {
  321. return
  322. IsGreaterThanOrEqualTo(src1Value, min1, max1, src2Value, min2, max2) &&
  323. IsLessThanOrEqualTo(src1Value, min1, max1, src2Value, min2, max2);
  324. }
  325. bool ValueInfo::IsNotEqualTo_NoConverse(
  326. const Value *const src1Value,
  327. const int32 min1,
  328. const int32 max1,
  329. const Value *const src2Value,
  330. const int32 min2,
  331. const int32 max2)
  332. {
  333. return
  334. IsGreaterThan(src1Value, min1, max1, src2Value, min2, max2) ||
  335. IsLessThan(src1Value, min1, max1, src2Value, min2, max2);
  336. }
  337. bool ValueInfo::IsGreaterThanOrEqualTo(
  338. const Value *const src1Value,
  339. const int32 min1,
  340. const int32 max1,
  341. const Value *const src2Value,
  342. const int32 min2,
  343. const int32 max2)
  344. {
  345. return IsGreaterThanOrEqualTo(src1Value, min1, max1, src2Value, min2, max2, 0);
  346. }
  347. bool ValueInfo::IsGreaterThan(
  348. const Value *const src1Value,
  349. const int32 min1,
  350. const int32 max1,
  351. const Value *const src2Value,
  352. const int32 min2,
  353. const int32 max2)
  354. {
  355. return IsGreaterThanOrEqualTo(src1Value, min1, max1, src2Value, min2, max2, 1);
  356. }
  357. bool ValueInfo::IsLessThanOrEqualTo(
  358. const Value *const src1Value,
  359. const int32 min1,
  360. const int32 max1,
  361. const Value *const src2Value,
  362. const int32 min2,
  363. const int32 max2)
  364. {
  365. return IsLessThanOrEqualTo(src1Value, min1, max1, src2Value, min2, max2, 0);
  366. }
  367. bool ValueInfo::IsLessThan(
  368. const Value *const src1Value,
  369. const int32 min1,
  370. const int32 max1,
  371. const Value *const src2Value,
  372. const int32 min2,
  373. const int32 max2)
  374. {
  375. return IsLessThanOrEqualTo(src1Value, min1, max1, src2Value, min2, max2, -1);
  376. }
  377. bool ValueInfo::IsGreaterThanOrEqualTo(
  378. const Value *const src1Value,
  379. const int32 min1,
  380. const int32 max1,
  381. const Value *const src2Value,
  382. const int32 min2,
  383. const int32 max2,
  384. const int src2Offset)
  385. {
  386. return
  387. IsGreaterThanOrEqualTo_NoConverse(src1Value, min1, max1, src2Value, min2, max2, src2Offset) ||
  388. src2Offset == IntConstMin ||
  389. IsLessThanOrEqualTo_NoConverse(src2Value, min2, max2, src1Value, min1, max1, -src2Offset);
  390. }
  391. bool ValueInfo::IsLessThanOrEqualTo(
  392. const Value *const src1Value,
  393. const int32 min1,
  394. const int32 max1,
  395. const Value *const src2Value,
  396. const int32 min2,
  397. const int32 max2,
  398. const int src2Offset)
  399. {
  400. return
  401. IsLessThanOrEqualTo_NoConverse(src1Value, min1, max1, src2Value, min2, max2, src2Offset) ||
  402. (
  403. src2Offset != IntConstMin &&
  404. IsGreaterThanOrEqualTo_NoConverse(src2Value, min2, max2, src1Value, min1, max1, -src2Offset)
  405. );
  406. }
  407. bool ValueInfo::IsGreaterThanOrEqualTo_NoConverse(
  408. const Value *const src1Value,
  409. const int32 min1,
  410. const int32 max1,
  411. const Value *const src2Value,
  412. const int32 min2,
  413. const int32 max2,
  414. const int src2Offset)
  415. {
  416. Assert(src1Value || min1 == max1);
  417. Assert(!src1Value || src1Value->GetValueInfo()->IsLikelyInt());
  418. Assert(src2Value || min2 == max2);
  419. Assert(!src2Value || src2Value->GetValueInfo()->IsLikelyInt());
  420. if(src1Value)
  421. {
  422. if(src2Value && src1Value->GetValueNumber() == src2Value->GetValueNumber())
  423. {
  424. return src2Offset <= 0;
  425. }
  426. ValueInfo *const src1ValueInfo = src1Value->GetValueInfo();
  427. if(src1ValueInfo->structureKind == ValueStructureKind::IntBounded)
  428. {
  429. const IntBounds *const bounds = src1ValueInfo->AsIntBounded()->Bounds();
  430. return
  431. src2Value
  432. ? bounds->IsGreaterThanOrEqualTo(src2Value, src2Offset)
  433. : bounds->IsGreaterThanOrEqualTo(min2, src2Offset);
  434. }
  435. }
  436. return IntBounds::IsGreaterThanOrEqualTo(min1, max2, src2Offset);
  437. }
  438. bool ValueInfo::IsLessThanOrEqualTo_NoConverse(
  439. const Value *const src1Value,
  440. const int32 min1,
  441. const int32 max1,
  442. const Value *const src2Value,
  443. const int32 min2,
  444. const int32 max2,
  445. const int src2Offset)
  446. {
  447. Assert(src1Value || min1 == max1);
  448. Assert(!src1Value || src1Value->GetValueInfo()->IsLikelyInt());
  449. Assert(src2Value || min2 == max2);
  450. Assert(!src2Value || src2Value->GetValueInfo()->IsLikelyInt());
  451. if(src1Value)
  452. {
  453. if(src2Value && src1Value->GetValueNumber() == src2Value->GetValueNumber())
  454. {
  455. return src2Offset >= 0;
  456. }
  457. ValueInfo *const src1ValueInfo = src1Value->GetValueInfo();
  458. if(src1ValueInfo->structureKind == ValueStructureKind::IntBounded)
  459. {
  460. const IntBounds *const bounds = src1ValueInfo->AsIntBounded()->Bounds();
  461. return
  462. src2Value
  463. ? bounds->IsLessThanOrEqualTo(src2Value, src2Offset)
  464. : bounds->IsLessThanOrEqualTo(min2, src2Offset);
  465. }
  466. }
  467. return IntBounds::IsLessThanOrEqualTo(max1, min2, src2Offset);
  468. }
  469. void GlobOpt::UpdateIntBoundsForEqualBranch(
  470. Value *const src1Value,
  471. Value *const src2Value,
  472. const int32 src2ConstantValue)
  473. {
  474. Assert(src1Value);
  475. if(!DoPathDependentValues() || (src2Value && src1Value->GetValueNumber() == src2Value->GetValueNumber()))
  476. {
  477. return;
  478. }
  479. #if DBG
  480. if(!IsLoopPrePass() && DoAggressiveIntTypeSpec() && DoConstFold())
  481. {
  482. IntConstantBounds src1ConstantBounds, src2ConstantBounds;
  483. AssertVerify(src1Value->GetValueInfo()->TryGetIntConstantBounds(&src1ConstantBounds, true));
  484. if(src2Value)
  485. {
  486. AssertVerify(src2Value->GetValueInfo()->TryGetIntConstantBounds(&src2ConstantBounds, true));
  487. }
  488. else
  489. {
  490. src2ConstantBounds = IntConstantBounds(src2ConstantValue, src2ConstantValue);
  491. }
  492. Assert(
  493. !ValueInfo::IsEqualTo(
  494. src1Value,
  495. src1ConstantBounds.LowerBound(),
  496. src1ConstantBounds.UpperBound(),
  497. src2Value,
  498. src2ConstantBounds.LowerBound(),
  499. src2ConstantBounds.UpperBound()));
  500. Assert(
  501. !ValueInfo::IsNotEqualTo(
  502. src1Value,
  503. src1ConstantBounds.LowerBound(),
  504. src1ConstantBounds.UpperBound(),
  505. src2Value,
  506. src2ConstantBounds.LowerBound(),
  507. src2ConstantBounds.UpperBound()));
  508. }
  509. #endif
  510. SetPathDependentInfo(
  511. true,
  512. PathDependentInfo(PathDependentRelationship::Equal, src1Value, src2Value, src2ConstantValue));
  513. SetPathDependentInfo(
  514. false,
  515. PathDependentInfo(PathDependentRelationship::NotEqual, src1Value, src2Value, src2ConstantValue));
  516. }
  517. void GlobOpt::UpdateIntBoundsForNotEqualBranch(
  518. Value *const src1Value,
  519. Value *const src2Value,
  520. const int32 src2ConstantValue)
  521. {
  522. Assert(src1Value);
  523. if(!DoPathDependentValues() || (src2Value && src1Value->GetValueNumber() == src2Value->GetValueNumber()))
  524. {
  525. return;
  526. }
  527. #if DBG
  528. if(!IsLoopPrePass() && DoAggressiveIntTypeSpec() && DoConstFold())
  529. {
  530. IntConstantBounds src1ConstantBounds, src2ConstantBounds;
  531. AssertVerify(src1Value->GetValueInfo()->TryGetIntConstantBounds(&src1ConstantBounds, true));
  532. if(src2Value)
  533. {
  534. AssertVerify(src2Value->GetValueInfo()->TryGetIntConstantBounds(&src2ConstantBounds, true));
  535. }
  536. else
  537. {
  538. src2ConstantBounds = IntConstantBounds(src2ConstantValue, src2ConstantValue);
  539. }
  540. Assert(
  541. !ValueInfo::IsEqualTo(
  542. src1Value,
  543. src1ConstantBounds.LowerBound(),
  544. src1ConstantBounds.UpperBound(),
  545. src2Value,
  546. src2ConstantBounds.LowerBound(),
  547. src2ConstantBounds.UpperBound()));
  548. Assert(
  549. !ValueInfo::IsNotEqualTo(
  550. src1Value,
  551. src1ConstantBounds.LowerBound(),
  552. src1ConstantBounds.UpperBound(),
  553. src2Value,
  554. src2ConstantBounds.LowerBound(),
  555. src2ConstantBounds.UpperBound()));
  556. }
  557. #endif
  558. SetPathDependentInfo(
  559. true, PathDependentInfo(PathDependentRelationship::NotEqual, src1Value, src2Value, src2ConstantValue));
  560. SetPathDependentInfo(
  561. false, PathDependentInfo(PathDependentRelationship::Equal, src1Value, src2Value, src2ConstantValue));
  562. }
  563. void GlobOpt::UpdateIntBoundsForGreaterThanOrEqualBranch(Value *const src1Value, Value *const src2Value)
  564. {
  565. Assert(src1Value);
  566. Assert(src2Value);
  567. if(!DoPathDependentValues() || src1Value->GetValueNumber() == src2Value->GetValueNumber())
  568. {
  569. return;
  570. }
  571. #if DBG
  572. if(!IsLoopPrePass() && DoAggressiveIntTypeSpec() && DoConstFold())
  573. {
  574. IntConstantBounds src1ConstantBounds, src2ConstantBounds;
  575. AssertVerify(src1Value->GetValueInfo()->TryGetIntConstantBounds(&src1ConstantBounds, true));
  576. AssertVerify(src2Value->GetValueInfo()->TryGetIntConstantBounds(&src2ConstantBounds, true));
  577. Assert(
  578. !ValueInfo::IsGreaterThanOrEqualTo(
  579. src1Value,
  580. src1ConstantBounds.LowerBound(),
  581. src1ConstantBounds.UpperBound(),
  582. src2Value,
  583. src2ConstantBounds.LowerBound(),
  584. src2ConstantBounds.UpperBound()));
  585. Assert(
  586. !ValueInfo::IsLessThan(
  587. src1Value,
  588. src1ConstantBounds.LowerBound(),
  589. src1ConstantBounds.UpperBound(),
  590. src2Value,
  591. src2ConstantBounds.LowerBound(),
  592. src2ConstantBounds.UpperBound()));
  593. }
  594. #endif
  595. SetPathDependentInfo(true, PathDependentInfo(PathDependentRelationship::GreaterThanOrEqual, src1Value, src2Value));
  596. SetPathDependentInfo(false, PathDependentInfo(PathDependentRelationship::LessThan, src1Value, src2Value));
  597. }
  598. void GlobOpt::UpdateIntBoundsForGreaterThanBranch(Value *const src1Value, Value *const src2Value)
  599. {
  600. return UpdateIntBoundsForLessThanBranch(src2Value, src1Value);
  601. }
  602. void GlobOpt::UpdateIntBoundsForLessThanOrEqualBranch(Value *const src1Value, Value *const src2Value)
  603. {
  604. return UpdateIntBoundsForGreaterThanOrEqualBranch(src2Value, src1Value);
  605. }
  606. void GlobOpt::UpdateIntBoundsForLessThanBranch(Value *const src1Value, Value *const src2Value)
  607. {
  608. Assert(src1Value);
  609. Assert(src2Value);
  610. if(!DoPathDependentValues() || src1Value->GetValueNumber() == src2Value->GetValueNumber())
  611. {
  612. return;
  613. }
  614. #if DBG
  615. if(!IsLoopPrePass() && DoAggressiveIntTypeSpec() && DoConstFold())
  616. {
  617. IntConstantBounds src1ConstantBounds, src2ConstantBounds;
  618. AssertVerify(src1Value->GetValueInfo()->TryGetIntConstantBounds(&src1ConstantBounds, true));
  619. AssertVerify(src2Value->GetValueInfo()->TryGetIntConstantBounds(&src2ConstantBounds, true));
  620. Assert(
  621. !ValueInfo::IsGreaterThanOrEqualTo(
  622. src1Value,
  623. src1ConstantBounds.LowerBound(),
  624. src1ConstantBounds.UpperBound(),
  625. src2Value,
  626. src2ConstantBounds.LowerBound(),
  627. src2ConstantBounds.UpperBound()));
  628. Assert(
  629. !ValueInfo::IsLessThan(
  630. src1Value,
  631. src1ConstantBounds.LowerBound(),
  632. src1ConstantBounds.UpperBound(),
  633. src2Value,
  634. src2ConstantBounds.LowerBound(),
  635. src2ConstantBounds.UpperBound()));
  636. }
  637. #endif
  638. SetPathDependentInfo(true, PathDependentInfo(PathDependentRelationship::LessThan, src1Value, src2Value));
  639. SetPathDependentInfo(false, PathDependentInfo(PathDependentRelationship::GreaterThanOrEqual, src1Value, src2Value));
  640. }
  641. IntBounds *GlobOpt::GetIntBoundsToUpdate(
  642. const ValueInfo *const valueInfo,
  643. const IntConstantBounds &constantBounds,
  644. const bool isSettingNewBound,
  645. const bool isBoundConstant,
  646. const bool isSettingUpperBound,
  647. const bool isExplicit)
  648. {
  649. Assert(valueInfo);
  650. Assert(valueInfo->IsLikelyInt());
  651. if(!DoTrackRelativeIntBounds())
  652. {
  653. return nullptr;
  654. }
  655. if(valueInfo->IsIntBounded())
  656. {
  657. const IntBounds *const bounds = valueInfo->AsIntBounded()->Bounds();
  658. if(bounds->RequiresIntBoundedValueInfo(valueInfo->Type()))
  659. {
  660. return bounds->Clone();
  661. }
  662. }
  663. if(valueInfo->IsInt())
  664. {
  665. if(constantBounds.IsConstant())
  666. {
  667. // Don't start tracking relative bounds for int constant values, just retain existing relative bounds. Will use
  668. // IntConstantValueInfo instead.
  669. return nullptr;
  670. }
  671. if(isBoundConstant)
  672. {
  673. // There are no relative bounds to track
  674. if(!(isSettingUpperBound && isExplicit))
  675. {
  676. // We are not setting a constant upper bound that is established explicitly, will use IntRangeValueInfo instead
  677. return nullptr;
  678. }
  679. }
  680. else if(!isSettingNewBound)
  681. {
  682. // New relative bounds are not being set, will use IntRangeValueInfo instead
  683. return nullptr;
  684. }
  685. return IntBounds::New(constantBounds, false, alloc);
  686. }
  687. return nullptr;
  688. }
  689. ValueInfo *GlobOpt::UpdateIntBoundsForEqual(
  690. Value *const value,
  691. const IntConstantBounds &constantBounds,
  692. Value *const boundValue,
  693. const IntConstantBounds &boundConstantBounds,
  694. const bool isExplicit)
  695. {
  696. Assert(value || constantBounds.IsConstant());
  697. Assert(boundValue || boundConstantBounds.IsConstant());
  698. if(!value)
  699. {
  700. return nullptr;
  701. }
  702. Assert(!boundValue || value->GetValueNumber() != boundValue->GetValueNumber());
  703. ValueInfo *const valueInfo = value->GetValueInfo();
  704. IntBounds *const bounds =
  705. GetIntBoundsToUpdate(valueInfo, constantBounds, true, boundConstantBounds.IsConstant(), true, isExplicit);
  706. if(bounds)
  707. {
  708. if(boundValue)
  709. {
  710. const ValueNumber valueNumber = value->GetValueNumber();
  711. bounds->SetLowerBound(valueNumber, boundValue, isExplicit);
  712. bounds->SetUpperBound(valueNumber, boundValue, isExplicit);
  713. }
  714. else
  715. {
  716. bounds->SetLowerBound(boundConstantBounds.LowerBound());
  717. bounds->SetUpperBound(boundConstantBounds.LowerBound(), isExplicit);
  718. }
  719. if(bounds->RequiresIntBoundedValueInfo(valueInfo->Type()))
  720. {
  721. return NewIntBoundedValueInfo(valueInfo, bounds);
  722. }
  723. bounds->Delete();
  724. }
  725. if(!valueInfo->IsInt())
  726. {
  727. return nullptr;
  728. }
  729. const int32 newMin = max(constantBounds.LowerBound(), boundConstantBounds.LowerBound());
  730. const int32 newMax = min(constantBounds.UpperBound(), boundConstantBounds.UpperBound());
  731. return newMin <= newMax ? NewIntRangeValueInfo(valueInfo, newMin, newMax) : nullptr;
  732. }
  733. ValueInfo *GlobOpt::UpdateIntBoundsForNotEqual(
  734. Value *const value,
  735. const IntConstantBounds &constantBounds,
  736. Value *const boundValue,
  737. const IntConstantBounds &boundConstantBounds,
  738. const bool isExplicit)
  739. {
  740. Assert(value || constantBounds.IsConstant());
  741. Assert(boundValue || boundConstantBounds.IsConstant());
  742. if(!value)
  743. {
  744. return nullptr;
  745. }
  746. Assert(!boundValue || value->GetValueNumber() != boundValue->GetValueNumber());
  747. ValueInfo *const valueInfo = value->GetValueInfo();
  748. IntBounds *const bounds =
  749. GetIntBoundsToUpdate(
  750. valueInfo,
  751. constantBounds,
  752. false,
  753. boundConstantBounds.IsConstant(),
  754. boundConstantBounds.IsConstant() && boundConstantBounds.LowerBound() == constantBounds.UpperBound(),
  755. isExplicit);
  756. if(bounds)
  757. {
  758. if(boundValue
  759. ? bounds->SetIsNot(boundValue, isExplicit)
  760. : bounds->SetIsNot(boundConstantBounds.LowerBound(), isExplicit))
  761. {
  762. if(bounds->RequiresIntBoundedValueInfo(valueInfo->Type()))
  763. {
  764. return NewIntBoundedValueInfo(valueInfo, bounds);
  765. }
  766. }
  767. else
  768. {
  769. bounds->Delete();
  770. return nullptr;
  771. }
  772. bounds->Delete();
  773. }
  774. if(!valueInfo->IsInt() || !boundConstantBounds.IsConstant())
  775. {
  776. return nullptr;
  777. }
  778. const int32 constantBound = boundConstantBounds.LowerBound();
  779. // The value is not equal to a constant, so narrow the range if the constant is equal to the value's lower or upper bound
  780. int32 newMin = constantBounds.LowerBound(), newMax = constantBounds.UpperBound();
  781. if(constantBound == newMin)
  782. {
  783. Assert(newMin <= newMax);
  784. if(newMin == newMax)
  785. {
  786. return nullptr;
  787. }
  788. ++newMin;
  789. }
  790. else if(constantBound == newMax)
  791. {
  792. Assert(newMin <= newMax);
  793. if(newMin == newMax)
  794. {
  795. return nullptr;
  796. }
  797. --newMax;
  798. }
  799. else
  800. {
  801. return nullptr;
  802. }
  803. return NewIntRangeValueInfo(valueInfo, newMin, newMax);
  804. }
  805. ValueInfo *GlobOpt::UpdateIntBoundsForGreaterThanOrEqual(
  806. Value *const value,
  807. const IntConstantBounds &constantBounds,
  808. Value *const boundValue,
  809. const IntConstantBounds &boundConstantBounds,
  810. const bool isExplicit)
  811. {
  812. return UpdateIntBoundsForGreaterThanOrEqual(value, constantBounds, boundValue, boundConstantBounds, 0, isExplicit);
  813. }
  814. ValueInfo *GlobOpt::UpdateIntBoundsForGreaterThanOrEqual(
  815. Value *const value,
  816. const IntConstantBounds &constantBounds,
  817. Value *const boundValue,
  818. const IntConstantBounds &boundConstantBounds,
  819. const int boundOffset,
  820. const bool isExplicit)
  821. {
  822. Assert(value || constantBounds.IsConstant());
  823. Assert(boundValue || boundConstantBounds.IsConstant());
  824. if(!value)
  825. {
  826. return nullptr;
  827. }
  828. Assert(!boundValue || value->GetValueNumber() != boundValue->GetValueNumber());
  829. ValueInfo *const valueInfo = value->GetValueInfo();
  830. IntBounds *const bounds =
  831. GetIntBoundsToUpdate(valueInfo, constantBounds, true, boundConstantBounds.IsConstant(), false, isExplicit);
  832. if(bounds)
  833. {
  834. if(boundValue)
  835. {
  836. bounds->SetLowerBound(value->GetValueNumber(), boundValue, boundOffset, isExplicit);
  837. }
  838. else
  839. {
  840. bounds->SetLowerBound(boundConstantBounds.LowerBound(), boundOffset);
  841. }
  842. if(bounds->RequiresIntBoundedValueInfo(valueInfo->Type()))
  843. {
  844. return NewIntBoundedValueInfo(valueInfo, bounds);
  845. }
  846. bounds->Delete();
  847. }
  848. if(!valueInfo->IsInt())
  849. {
  850. return nullptr;
  851. }
  852. int32 adjustedBoundMin;
  853. if(boundOffset == 0)
  854. {
  855. adjustedBoundMin = boundConstantBounds.LowerBound();
  856. }
  857. else if(boundOffset == 1)
  858. {
  859. if(boundConstantBounds.LowerBound() + 1 <= boundConstantBounds.LowerBound())
  860. {
  861. return nullptr;
  862. }
  863. adjustedBoundMin = boundConstantBounds.LowerBound() + 1;
  864. }
  865. else if(Int32Math::Add(boundConstantBounds.LowerBound(), boundOffset, &adjustedBoundMin))
  866. {
  867. return nullptr;
  868. }
  869. const int32 newMin = max(constantBounds.LowerBound(), adjustedBoundMin);
  870. return
  871. newMin <= constantBounds.UpperBound()
  872. ? NewIntRangeValueInfo(valueInfo, newMin, constantBounds.UpperBound())
  873. : nullptr;
  874. }
  875. ValueInfo *GlobOpt::UpdateIntBoundsForGreaterThan(
  876. Value *const value,
  877. const IntConstantBounds &constantBounds,
  878. Value *const boundValue,
  879. const IntConstantBounds &boundConstantBounds,
  880. const bool isExplicit)
  881. {
  882. return UpdateIntBoundsForGreaterThanOrEqual(value, constantBounds, boundValue, boundConstantBounds, 1, isExplicit);
  883. }
  884. ValueInfo *GlobOpt::UpdateIntBoundsForLessThanOrEqual(
  885. Value *const value,
  886. const IntConstantBounds &constantBounds,
  887. Value *const boundValue,
  888. const IntConstantBounds &boundConstantBounds,
  889. const bool isExplicit)
  890. {
  891. return UpdateIntBoundsForLessThanOrEqual(value, constantBounds, boundValue, boundConstantBounds, 0, isExplicit);
  892. }
  893. ValueInfo *GlobOpt::UpdateIntBoundsForLessThanOrEqual(
  894. Value *const value,
  895. const IntConstantBounds &constantBounds,
  896. Value *const boundValue,
  897. const IntConstantBounds &boundConstantBounds,
  898. const int boundOffset,
  899. const bool isExplicit)
  900. {
  901. Assert(value || constantBounds.IsConstant());
  902. Assert(boundValue || boundConstantBounds.IsConstant());
  903. if(!value)
  904. {
  905. return nullptr;
  906. }
  907. Assert(!boundValue || value->GetValueNumber() != boundValue->GetValueNumber());
  908. ValueInfo *const valueInfo = value->GetValueInfo();
  909. IntBounds *const bounds =
  910. GetIntBoundsToUpdate(valueInfo, constantBounds, true, boundConstantBounds.IsConstant(), true, isExplicit);
  911. if(bounds)
  912. {
  913. if(boundValue)
  914. {
  915. bounds->SetUpperBound(value->GetValueNumber(), boundValue, boundOffset, isExplicit);
  916. }
  917. else
  918. {
  919. bounds->SetUpperBound(boundConstantBounds.LowerBound(), boundOffset, isExplicit);
  920. }
  921. if(bounds->RequiresIntBoundedValueInfo(valueInfo->Type()))
  922. {
  923. return NewIntBoundedValueInfo(valueInfo, bounds);
  924. }
  925. bounds->Delete();
  926. }
  927. if(!valueInfo->IsInt())
  928. {
  929. return nullptr;
  930. }
  931. int32 adjustedBoundMax;
  932. if(boundOffset == 0)
  933. {
  934. adjustedBoundMax = boundConstantBounds.UpperBound();
  935. }
  936. else if(boundOffset == -1)
  937. {
  938. if(boundConstantBounds.UpperBound() - 1 >= boundConstantBounds.UpperBound())
  939. {
  940. return nullptr;
  941. }
  942. adjustedBoundMax = boundConstantBounds.UpperBound() - 1;
  943. }
  944. else if(Int32Math::Add(boundConstantBounds.UpperBound(), boundOffset, &adjustedBoundMax))
  945. {
  946. return nullptr;
  947. }
  948. const int32 newMax = min(constantBounds.UpperBound(), adjustedBoundMax);
  949. return
  950. newMax >= constantBounds.LowerBound()
  951. ? NewIntRangeValueInfo(valueInfo, constantBounds.LowerBound(), newMax)
  952. : nullptr;
  953. }
  954. ValueInfo *GlobOpt::UpdateIntBoundsForLessThan(
  955. Value *const value,
  956. const IntConstantBounds &constantBounds,
  957. Value *const boundValue,
  958. const IntConstantBounds &boundConstantBounds,
  959. const bool isExplicit)
  960. {
  961. return UpdateIntBoundsForLessThanOrEqual(value, constantBounds, boundValue, boundConstantBounds, -1, isExplicit);
  962. }
  963. void GlobOpt::TrackIntSpecializedAddSubConstant(
  964. IR::Instr *const instr,
  965. const AddSubConstantInfo *const addSubConstantInfo,
  966. Value *const dstValue,
  967. const bool updateSourceBounds)
  968. {
  969. Assert(instr);
  970. Assert(dstValue);
  971. if(addSubConstantInfo)
  972. {
  973. Assert(addSubConstantInfo->HasInfo());
  974. Assert(!ignoredIntOverflowForCurrentInstr);
  975. do
  976. {
  977. if(!IsLoopPrePass() || !DoBoundCheckHoist())
  978. {
  979. break;
  980. }
  981. Assert(
  982. instr->m_opcode == Js::OpCode::Incr_A ||
  983. instr->m_opcode == Js::OpCode::Decr_A ||
  984. instr->m_opcode == Js::OpCode::Add_A ||
  985. instr->m_opcode == Js::OpCode::Sub_A);
  986. StackSym *sym = instr->GetDst()->AsRegOpnd()->m_sym;
  987. bool isPostfixIncDecPattern = false;
  988. if(addSubConstantInfo->SrcSym() != sym)
  989. {
  990. // Check for the following patterns.
  991. //
  992. // This pattern is used for postfix inc/dec operators:
  993. // s2 = Conv_Num s1
  994. // s1 = Inc s2
  995. //
  996. // This pattern is used for prefix inc/dec operators:
  997. // s2 = Inc s1
  998. // s1 = Ld s2
  999. IR::Instr *const prevInstr = instr->m_prev;
  1000. Assert(prevInstr);
  1001. if(prevInstr->m_opcode == Js::OpCode::Conv_Num &&
  1002. prevInstr->GetSrc1()->IsRegOpnd() &&
  1003. prevInstr->GetSrc1()->AsRegOpnd()->m_sym == sym &&
  1004. prevInstr->GetDst()->AsRegOpnd()->m_sym == addSubConstantInfo->SrcSym())
  1005. {
  1006. // s2 will get a new value number, since Conv_Num cannot transfer in the prepass. For the purposes of
  1007. // induction variable tracking however, it doesn't matter, so record this case and use s1's value in the
  1008. // current block.
  1009. isPostfixIncDecPattern = true;
  1010. }
  1011. else
  1012. {
  1013. IR::Instr *const nextInstr = instr->m_next;
  1014. Assert(nextInstr);
  1015. if(nextInstr->m_opcode != Js::OpCode::Ld_A ||
  1016. !nextInstr->GetSrc1()->IsRegOpnd() ||
  1017. nextInstr->GetSrc1()->AsRegOpnd()->m_sym != sym)
  1018. {
  1019. break;
  1020. }
  1021. sym = addSubConstantInfo->SrcSym();
  1022. if(nextInstr->GetDst()->AsRegOpnd()->m_sym != sym)
  1023. {
  1024. break;
  1025. }
  1026. // In the prefix inc/dec pattern, the result of Ld currently gets a new value number, which will cause the
  1027. // induction variable info to become indeterminate. Indicate that the value number should be updated in the
  1028. // induction variable info.
  1029. // Consider: Remove this once loop prepass value transfer scheme is fixed
  1030. updateInductionVariableValueNumber = true;
  1031. }
  1032. }
  1033. // Track induction variable info
  1034. ValueNumber srcValueNumber;
  1035. if(isPostfixIncDecPattern)
  1036. {
  1037. Value *const value = FindValue(sym);
  1038. Assert(value);
  1039. srcValueNumber = value->GetValueNumber();
  1040. }
  1041. else
  1042. {
  1043. srcValueNumber = addSubConstantInfo->SrcValue()->GetValueNumber();
  1044. }
  1045. InductionVariableSet *const inductionVariables = blockData.inductionVariables;
  1046. Assert(inductionVariables);
  1047. InductionVariable *inductionVariable;
  1048. if(!inductionVariables->TryGetReference(sym->m_id, &inductionVariable))
  1049. {
  1050. // Only track changes in the current loop's prepass. In subsequent prepasses, the info is only being propagated
  1051. // for use by the parent loop, so changes in the current loop have already been tracked.
  1052. if(prePassLoop != currentBlock->loop)
  1053. {
  1054. updateInductionVariableValueNumber = false;
  1055. break;
  1056. }
  1057. // Ensure that the sym is live in the landing pad, and that its value has not changed in an unknown way yet
  1058. Value *const landingPadValue = FindValue(currentBlock->loop->landingPad->globOptData.symToValueMap, sym);
  1059. if(!landingPadValue || srcValueNumber != landingPadValue->GetValueNumber())
  1060. {
  1061. updateInductionVariableValueNumber = false;
  1062. break;
  1063. }
  1064. inductionVariables->Add(
  1065. InductionVariable(sym, dstValue->GetValueNumber(), addSubConstantInfo->Offset()));
  1066. break;
  1067. }
  1068. if(!inductionVariable->IsChangeDeterminate())
  1069. {
  1070. updateInductionVariableValueNumber = false;
  1071. break;
  1072. }
  1073. if(srcValueNumber != inductionVariable->SymValueNumber())
  1074. {
  1075. // The sym's value has changed since the last time induction variable info was recorded for it. Due to the
  1076. // unknown change, mark the info as indeterminate.
  1077. inductionVariable->SetChangeIsIndeterminate();
  1078. updateInductionVariableValueNumber = false;
  1079. break;
  1080. }
  1081. // Only track changes in the current loop's prepass. In subsequent prepasses, the info is only being propagated for
  1082. // use by the parent loop, so changes in the current loop have already been tracked. Induction variable value
  1083. // numbers are updated as changes occur, but their change bounds are preserved from the first prepass over the loop.
  1084. inductionVariable->SetSymValueNumber(dstValue->GetValueNumber());
  1085. if(prePassLoop != currentBlock->loop)
  1086. {
  1087. break;
  1088. }
  1089. if(!inductionVariable->Add(addSubConstantInfo->Offset()))
  1090. {
  1091. updateInductionVariableValueNumber = false;
  1092. }
  1093. } while(false);
  1094. if(updateSourceBounds && addSubConstantInfo->Offset() != IntConstMin)
  1095. {
  1096. // Track bounds for add or sub with a constant. For instance, consider (b = a + 2). The value of 'b' should track
  1097. // that it is equal to (the value of 'a') + 2. That part has been done above. Similarly, the value of 'a' should
  1098. // also track that it is equal to (the value of 'b') - 2.
  1099. Value *const value = addSubConstantInfo->SrcValue();
  1100. const ValueInfo *const valueInfo = value->GetValueInfo();
  1101. Assert(valueInfo->IsInt());
  1102. IntConstantBounds constantBounds;
  1103. AssertVerify(valueInfo->TryGetIntConstantBounds(&constantBounds));
  1104. IntBounds *const bounds =
  1105. GetIntBoundsToUpdate(
  1106. valueInfo,
  1107. constantBounds,
  1108. true,
  1109. dstValue->GetValueInfo()->HasIntConstantValue(),
  1110. true,
  1111. true);
  1112. if(bounds)
  1113. {
  1114. const ValueNumber valueNumber = value->GetValueNumber();
  1115. const int32 dstOffset = -addSubConstantInfo->Offset();
  1116. bounds->SetLowerBound(valueNumber, dstValue, dstOffset, true);
  1117. bounds->SetUpperBound(valueNumber, dstValue, dstOffset, true);
  1118. ChangeValueInfo(nullptr, value, NewIntBoundedValueInfo(valueInfo, bounds));
  1119. }
  1120. }
  1121. return;
  1122. }
  1123. if(!updateInductionVariableValueNumber)
  1124. {
  1125. return;
  1126. }
  1127. // See comment above where this is set to true
  1128. // Consider: Remove this once loop prepass value transfer scheme is fixed
  1129. updateInductionVariableValueNumber = false;
  1130. Assert(IsLoopPrePass());
  1131. Assert(instr->m_opcode == Js::OpCode::Ld_A);
  1132. Assert(
  1133. instr->m_prev->m_opcode == Js::OpCode::Incr_A ||
  1134. instr->m_prev->m_opcode == Js::OpCode::Decr_A ||
  1135. instr->m_prev->m_opcode == Js::OpCode::Add_A ||
  1136. instr->m_prev->m_opcode == Js::OpCode::Sub_A);
  1137. Assert(instr->m_prev->GetDst()->AsRegOpnd()->m_sym == instr->GetSrc1()->AsRegOpnd()->m_sym);
  1138. InductionVariable *inductionVariable;
  1139. AssertVerify(blockData.inductionVariables->TryGetReference(instr->GetDst()->AsRegOpnd()->m_sym->m_id, &inductionVariable));
  1140. inductionVariable->SetSymValueNumber(dstValue->GetValueNumber());
  1141. }
  1142. void GlobOpt::CloneBoundCheckHoistBlockData(
  1143. BasicBlock *const toBlock,
  1144. GlobOptBlockData *const toData,
  1145. BasicBlock *const fromBlock,
  1146. GlobOptBlockData *const fromData)
  1147. {
  1148. Assert(DoBoundCheckHoist());
  1149. Assert(toBlock);
  1150. Assert(toData);
  1151. Assert(toData == &toBlock->globOptData || toData == &blockData);
  1152. Assert(fromBlock);
  1153. Assert(fromData);
  1154. Assert(fromData == &fromBlock->globOptData);
  1155. Assert(fromData->availableIntBoundChecks);
  1156. toData->availableIntBoundChecks = fromData->availableIntBoundChecks->Clone();
  1157. if(toBlock->isLoopHeader)
  1158. {
  1159. Assert(fromBlock == toBlock->loop->landingPad);
  1160. if(prePassLoop == toBlock->loop)
  1161. {
  1162. // When the current prepass loop is the current loop, the loop header's induction variable set needs to start off
  1163. // empty to track changes in the current loop
  1164. toData->inductionVariables = JitAnew(alloc, InductionVariableSet, alloc);
  1165. return;
  1166. }
  1167. if(!IsLoopPrePass())
  1168. {
  1169. return;
  1170. }
  1171. // After the prepass on this loop, if we're still in a prepass, this must be an inner loop. Merge the landing pad info
  1172. // for use by the parent loop.
  1173. Assert(fromBlock->loop);
  1174. Assert(fromData->inductionVariables);
  1175. toData->inductionVariables = fromData->inductionVariables->Clone();
  1176. return;
  1177. }
  1178. if(!toBlock->loop || !IsLoopPrePass())
  1179. {
  1180. return;
  1181. }
  1182. Assert(fromBlock->loop);
  1183. Assert(toBlock->loop->IsDescendentOrSelf(fromBlock->loop));
  1184. Assert(fromData->inductionVariables);
  1185. toData->inductionVariables = fromData->inductionVariables->Clone();
  1186. }
  1187. void GlobOpt::MergeBoundCheckHoistBlockData(
  1188. BasicBlock *const toBlock,
  1189. GlobOptBlockData *const toData,
  1190. BasicBlock *const fromBlock,
  1191. GlobOptBlockData *const fromData)
  1192. {
  1193. Assert(DoBoundCheckHoist());
  1194. Assert(toBlock);
  1195. Assert(toData);
  1196. Assert(toData == &toBlock->globOptData || toData == &blockData);
  1197. Assert(fromBlock);
  1198. Assert(fromData);
  1199. Assert(fromData == &fromBlock->globOptData);
  1200. Assert(toData->availableIntBoundChecks);
  1201. for(auto it = toData->availableIntBoundChecks->GetIteratorWithRemovalSupport(); it.IsValid(); it.MoveNext())
  1202. {
  1203. const IntBoundCheck &toDataIntBoundCheck = it.CurrentValue();
  1204. const IntBoundCheck *fromDataIntBoundCheck;
  1205. if(!fromData->availableIntBoundChecks->TryGetReference(
  1206. toDataIntBoundCheck.CompatibilityId(),
  1207. &fromDataIntBoundCheck) ||
  1208. fromDataIntBoundCheck->Instr() != toDataIntBoundCheck.Instr())
  1209. {
  1210. it.RemoveCurrent();
  1211. }
  1212. }
  1213. InductionVariableSet *mergeInductionVariablesInto;
  1214. if(toBlock->isLoopHeader)
  1215. {
  1216. Assert(fromBlock->loop == toBlock->loop); // The flow is such that you cannot have back-edges from an inner loop
  1217. if(IsLoopPrePass())
  1218. {
  1219. // Collect info for the parent loop. Any changes to induction variables in this inner loop need to be expanded in
  1220. // the same direction for the parent loop, so merge expanded info from back-edges. Info about induction variables
  1221. // that changed before the loop but not inside the loop, can be kept intact because the landing pad dominates the
  1222. // loop.
  1223. Assert(prePassLoop != toBlock->loop);
  1224. Assert(fromData->inductionVariables);
  1225. Assert(toData->inductionVariables);
  1226. InductionVariableSet *const mergedInductionVariables = toData->inductionVariables;
  1227. for(auto it = fromData->inductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
  1228. {
  1229. InductionVariable backEdgeInductionVariable = it.CurrentValue();
  1230. backEdgeInductionVariable.ExpandInnerLoopChange();
  1231. StackSym *const sym = backEdgeInductionVariable.Sym();
  1232. InductionVariable *mergedInductionVariable;
  1233. if(mergedInductionVariables->TryGetReference(sym->m_id, &mergedInductionVariable))
  1234. {
  1235. mergedInductionVariable->Merge(backEdgeInductionVariable);
  1236. continue;
  1237. }
  1238. // Ensure that the sym is live in the parent loop's landing pad, and that its value has not changed in an
  1239. // unknown way between the parent loop's landing pad and the current loop's landing pad.
  1240. Value *const parentLandingPadValue =
  1241. FindValue(currentBlock->loop->parent->landingPad->globOptData.symToValueMap, sym);
  1242. if(!parentLandingPadValue)
  1243. {
  1244. continue;
  1245. }
  1246. Value *const landingPadValue = FindValue(currentBlock->loop->landingPad->globOptData.symToValueMap, sym);
  1247. Assert(landingPadValue);
  1248. if(landingPadValue->GetValueNumber() == parentLandingPadValue->GetValueNumber())
  1249. {
  1250. mergedInductionVariables->Add(backEdgeInductionVariable);
  1251. }
  1252. }
  1253. return;
  1254. }
  1255. // Collect info for the current loop. We want to merge only the back-edge info without the landing pad info, such that
  1256. // the loop's induction variable set reflects changes made inside this loop.
  1257. Assert(fromData->inductionVariables);
  1258. InductionVariableSet *&loopInductionVariables = toBlock->loop->inductionVariables;
  1259. if(!loopInductionVariables)
  1260. {
  1261. loopInductionVariables = fromData->inductionVariables->Clone();
  1262. return;
  1263. }
  1264. mergeInductionVariablesInto = loopInductionVariables;
  1265. }
  1266. else if(toBlock->loop && IsLoopPrePass())
  1267. {
  1268. Assert(fromBlock->loop);
  1269. Assert(toBlock->loop->IsDescendentOrSelf(fromBlock->loop));
  1270. mergeInductionVariablesInto = toData->inductionVariables;
  1271. }
  1272. else
  1273. {
  1274. return;
  1275. }
  1276. const InductionVariableSet *const fromDataInductionVariables = fromData->inductionVariables;
  1277. InductionVariableSet *const mergedInductionVariables = mergeInductionVariablesInto;
  1278. Assert(fromDataInductionVariables);
  1279. Assert(mergedInductionVariables);
  1280. for(auto it = mergedInductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
  1281. {
  1282. InductionVariable &mergedInductionVariable = it.CurrentValueReference();
  1283. if(!mergedInductionVariable.IsChangeDeterminate())
  1284. {
  1285. continue;
  1286. }
  1287. StackSym *const sym = mergedInductionVariable.Sym();
  1288. const InductionVariable *fromDataInductionVariable;
  1289. if(fromDataInductionVariables->TryGetReference(sym->m_id, &fromDataInductionVariable))
  1290. {
  1291. mergedInductionVariable.Merge(*fromDataInductionVariable);
  1292. continue;
  1293. }
  1294. // Ensure that the sym is live in the landing pad, and that its value has not changed in an unknown way yet on the path
  1295. // where the sym is not already marked as an induction variable.
  1296. Value *const fromDataValue = FindValue(fromData->symToValueMap, sym);
  1297. if(fromDataValue)
  1298. {
  1299. Value *const landingPadValue = FindValue(toBlock->loop->landingPad->globOptData.symToValueMap, sym);
  1300. if(landingPadValue && fromDataValue->GetValueNumber() == landingPadValue->GetValueNumber())
  1301. {
  1302. mergedInductionVariable.Merge(InductionVariable(sym, ZeroValueNumber, 0));
  1303. continue;
  1304. }
  1305. }
  1306. mergedInductionVariable.SetChangeIsIndeterminate();
  1307. }
  1308. for(auto it = fromDataInductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
  1309. {
  1310. const InductionVariable &fromDataInductionVariable = it.CurrentValue();
  1311. StackSym *const sym = fromDataInductionVariable.Sym();
  1312. if(mergedInductionVariables->ContainsKey(sym->m_id))
  1313. {
  1314. continue;
  1315. }
  1316. // Ensure that the sym is live in the landing pad, and that its value has not changed in an unknown way yet on the path
  1317. // where the sym is not already marked as an induction variable.
  1318. bool indeterminate = true;
  1319. Value *const toDataValue = FindValue(toData->symToValueMap, sym);
  1320. if(toDataValue)
  1321. {
  1322. Value *const landingPadValue = FindValue(toBlock->loop->landingPad->globOptData.symToValueMap, sym);
  1323. if(landingPadValue && toDataValue->GetValueNumber() == landingPadValue->GetValueNumber())
  1324. {
  1325. indeterminate = false;
  1326. }
  1327. }
  1328. InductionVariable mergedInductionVariable(sym, ZeroValueNumber, 0);
  1329. if(indeterminate)
  1330. {
  1331. mergedInductionVariable.SetChangeIsIndeterminate();
  1332. }
  1333. else
  1334. {
  1335. mergedInductionVariable.Merge(fromDataInductionVariable);
  1336. }
  1337. mergedInductionVariables->Add(mergedInductionVariable);
  1338. }
  1339. }
  1340. void GlobOpt::DetectUnknownChangesToInductionVariables(GlobOptBlockData *const blockData)
  1341. {
  1342. Assert(DoBoundCheckHoist());
  1343. Assert(IsLoopPrePass());
  1344. Assert(blockData);
  1345. Assert(blockData->inductionVariables);
  1346. // Check induction variable value numbers, and mark those that changed in an unknown way as indeterminate. They must remain
  1347. // in the set though, for merging purposes.
  1348. GlobHashTable *const symToValueMap = blockData->symToValueMap;
  1349. for(auto it = blockData->inductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
  1350. {
  1351. InductionVariable &inductionVariable = it.CurrentValueReference();
  1352. if(!inductionVariable.IsChangeDeterminate())
  1353. {
  1354. continue;
  1355. }
  1356. Value *const value = FindValue(symToValueMap, inductionVariable.Sym());
  1357. if(!value || value->GetValueNumber() != inductionVariable.SymValueNumber())
  1358. {
  1359. inductionVariable.SetChangeIsIndeterminate();
  1360. }
  1361. }
  1362. }
  1363. void GlobOpt::SetInductionVariableValueNumbers(GlobOptBlockData *const blockData)
  1364. {
  1365. Assert(DoBoundCheckHoist());
  1366. Assert(IsLoopPrePass());
  1367. Assert(blockData == &this->blockData);
  1368. Assert(blockData->inductionVariables);
  1369. // Now that all values have been merged, update value numbers in the induction variable info.
  1370. GlobHashTable *const symToValueMap = blockData->symToValueMap;
  1371. for(auto it = blockData->inductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
  1372. {
  1373. InductionVariable &inductionVariable = it.CurrentValueReference();
  1374. if(!inductionVariable.IsChangeDeterminate())
  1375. {
  1376. continue;
  1377. }
  1378. Value *const value = FindValue(symToValueMap, inductionVariable.Sym());
  1379. if(value)
  1380. {
  1381. inductionVariable.SetSymValueNumber(value->GetValueNumber());
  1382. }
  1383. else
  1384. {
  1385. inductionVariable.SetChangeIsIndeterminate();
  1386. }
  1387. }
  1388. }
  1389. void GlobOpt::FinalizeInductionVariables(Loop *const loop, GlobOptBlockData *const headerData)
  1390. {
  1391. Assert(DoBoundCheckHoist());
  1392. Assert(!IsLoopPrePass());
  1393. Assert(loop);
  1394. Assert(loop->GetHeadBlock() == currentBlock);
  1395. Assert(loop->inductionVariables);
  1396. Assert(currentBlock->isLoopHeader);
  1397. Assert(headerData == &this->blockData);
  1398. // Clean up induction variables and for each, install a relationship between its values inside and outside the loop.
  1399. GlobHashTable *const symToValueMap = headerData->symToValueMap;
  1400. GlobOptBlockData &landingPadBlockData = loop->landingPad->globOptData;
  1401. GlobHashTable *const landingPadSymToValueMap = landingPadBlockData.symToValueMap;
  1402. for(auto it = loop->inductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
  1403. {
  1404. InductionVariable &inductionVariable = it.CurrentValueReference();
  1405. if(!inductionVariable.IsChangeDeterminate())
  1406. {
  1407. continue;
  1408. }
  1409. if(!inductionVariable.IsChangeUnidirectional())
  1410. {
  1411. inductionVariable.SetChangeIsIndeterminate();
  1412. continue;
  1413. }
  1414. StackSym *const sym = inductionVariable.Sym();
  1415. if(!IsInt32TypeSpecialized(sym, headerData))
  1416. {
  1417. inductionVariable.SetChangeIsIndeterminate();
  1418. continue;
  1419. }
  1420. Assert(IsInt32TypeSpecialized(sym, &landingPadBlockData));
  1421. Value *const value = FindValue(symToValueMap, sym);
  1422. if(!value)
  1423. {
  1424. inductionVariable.SetChangeIsIndeterminate();
  1425. continue;
  1426. }
  1427. Value *const landingPadValue = FindValue(landingPadSymToValueMap, sym);
  1428. Assert(landingPadValue);
  1429. IntConstantBounds constantBounds, landingPadConstantBounds;
  1430. AssertVerify(value->GetValueInfo()->TryGetIntConstantBounds(&constantBounds));
  1431. AssertVerify(landingPadValue->GetValueInfo()->TryGetIntConstantBounds(&landingPadConstantBounds, true));
  1432. // For an induction variable i, update the value of i inside the loop to indicate that it is bounded by the value of i
  1433. // just before the loop.
  1434. if(inductionVariable.ChangeBounds().LowerBound() >= 0)
  1435. {
  1436. ValueInfo *const newValueInfo =
  1437. UpdateIntBoundsForGreaterThanOrEqual(value, constantBounds, landingPadValue, landingPadConstantBounds, true);
  1438. ChangeValueInfo(nullptr, value, newValueInfo);
  1439. if(inductionVariable.ChangeBounds().UpperBound() == 0)
  1440. {
  1441. AssertVerify(newValueInfo->TryGetIntConstantBounds(&constantBounds, true));
  1442. }
  1443. }
  1444. if(inductionVariable.ChangeBounds().UpperBound() <= 0)
  1445. {
  1446. ValueInfo *const newValueInfo =
  1447. UpdateIntBoundsForLessThanOrEqual(value, constantBounds, landingPadValue, landingPadConstantBounds, true);
  1448. ChangeValueInfo(nullptr, value, newValueInfo);
  1449. }
  1450. }
  1451. }
  1452. bool GlobOpt::DetermineSymBoundOffsetOrValueRelativeToLandingPad(
  1453. StackSym *const sym,
  1454. const bool landingPadValueIsLowerBound,
  1455. ValueInfo *const valueInfo,
  1456. const IntBounds *const bounds,
  1457. GlobHashTable *const landingPadSymToValueMap,
  1458. int *const boundOffsetOrValueRef)
  1459. {
  1460. Assert(sym);
  1461. Assert(!sym->IsTypeSpec());
  1462. Assert(valueInfo);
  1463. Assert(landingPadSymToValueMap);
  1464. Assert(boundOffsetOrValueRef);
  1465. Assert(valueInfo->IsInt());
  1466. int constantValue;
  1467. if(valueInfo->TryGetIntConstantValue(&constantValue))
  1468. {
  1469. // The sym's constant value is the constant bound value, so just return that. This is possible in loops such as
  1470. // for(; i === 1; ++i){...}, where 'i' is an induction variable but has a constant value inside the loop, or in blocks
  1471. // inside the loop such as if(i === 1){...}
  1472. *boundOffsetOrValueRef = constantValue;
  1473. return true; // 'true' indicates that *boundOffsetOrValueRef contains the constant bound value
  1474. }
  1475. Value *const landingPadValue = FindValue(landingPadSymToValueMap, sym);
  1476. Assert(landingPadValue);
  1477. Assert(landingPadValue->GetValueInfo()->IsInt());
  1478. int landingPadConstantValue;
  1479. if(landingPadValue->GetValueInfo()->TryGetIntConstantValue(&landingPadConstantValue))
  1480. {
  1481. // The sym's bound already takes the landing pad constant value into consideration, unless the landing pad value was
  1482. // updated to have a more aggressive range (and hence, now a constant value) as part of hoisting a bound check or some
  1483. // other hoisting operation. The sym's bound also takes into consideration the change to the sym so far inside the loop,
  1484. // and the landing pad constant value does not, so use the sym's bound by default.
  1485. int constantBound;
  1486. if(bounds)
  1487. {
  1488. constantBound = landingPadValueIsLowerBound ? bounds->ConstantLowerBound() : bounds->ConstantUpperBound();
  1489. }
  1490. else
  1491. {
  1492. AssertVerify(
  1493. landingPadValueIsLowerBound
  1494. ? valueInfo->TryGetIntConstantLowerBound(&constantBound)
  1495. : valueInfo->TryGetIntConstantUpperBound(&constantBound));
  1496. }
  1497. if(landingPadValueIsLowerBound ? landingPadConstantValue > constantBound : landingPadConstantValue < constantBound)
  1498. {
  1499. // The landing pad value became a constant value as part of a hoisting operation. The landing pad constant value is
  1500. // a more aggressive bound, so use that instead, and take into consideration the change to the sym so far inside the
  1501. // loop, using the relative bound to the landing pad value.
  1502. AnalysisAssert(bounds);
  1503. const ValueRelativeOffset *bound;
  1504. AssertVerify(
  1505. (landingPadValueIsLowerBound ? bounds->RelativeLowerBounds() : bounds->RelativeUpperBounds())
  1506. .TryGetReference(landingPadValue->GetValueNumber(), &bound));
  1507. constantBound = landingPadConstantValue + bound->Offset();
  1508. }
  1509. *boundOffsetOrValueRef = constantBound;
  1510. return true; // 'true' indicates that *boundOffsetOrValueRef contains the constant bound value
  1511. }
  1512. AnalysisAssert(bounds);
  1513. const ValueRelativeOffset *bound;
  1514. AssertVerify(
  1515. (landingPadValueIsLowerBound ? bounds->RelativeLowerBounds() : bounds->RelativeUpperBounds())
  1516. .TryGetReference(landingPadValue->GetValueNumber(), &bound));
  1517. *boundOffsetOrValueRef = bound->Offset();
  1518. // 'false' indicates that *boundOffsetOrValueRef contains the bound offset, which must be added to the sym's value in the
  1519. // landing pad to get the bound value
  1520. return false;
  1521. }
  1522. void GlobOpt::DetermineDominatingLoopCountableBlock(Loop *const loop, BasicBlock *const headerBlock)
  1523. {
  1524. Assert(DoLoopCountBasedBoundCheckHoist());
  1525. Assert(!IsLoopPrePass());
  1526. Assert(loop);
  1527. Assert(headerBlock);
  1528. Assert(headerBlock->isLoopHeader);
  1529. Assert(headerBlock->loop == loop);
  1530. // Determine if the loop header has a unique successor that is inside the loop. If so, then all other paths out of the loop
  1531. // header exit the loop, allowing a loop count to be established and used from the unique in-loop successor block.
  1532. Assert(!loop->dominatingLoopCountableBlock);
  1533. FOREACH_SUCCESSOR_BLOCK(successor, headerBlock)
  1534. {
  1535. if(successor->loop != loop)
  1536. {
  1537. Assert(!successor->loop || successor->loop->IsDescendentOrSelf(loop->parent));
  1538. continue;
  1539. }
  1540. if(loop->dominatingLoopCountableBlock)
  1541. {
  1542. // Found a second successor inside the loop
  1543. loop->dominatingLoopCountableBlock = nullptr;
  1544. break;
  1545. }
  1546. loop->dominatingLoopCountableBlock = successor;
  1547. } NEXT_SUCCESSOR_BLOCK;
  1548. }
  1549. void GlobOpt::DetermineLoopCount(Loop *const loop)
  1550. {
  1551. Assert(DoLoopCountBasedBoundCheckHoist());
  1552. Assert(loop);
  1553. GlobOptBlockData &landingPadBlockData = loop->landingPad->globOptData;
  1554. GlobHashTable *const landingPadSymToValueMap = landingPadBlockData.symToValueMap;
  1555. const InductionVariableSet *const inductionVariables = loop->inductionVariables;
  1556. Assert(inductionVariables);
  1557. for(auto inductionVariablesIterator = inductionVariables->GetIterator(); inductionVariablesIterator.IsValid(); inductionVariablesIterator.MoveNext())
  1558. {
  1559. InductionVariable &inductionVariable = inductionVariablesIterator.CurrentValueReference();
  1560. if(!inductionVariable.IsChangeDeterminate())
  1561. {
  1562. continue;
  1563. }
  1564. // Determine the minimum-magnitude change per iteration, and verify that the change is nonzero and finite
  1565. Assert(inductionVariable.IsChangeUnidirectional());
  1566. int minMagnitudeChange = inductionVariable.ChangeBounds().LowerBound();
  1567. if(minMagnitudeChange >= 0)
  1568. {
  1569. if(minMagnitudeChange == 0 || minMagnitudeChange == IntConstMax)
  1570. {
  1571. continue;
  1572. }
  1573. }
  1574. else
  1575. {
  1576. minMagnitudeChange = inductionVariable.ChangeBounds().UpperBound();
  1577. Assert(minMagnitudeChange <= 0);
  1578. if(minMagnitudeChange == 0 || minMagnitudeChange == IntConstMin)
  1579. {
  1580. continue;
  1581. }
  1582. }
  1583. StackSym *const inductionVariableVarSym = inductionVariable.Sym();
  1584. if(!IsInt32TypeSpecialized(inductionVariableVarSym, &blockData))
  1585. {
  1586. inductionVariable.SetChangeIsIndeterminate();
  1587. continue;
  1588. }
  1589. Assert(IsInt32TypeSpecialized(inductionVariableVarSym, &landingPadBlockData));
  1590. Value *const inductionVariableValue = FindValue(inductionVariableVarSym);
  1591. if(!inductionVariableValue)
  1592. {
  1593. inductionVariable.SetChangeIsIndeterminate();
  1594. continue;
  1595. }
  1596. ValueInfo *const inductionVariableValueInfo = inductionVariableValue->GetValueInfo();
  1597. const IntBounds *const inductionVariableBounds =
  1598. inductionVariableValueInfo->IsIntBounded() ? inductionVariableValueInfo->AsIntBounded()->Bounds() : nullptr;
  1599. // Look for an invariant bound in the direction of change
  1600. StackSym *boundBaseVarSym = nullptr;
  1601. int boundOffset = 0;
  1602. {
  1603. bool foundBound = false;
  1604. if(inductionVariableBounds)
  1605. {
  1606. // Look for a relative bound
  1607. for(auto it =
  1608. (
  1609. minMagnitudeChange >= 0
  1610. ? inductionVariableBounds->RelativeUpperBounds()
  1611. : inductionVariableBounds->RelativeLowerBounds()
  1612. ).GetIterator();
  1613. it.IsValid();
  1614. it.MoveNext())
  1615. {
  1616. const ValueRelativeOffset &bound = it.CurrentValue();
  1617. StackSym *currentBoundBaseVarSym = bound.BaseSym();
  1618. if(!currentBoundBaseVarSym || !IsInt32TypeSpecialized(currentBoundBaseVarSym, &landingPadBlockData))
  1619. {
  1620. continue;
  1621. }
  1622. Value *const boundBaseValue = FindValue(currentBoundBaseVarSym);
  1623. const ValueNumber boundBaseValueNumber = bound.BaseValueNumber();
  1624. if(!boundBaseValue || boundBaseValue->GetValueNumber() != boundBaseValueNumber)
  1625. {
  1626. continue;
  1627. }
  1628. Value *const landingPadBoundBaseValue = FindValue(landingPadSymToValueMap, currentBoundBaseVarSym);
  1629. if(!landingPadBoundBaseValue || landingPadBoundBaseValue->GetValueNumber() != boundBaseValueNumber)
  1630. {
  1631. continue;
  1632. }
  1633. if (foundBound)
  1634. {
  1635. // We used to pick the first usable bound we saw in this list, but the list contains both
  1636. // the loop counter's bound *and* relative bounds of the primary bound. These secondary bounds
  1637. // are not guaranteed to be correct, so if the bound we found on a previous iteration is itself
  1638. // a bound for the current bound, then choose the current bound.
  1639. if (!boundBaseValue->GetValueInfo()->IsIntBounded())
  1640. {
  1641. continue;
  1642. }
  1643. // currentBoundBaseVarSym has relative bounds of its own. If we find the saved boundBaseVarSym
  1644. // in currentBoundBaseVarSym's relative bounds list, let currentBoundBaseVarSym be the
  1645. // chosen bound.
  1646. const IntBounds *const currentBounds = boundBaseValue->GetValueInfo()->AsIntBounded()->Bounds();
  1647. bool foundSecondaryBound = false;
  1648. for (auto it2 =
  1649. (
  1650. minMagnitudeChange >= 0
  1651. ? currentBounds->RelativeUpperBounds()
  1652. : currentBounds->RelativeLowerBounds()
  1653. ).GetIterator();
  1654. it2.IsValid();
  1655. it2.MoveNext())
  1656. {
  1657. const ValueRelativeOffset &bound2 = it2.CurrentValue();
  1658. if (bound2.BaseSym() == boundBaseVarSym)
  1659. {
  1660. // boundBaseVarSym is a secondary bound. Use currentBoundBaseVarSym instead.
  1661. foundSecondaryBound = true;
  1662. break;
  1663. }
  1664. }
  1665. if (!foundSecondaryBound)
  1666. {
  1667. // boundBaseVarSym is not a relative bound of currentBoundBaseVarSym, so continue
  1668. // to use boundBaseVarSym.
  1669. continue;
  1670. }
  1671. }
  1672. boundBaseVarSym = bound.BaseSym();
  1673. boundOffset = bound.Offset();
  1674. foundBound = true;
  1675. }
  1676. }
  1677. if(!foundBound)
  1678. {
  1679. // No useful relative bound found; look for a constant bound. Exclude large constant bounds established implicitly by
  1680. // <, <=, >, and >=. For example, for a loop condition (i < n), if 'n' is not invariant and hence can't be used,
  1681. // 'i' will still have a constant upper bound of (int32 max - 1) that should be excluded as it's too large. Any
  1682. // other constant bounds must have been established explicitly by the loop condition, and are safe to use.
  1683. boundBaseVarSym = nullptr;
  1684. if(minMagnitudeChange >= 0)
  1685. {
  1686. if(inductionVariableBounds)
  1687. {
  1688. boundOffset = inductionVariableBounds->ConstantUpperBound();
  1689. }
  1690. else
  1691. {
  1692. AssertVerify(inductionVariableValueInfo->TryGetIntConstantUpperBound(&boundOffset));
  1693. }
  1694. if(boundOffset >= IntConstMax - 1)
  1695. {
  1696. continue;
  1697. }
  1698. }
  1699. else
  1700. {
  1701. if(inductionVariableBounds)
  1702. {
  1703. boundOffset = inductionVariableBounds->ConstantLowerBound();
  1704. }
  1705. else
  1706. {
  1707. AssertVerify(inductionVariableValueInfo->TryGetIntConstantLowerBound(&boundOffset));
  1708. }
  1709. if(boundOffset <= IntConstMin + 1)
  1710. {
  1711. continue;
  1712. }
  1713. }
  1714. }
  1715. }
  1716. // Determine if the induction variable already changed in the loop, and by how much
  1717. int inductionVariableOffset;
  1718. StackSym *inductionVariableSymToAdd;
  1719. if(DetermineSymBoundOffsetOrValueRelativeToLandingPad(
  1720. inductionVariableVarSym,
  1721. minMagnitudeChange >= 0,
  1722. inductionVariableValueInfo,
  1723. inductionVariableBounds,
  1724. landingPadSymToValueMap,
  1725. &inductionVariableOffset))
  1726. {
  1727. // The bound value is constant
  1728. inductionVariableSymToAdd = nullptr;
  1729. }
  1730. else
  1731. {
  1732. // The bound value is not constant, the offset needs to be added to the induction variable in the landing pad
  1733. inductionVariableSymToAdd = inductionVariableVarSym->GetInt32EquivSym(nullptr);
  1734. Assert(inductionVariableSymToAdd);
  1735. }
  1736. // Int operands are required
  1737. StackSym *boundBaseSym;
  1738. if(boundBaseVarSym)
  1739. {
  1740. boundBaseSym = boundBaseVarSym->IsVar() ? boundBaseVarSym->GetInt32EquivSym(nullptr) : boundBaseVarSym;
  1741. Assert(boundBaseSym);
  1742. Assert(boundBaseSym->GetType() == TyInt32 || boundBaseSym->GetType() == TyUint32);
  1743. }
  1744. else
  1745. {
  1746. boundBaseSym = nullptr;
  1747. }
  1748. // The loop count is computed as follows. We're actually computing the loop count minus one, because the value is used
  1749. // to determine the bound of a secondary induction variable in its direction of change, and at that point the secondary
  1750. // induction variable's information already accounts for changes in the first loop iteration.
  1751. //
  1752. // If the induction variable increases in the loop:
  1753. // loopCountMinusOne = (upperBound - inductionVariable) / abs(minMagnitudeChange)
  1754. // Or more precisely:
  1755. // loopCountMinusOne =
  1756. // ((boundBase - inductionVariable) + (boundOffset - inductionVariableOffset)) / abs(minMagnitudeChange)
  1757. //
  1758. // If the induction variable decreases in the loop, the subtract operands are just reversed to yield a nonnegative
  1759. // number, and the rest is similar. The two offsets are also constant and can be folded. So in general:
  1760. // loopCountMinusOne = (left - right + offset) / abs(minMagnitudeChange)
  1761. // Determine the left and right information
  1762. StackSym *leftSym, *rightSym;
  1763. int leftOffset, rightOffset;
  1764. if(minMagnitudeChange >= 0)
  1765. {
  1766. leftSym = boundBaseSym;
  1767. leftOffset = boundOffset;
  1768. rightSym = inductionVariableSymToAdd;
  1769. rightOffset = inductionVariableOffset;
  1770. }
  1771. else
  1772. {
  1773. minMagnitudeChange = -minMagnitudeChange;
  1774. leftSym = inductionVariableSymToAdd;
  1775. leftOffset = inductionVariableOffset;
  1776. rightSym = boundBaseSym;
  1777. rightOffset = boundOffset;
  1778. }
  1779. // Determine the combined offset, and save the info necessary to generate the loop count
  1780. int offset;
  1781. if(Int32Math::Sub(leftOffset, rightOffset, &offset))
  1782. {
  1783. continue;
  1784. }
  1785. void *const loopCountBuffer = JitAnewArray(this->func->GetTopFunc()->m_fg->alloc, byte, sizeof(LoopCount));
  1786. if(!rightSym)
  1787. {
  1788. if(!leftSym)
  1789. {
  1790. loop->loopCount = new(loopCountBuffer) LoopCount(offset / minMagnitudeChange);
  1791. break;
  1792. }
  1793. if(offset == 0 && minMagnitudeChange == 1)
  1794. {
  1795. loop->loopCount = new(loopCountBuffer) LoopCount(leftSym);
  1796. break;
  1797. }
  1798. }
  1799. loop->loopCount = new(loopCountBuffer) LoopCount(leftSym, rightSym, offset, minMagnitudeChange);
  1800. break;
  1801. }
  1802. }
  1803. void GlobOpt::GenerateLoopCount(Loop *const loop, LoopCount *const loopCount)
  1804. {
  1805. Assert(DoLoopCountBasedBoundCheckHoist());
  1806. Assert(loop);
  1807. Assert(loopCount);
  1808. Assert(loopCount == loop->loopCount);
  1809. Assert(!loopCount->HasBeenGenerated());
  1810. // loopCountMinusOne = (left - right + offset) / minMagnitudeChange
  1811. // Prepare the landing pad for bailouts and instruction insertion
  1812. BailOutInfo *const bailOutInfo = loop->bailOutInfo;
  1813. Assert(bailOutInfo);
  1814. const IR::BailOutKind bailOutKind = IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck;
  1815. IR::Instr *const insertBeforeInstr = bailOutInfo->bailOutInstr;
  1816. Assert(insertBeforeInstr);
  1817. Func *const func = bailOutInfo->bailOutFunc;
  1818. // intermediateValue = left - right
  1819. IR::IntConstOpnd *offset =
  1820. loopCount->Offset() == 0 ? nullptr : IR::IntConstOpnd::New(loopCount->Offset(), TyInt32, func, true);
  1821. StackSym *const rightSym = loopCount->RightSym();
  1822. StackSym *intermediateValueSym;
  1823. if(rightSym)
  1824. {
  1825. IR::BailOutInstr *const instr = IR::BailOutInstr::New(Js::OpCode::Sub_I4, bailOutKind, bailOutInfo, func);
  1826. instr->SetSrc2(IR::RegOpnd::New(rightSym, rightSym->GetType(), func));
  1827. instr->GetSrc2()->SetIsJITOptimizedReg(true);
  1828. StackSym *const leftSym = loopCount->LeftSym();
  1829. if(leftSym)
  1830. {
  1831. // intermediateValue = left - right
  1832. instr->SetSrc1(IR::RegOpnd::New(leftSym, leftSym->GetType(), func));
  1833. instr->GetSrc1()->SetIsJITOptimizedReg(true);
  1834. }
  1835. else if(offset)
  1836. {
  1837. // intermediateValue = offset - right
  1838. instr->SetSrc1(offset);
  1839. offset = nullptr;
  1840. }
  1841. else
  1842. {
  1843. // intermediateValue = -right
  1844. instr->m_opcode = Js::OpCode::Neg_I4;
  1845. instr->SetSrc1(instr->UnlinkSrc2());
  1846. }
  1847. intermediateValueSym = StackSym::New(TyInt32, func);
  1848. instr->SetDst(IR::RegOpnd::New(intermediateValueSym, intermediateValueSym->GetType(), func));
  1849. instr->GetDst()->SetIsJITOptimizedReg(true);
  1850. instr->SetByteCodeOffset(insertBeforeInstr);
  1851. insertBeforeInstr->InsertBefore(instr);
  1852. }
  1853. else
  1854. {
  1855. // intermediateValue = left
  1856. Assert(loopCount->LeftSym());
  1857. intermediateValueSym = loopCount->LeftSym();
  1858. }
  1859. // intermediateValue += offset
  1860. if(offset)
  1861. {
  1862. IR::BailOutInstr *const instr = IR::BailOutInstr::New(Js::OpCode::Add_I4, bailOutKind, bailOutInfo, func);
  1863. instr->SetSrc1(IR::RegOpnd::New(intermediateValueSym, intermediateValueSym->GetType(), func));
  1864. instr->GetSrc1()->SetIsJITOptimizedReg(true);
  1865. if(offset->GetValue() < 0 && offset->GetValue() != IntConstMin)
  1866. {
  1867. instr->m_opcode = Js::OpCode::Sub_I4;
  1868. offset->SetValue(-offset->GetValue());
  1869. }
  1870. instr->SetSrc2(offset);
  1871. if(intermediateValueSym == loopCount->LeftSym())
  1872. {
  1873. intermediateValueSym = StackSym::New(TyInt32, func);
  1874. }
  1875. instr->SetDst(IR::RegOpnd::New(intermediateValueSym, intermediateValueSym->GetType(), func));
  1876. instr->GetDst()->SetIsJITOptimizedReg(true);
  1877. instr->SetByteCodeOffset(insertBeforeInstr);
  1878. insertBeforeInstr->InsertBefore(instr);
  1879. }
  1880. // intermediateValue /= minMagnitudeChange
  1881. const int minMagnitudeChange = loopCount->MinMagnitudeChange();
  1882. if(minMagnitudeChange != 1)
  1883. {
  1884. IR::Instr *const instr = IR::Instr::New(Js::OpCode::Div_I4, func);
  1885. instr->SetSrc1(IR::RegOpnd::New(intermediateValueSym, intermediateValueSym->GetType(), func));
  1886. instr->GetSrc1()->SetIsJITOptimizedReg(true);
  1887. Assert(minMagnitudeChange != 0); // bailout is not needed
  1888. instr->SetSrc2(IR::IntConstOpnd::New(minMagnitudeChange, TyInt32, func, true));
  1889. if(intermediateValueSym == loopCount->LeftSym())
  1890. {
  1891. intermediateValueSym = StackSym::New(TyInt32, func);
  1892. }
  1893. instr->SetDst(IR::RegOpnd::New(intermediateValueSym, intermediateValueSym->GetType(), func));
  1894. instr->GetDst()->SetIsJITOptimizedReg(true);
  1895. instr->SetByteCodeOffset(insertBeforeInstr);
  1896. insertBeforeInstr->InsertBefore(instr);
  1897. }
  1898. else
  1899. {
  1900. Assert(intermediateValueSym != loopCount->LeftSym());
  1901. }
  1902. // loopCountMinusOne = intermediateValue
  1903. loopCount->SetLoopCountMinusOneSym(intermediateValueSym);
  1904. }
  1905. void GlobOpt::GenerateLoopCountPlusOne(Loop *const loop, LoopCount *const loopCount)
  1906. {
  1907. Assert(loop);
  1908. Assert(loopCount);
  1909. Assert(loopCount == loop->loopCount);
  1910. if (loopCount->HasGeneratedLoopCountSym())
  1911. {
  1912. return;
  1913. }
  1914. if (!loopCount->HasBeenGenerated())
  1915. {
  1916. GenerateLoopCount(loop, loopCount);
  1917. }
  1918. Assert(loopCount->HasBeenGenerated());
  1919. // If this is null then the loop count is a constant and there is nothing more to do here
  1920. if (loopCount->LoopCountMinusOneSym())
  1921. {
  1922. // Prepare the landing pad for bailouts and instruction insertion
  1923. BailOutInfo *const bailOutInfo = loop->bailOutInfo;
  1924. Assert(bailOutInfo);
  1925. IR::Instr *const insertBeforeInstr = bailOutInfo->bailOutInstr;
  1926. Assert(insertBeforeInstr);
  1927. Func *const func = bailOutInfo->bailOutFunc;
  1928. IRType type = loopCount->LoopCountMinusOneSym()->GetType();
  1929. // loop count is off by one, so add one
  1930. IR::RegOpnd *loopCountOpnd = IR::RegOpnd::New(type, func);
  1931. IR::RegOpnd *minusOneOpnd = IR::RegOpnd::New(loopCount->LoopCountMinusOneSym(), type, func);
  1932. minusOneOpnd->SetIsJITOptimizedReg(true);
  1933. insertBeforeInstr->InsertBefore(IR::Instr::New(Js::OpCode::Add_I4,
  1934. loopCountOpnd,
  1935. minusOneOpnd,
  1936. IR::IntConstOpnd::New(1, type, func, true),
  1937. func));
  1938. loopCount->SetLoopCountSym(loopCountOpnd->GetStackSym());
  1939. }
  1940. }
  1941. void GlobOpt::GenerateSecondaryInductionVariableBound(
  1942. Loop *const loop,
  1943. StackSym *const inductionVariableSym,
  1944. const LoopCount *const loopCount,
  1945. const int maxMagnitudeChange,
  1946. StackSym *const boundSym)
  1947. {
  1948. Assert(loop);
  1949. Assert(inductionVariableSym);
  1950. Assert(inductionVariableSym->GetType() == TyInt32 || inductionVariableSym->GetType() == TyUint32);
  1951. Assert(loopCount);
  1952. Assert(loopCount == loop->loopCount);
  1953. Assert(loopCount->LoopCountMinusOneSym());
  1954. Assert(maxMagnitudeChange != 0);
  1955. Assert(maxMagnitudeChange >= -InductionVariable::ChangeMagnitudeLimitForLoopCountBasedHoisting);
  1956. Assert(maxMagnitudeChange <= InductionVariable::ChangeMagnitudeLimitForLoopCountBasedHoisting);
  1957. Assert(boundSym);
  1958. Assert(boundSym->IsInt32());
  1959. // bound = inductionVariable + loopCountMinusOne * maxMagnitudeChange
  1960. // Prepare the landing pad for bailouts and instruction insertion
  1961. BailOutInfo *const bailOutInfo = loop->bailOutInfo;
  1962. Assert(bailOutInfo);
  1963. const IR::BailOutKind bailOutKind = IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck;
  1964. IR::Instr *const insertBeforeInstr = bailOutInfo->bailOutInstr;
  1965. Assert(insertBeforeInstr);
  1966. Func *const func = bailOutInfo->bailOutFunc;
  1967. // intermediateValue = loopCount * maxMagnitudeChange
  1968. StackSym *intermediateValueSym;
  1969. if(maxMagnitudeChange == 1 || maxMagnitudeChange == -1)
  1970. {
  1971. intermediateValueSym = loopCount->LoopCountMinusOneSym();
  1972. }
  1973. else
  1974. {
  1975. IR::BailOutInstr *const instr = IR::BailOutInstr::New(Js::OpCode::Mul_I4, bailOutKind, bailOutInfo, func);
  1976. instr->SetSrc1(
  1977. IR::RegOpnd::New(loopCount->LoopCountMinusOneSym(), loopCount->LoopCountMinusOneSym()->GetType(), func));
  1978. instr->GetSrc1()->SetIsJITOptimizedReg(true);
  1979. instr->SetSrc2(IR::IntConstOpnd::New(maxMagnitudeChange, TyInt32, func, true));
  1980. intermediateValueSym = boundSym;
  1981. instr->SetDst(IR::RegOpnd::New(intermediateValueSym, intermediateValueSym->GetType(), func));
  1982. instr->GetDst()->SetIsJITOptimizedReg(true);
  1983. instr->SetByteCodeOffset(insertBeforeInstr);
  1984. insertBeforeInstr->InsertBefore(instr);
  1985. }
  1986. // bound = intermediateValue + inductionVariable
  1987. {
  1988. IR::BailOutInstr *const instr = IR::BailOutInstr::New(Js::OpCode::Add_I4, bailOutKind, bailOutInfo, func);
  1989. instr->SetSrc1(IR::RegOpnd::New(intermediateValueSym, intermediateValueSym->GetType(), func));
  1990. instr->GetSrc1()->SetIsJITOptimizedReg(true);
  1991. instr->SetSrc2(IR::RegOpnd::New(inductionVariableSym, inductionVariableSym->GetType(), func));
  1992. instr->GetSrc2()->SetIsJITOptimizedReg(true);
  1993. if(maxMagnitudeChange == -1)
  1994. {
  1995. // bound = inductionVariable - intermediateValue[loopCount]
  1996. instr->m_opcode = Js::OpCode::Sub_I4;
  1997. instr->SwapOpnds();
  1998. }
  1999. instr->SetDst(IR::RegOpnd::New(boundSym, boundSym->GetType(), func));
  2000. instr->GetDst()->SetIsJITOptimizedReg(true);
  2001. instr->SetByteCodeOffset(insertBeforeInstr);
  2002. insertBeforeInstr->InsertBefore(instr);
  2003. }
  2004. }
  2005. void GlobOpt::DetermineArrayBoundCheckHoistability(
  2006. bool needLowerBoundCheck,
  2007. bool needUpperBoundCheck,
  2008. ArrayLowerBoundCheckHoistInfo &lowerHoistInfo,
  2009. ArrayUpperBoundCheckHoistInfo &upperHoistInfo,
  2010. const bool isJsArray,
  2011. StackSym *const indexSym,
  2012. Value *const indexValue,
  2013. const IntConstantBounds &indexConstantBounds,
  2014. StackSym *const headSegmentLengthSym,
  2015. Value *const headSegmentLengthValue,
  2016. const IntConstantBounds &headSegmentLengthConstantBounds,
  2017. Loop *const headSegmentLengthInvariantLoop,
  2018. bool &failedToUpdateCompatibleLowerBoundCheck,
  2019. bool &failedToUpdateCompatibleUpperBoundCheck)
  2020. {
  2021. Assert(DoBoundCheckHoist());
  2022. Assert(needLowerBoundCheck || needUpperBoundCheck);
  2023. Assert(!lowerHoistInfo.HasAnyInfo());
  2024. Assert(!upperHoistInfo.HasAnyInfo());
  2025. Assert(!indexSym == !indexValue);
  2026. Assert(!needUpperBoundCheck || headSegmentLengthSym);
  2027. Assert(!headSegmentLengthSym == !headSegmentLengthValue);
  2028. Assert(!failedToUpdateCompatibleLowerBoundCheck);
  2029. Assert(!failedToUpdateCompatibleUpperBoundCheck);
  2030. Loop *const currentLoop = currentBlock->loop;
  2031. if(!indexValue)
  2032. {
  2033. Assert(!needLowerBoundCheck);
  2034. Assert(needUpperBoundCheck);
  2035. Assert(indexConstantBounds.IsConstant());
  2036. // The index is a constant value, so a bound check on it can be hoisted as far as desired. Just find a compatible bound
  2037. // check that is already available, or the loop in which the head segment length is invariant.
  2038. TRACE_PHASE_VERBOSE(
  2039. Js::Phase::BoundCheckHoistPhase,
  2040. 2,
  2041. _u("Index is constant, looking for a compatible upper bound check\n"));
  2042. const int indexConstantValue = indexConstantBounds.LowerBound();
  2043. Assert(indexConstantValue != IntConstMax);
  2044. const IntBoundCheck *compatibleBoundCheck;
  2045. if(blockData.availableIntBoundChecks->TryGetReference(
  2046. IntBoundCheckCompatibilityId(ZeroValueNumber, headSegmentLengthValue->GetValueNumber()),
  2047. &compatibleBoundCheck))
  2048. {
  2049. // We need:
  2050. // index < headSegmentLength
  2051. // Normalize the offset such that:
  2052. // 0 <= headSegmentLength + compatibleBoundCheckOffset
  2053. // Where (compatibleBoundCheckOffset = -1 - index), and -1 is to simulate < instead of <=.
  2054. const int compatibleBoundCheckOffset = -1 - indexConstantValue;
  2055. if(compatibleBoundCheck->SetBoundOffset(compatibleBoundCheckOffset))
  2056. {
  2057. TRACE_PHASE_VERBOSE(
  2058. Js::Phase::BoundCheckHoistPhase,
  2059. 3,
  2060. _u("Found in block %u\n"),
  2061. compatibleBoundCheck->Block()->GetBlockNum());
  2062. upperHoistInfo.SetCompatibleBoundCheck(compatibleBoundCheck->Block(), indexConstantValue);
  2063. return;
  2064. }
  2065. failedToUpdateCompatibleUpperBoundCheck = true;
  2066. }
  2067. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Not found\n"));
  2068. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 2, _u("Looking for invariant head segment length\n"));
  2069. Loop *invariantLoop;
  2070. Value *landingPadHeadSegmentLengthValue = nullptr;
  2071. if(headSegmentLengthInvariantLoop)
  2072. {
  2073. invariantLoop = headSegmentLengthInvariantLoop;
  2074. landingPadHeadSegmentLengthValue =
  2075. FindValue(invariantLoop->landingPad->globOptData.symToValueMap, headSegmentLengthSym);
  2076. }
  2077. else if(currentLoop)
  2078. {
  2079. invariantLoop = nullptr;
  2080. for(Loop *loop = currentLoop; loop; loop = loop->parent)
  2081. {
  2082. GlobOptBlockData &landingPadBlockData = loop->landingPad->globOptData;
  2083. GlobHashTable *const landingPadSymToValueMap = landingPadBlockData.symToValueMap;
  2084. Value *const value = FindValue(landingPadSymToValueMap, headSegmentLengthSym);
  2085. if(!value)
  2086. {
  2087. break;
  2088. }
  2089. invariantLoop = loop;
  2090. landingPadHeadSegmentLengthValue = value;
  2091. }
  2092. if(!invariantLoop)
  2093. {
  2094. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Not found\n"));
  2095. return;
  2096. }
  2097. }
  2098. else
  2099. {
  2100. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Not found, block is not in a loop\n"));
  2101. return;
  2102. }
  2103. TRACE_PHASE_VERBOSE(
  2104. Js::Phase::BoundCheckHoistPhase,
  2105. 3,
  2106. _u("Found in loop %u landing pad block %u\n"),
  2107. invariantLoop->GetLoopNumber(),
  2108. invariantLoop->landingPad->GetBlockNum());
  2109. IntConstantBounds landingPadHeadSegmentLengthConstantBounds;
  2110. AssertVerify(
  2111. landingPadHeadSegmentLengthValue
  2112. ->GetValueInfo()
  2113. ->TryGetIntConstantBounds(&landingPadHeadSegmentLengthConstantBounds));
  2114. if(isJsArray)
  2115. {
  2116. // index >= headSegmentLength is currently not possible for JS arrays (except when index == int32 max, which is
  2117. // covered above).
  2118. Assert(
  2119. !ValueInfo::IsGreaterThanOrEqualTo(
  2120. nullptr,
  2121. indexConstantValue,
  2122. indexConstantValue,
  2123. landingPadHeadSegmentLengthValue,
  2124. landingPadHeadSegmentLengthConstantBounds.LowerBound(),
  2125. landingPadHeadSegmentLengthConstantBounds.UpperBound()));
  2126. }
  2127. else if(
  2128. ValueInfo::IsGreaterThanOrEqualTo(
  2129. nullptr,
  2130. indexConstantValue,
  2131. indexConstantValue,
  2132. landingPadHeadSegmentLengthValue,
  2133. landingPadHeadSegmentLengthConstantBounds.LowerBound(),
  2134. landingPadHeadSegmentLengthConstantBounds.UpperBound()))
  2135. {
  2136. // index >= headSegmentLength in the landing pad, can't use the index sym. This is possible for typed arrays through
  2137. // conditions on array.length in user code.
  2138. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 2, _u("Index >= head segment length\n"));
  2139. return;
  2140. }
  2141. upperHoistInfo.SetLoop(
  2142. invariantLoop,
  2143. indexConstantValue,
  2144. landingPadHeadSegmentLengthValue,
  2145. landingPadHeadSegmentLengthConstantBounds);
  2146. return;
  2147. }
  2148. Assert(!indexConstantBounds.IsConstant());
  2149. ValueInfo *const indexValueInfo = indexValue->GetValueInfo();
  2150. const IntBounds *const indexBounds = indexValueInfo->IsIntBounded() ? indexValueInfo->AsIntBounded()->Bounds() : nullptr;
  2151. {
  2152. // See if a compatible bound check is already available
  2153. TRACE_PHASE_VERBOSE(
  2154. Js::Phase::BoundCheckHoistPhase,
  2155. 2,
  2156. _u("Looking for compatible bound checks for index bounds\n"));
  2157. bool searchingLower = needLowerBoundCheck;
  2158. bool searchingUpper = needUpperBoundCheck;
  2159. Assert(searchingLower || searchingUpper);
  2160. bool foundLowerBoundCheck = false;
  2161. const IntBoundCheck *lowerBoundCheck = nullptr;
  2162. ValueNumber lowerHoistBlockIndexValueNumber = InvalidValueNumber;
  2163. int lowerBoundOffset = 0;
  2164. if(searchingLower &&
  2165. blockData.availableIntBoundChecks->TryGetReference(
  2166. IntBoundCheckCompatibilityId(ZeroValueNumber, indexValue->GetValueNumber()),
  2167. &lowerBoundCheck))
  2168. {
  2169. if(lowerBoundCheck->SetBoundOffset(0))
  2170. {
  2171. foundLowerBoundCheck = true;
  2172. lowerHoistBlockIndexValueNumber = indexValue->GetValueNumber();
  2173. lowerBoundOffset = 0;
  2174. searchingLower = false;
  2175. }
  2176. else
  2177. {
  2178. failedToUpdateCompatibleLowerBoundCheck = true;
  2179. }
  2180. }
  2181. bool foundUpperBoundCheck = false;
  2182. const IntBoundCheck *upperBoundCheck = nullptr;
  2183. ValueNumber upperHoistBlockIndexValueNumber = InvalidValueNumber;
  2184. int upperBoundOffset = 0;
  2185. if(searchingUpper &&
  2186. blockData.availableIntBoundChecks->TryGetReference(
  2187. IntBoundCheckCompatibilityId(indexValue->GetValueNumber(), headSegmentLengthValue->GetValueNumber()),
  2188. &upperBoundCheck))
  2189. {
  2190. if(upperBoundCheck->SetBoundOffset(-1)) // -1 is to simulate < instead of <=
  2191. {
  2192. foundUpperBoundCheck = true;
  2193. upperHoistBlockIndexValueNumber = indexValue->GetValueNumber();
  2194. upperBoundOffset = 0;
  2195. searchingUpper = false;
  2196. }
  2197. else
  2198. {
  2199. failedToUpdateCompatibleUpperBoundCheck = true;
  2200. }
  2201. }
  2202. if(indexBounds)
  2203. {
  2204. searchingLower = searchingLower && indexBounds->RelativeLowerBounds().Count() != 0;
  2205. searchingUpper = searchingUpper && indexBounds->RelativeUpperBounds().Count() != 0;
  2206. if(searchingLower || searchingUpper)
  2207. {
  2208. for(auto it = blockData.availableIntBoundChecks->GetIterator(); it.IsValid(); it.MoveNext())
  2209. {
  2210. const IntBoundCheck &boundCheck = it.CurrentValue();
  2211. if(searchingLower && boundCheck.LeftValueNumber() == ZeroValueNumber)
  2212. {
  2213. lowerHoistBlockIndexValueNumber = boundCheck.RightValueNumber();
  2214. const ValueRelativeOffset *bound;
  2215. if(indexBounds->RelativeLowerBounds().TryGetReference(lowerHoistBlockIndexValueNumber, &bound))
  2216. {
  2217. // We need:
  2218. // 0 <= boundBase + boundOffset
  2219. const int offset = bound->Offset();
  2220. if(boundCheck.SetBoundOffset(offset))
  2221. {
  2222. foundLowerBoundCheck = true;
  2223. lowerBoundCheck = &boundCheck;
  2224. lowerBoundOffset = offset;
  2225. searchingLower = false;
  2226. if(!searchingUpper)
  2227. {
  2228. break;
  2229. }
  2230. }
  2231. else
  2232. {
  2233. failedToUpdateCompatibleLowerBoundCheck = true;
  2234. }
  2235. }
  2236. }
  2237. if(searchingUpper && boundCheck.RightValueNumber() == headSegmentLengthValue->GetValueNumber())
  2238. {
  2239. upperHoistBlockIndexValueNumber = boundCheck.LeftValueNumber();
  2240. const ValueRelativeOffset *bound;
  2241. if(indexBounds->RelativeUpperBounds().TryGetReference(upperHoistBlockIndexValueNumber, &bound))
  2242. {
  2243. // We need:
  2244. // boundBase + boundOffset < headSegmentLength
  2245. // Normalize the offset such that:
  2246. // boundBase <= headSegmentLength + compatibleBoundCheckOffset
  2247. // Where (compatibleBoundCheckOffset = -1 - boundOffset), and -1 is to simulate < instead of <=.
  2248. const int offset = -1 - bound->Offset();
  2249. if(boundCheck.SetBoundOffset(offset))
  2250. {
  2251. foundUpperBoundCheck = true;
  2252. upperBoundCheck = &boundCheck;
  2253. upperBoundOffset = bound->Offset();
  2254. searchingUpper = false;
  2255. if(!searchingLower)
  2256. {
  2257. break;
  2258. }
  2259. }
  2260. else
  2261. {
  2262. failedToUpdateCompatibleUpperBoundCheck = true;
  2263. }
  2264. }
  2265. }
  2266. }
  2267. }
  2268. }
  2269. if(foundLowerBoundCheck)
  2270. {
  2271. // A bound check takes the form src1 <= src2 + dst
  2272. Assert(lowerBoundCheck->Instr()->GetSrc2());
  2273. Assert(
  2274. lowerBoundCheck->Instr()->GetSrc2()->AsRegOpnd()->m_sym->GetType() == TyInt32 ||
  2275. lowerBoundCheck->Instr()->GetSrc2()->AsRegOpnd()->m_sym->GetType() == TyUint32);
  2276. StackSym *boundCheckIndexSym = lowerBoundCheck->Instr()->GetSrc2()->AsRegOpnd()->m_sym;
  2277. if(boundCheckIndexSym->IsTypeSpec())
  2278. {
  2279. boundCheckIndexSym = boundCheckIndexSym->GetVarEquivSym(nullptr);
  2280. Assert(boundCheckIndexSym);
  2281. }
  2282. TRACE_PHASE_VERBOSE(
  2283. Js::Phase::BoundCheckHoistPhase,
  2284. 3,
  2285. _u("Found lower bound (s%u + %d) in block %u\n"),
  2286. boundCheckIndexSym->m_id,
  2287. lowerBoundOffset,
  2288. lowerBoundCheck->Block()->GetBlockNum());
  2289. lowerHoistInfo.SetCompatibleBoundCheck(
  2290. lowerBoundCheck->Block(),
  2291. boundCheckIndexSym,
  2292. lowerBoundOffset,
  2293. lowerHoistBlockIndexValueNumber);
  2294. Assert(!searchingLower);
  2295. needLowerBoundCheck = false;
  2296. if(!needUpperBoundCheck)
  2297. {
  2298. return;
  2299. }
  2300. }
  2301. if(foundUpperBoundCheck)
  2302. {
  2303. // A bound check takes the form src1 <= src2 + dst
  2304. Assert(upperBoundCheck->Instr()->GetSrc1());
  2305. Assert(
  2306. upperBoundCheck->Instr()->GetSrc1()->AsRegOpnd()->m_sym->GetType() == TyInt32 ||
  2307. upperBoundCheck->Instr()->GetSrc1()->AsRegOpnd()->m_sym->GetType() == TyUint32);
  2308. StackSym *boundCheckIndexSym = upperBoundCheck->Instr()->GetSrc1()->AsRegOpnd()->m_sym;
  2309. if(boundCheckIndexSym->IsTypeSpec())
  2310. {
  2311. boundCheckIndexSym = boundCheckIndexSym->GetVarEquivSym(nullptr);
  2312. Assert(boundCheckIndexSym);
  2313. }
  2314. TRACE_PHASE_VERBOSE(
  2315. Js::Phase::BoundCheckHoistPhase,
  2316. 3,
  2317. _u("Found upper bound (s%u + %d) in block %u\n"),
  2318. boundCheckIndexSym->m_id,
  2319. upperBoundOffset,
  2320. upperBoundCheck->Block()->GetBlockNum());
  2321. upperHoistInfo.SetCompatibleBoundCheck(
  2322. upperBoundCheck->Block(),
  2323. boundCheckIndexSym,
  2324. -1 - upperBoundOffset,
  2325. upperHoistBlockIndexValueNumber);
  2326. Assert(!searchingUpper);
  2327. needUpperBoundCheck = false;
  2328. if(!needLowerBoundCheck)
  2329. {
  2330. return;
  2331. }
  2332. }
  2333. Assert(needLowerBoundCheck || needUpperBoundCheck);
  2334. Assert(!needLowerBoundCheck || !lowerHoistInfo.CompatibleBoundCheckBlock());
  2335. Assert(!needUpperBoundCheck || !upperHoistInfo.CompatibleBoundCheckBlock());
  2336. }
  2337. if(!currentLoop)
  2338. {
  2339. return;
  2340. }
  2341. // Check if the index sym is invariant in the loop, or if the index value in the landing pad is a lower/upper bound of the
  2342. // index value in the current block
  2343. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 2, _u("Looking for invariant index or index bounded by itself\n"));
  2344. bool searchingLower = needLowerBoundCheck, searchingUpper = needUpperBoundCheck;
  2345. for(Loop *loop = currentLoop; loop; loop = loop->parent)
  2346. {
  2347. GlobOptBlockData &landingPadBlockData = loop->landingPad->globOptData;
  2348. GlobHashTable *const landingPadSymToValueMap = landingPadBlockData.symToValueMap;
  2349. TRACE_PHASE_VERBOSE(
  2350. Js::Phase::BoundCheckHoistPhase,
  2351. 3,
  2352. _u("Trying loop %u landing pad block %u\n"),
  2353. loop->GetLoopNumber(),
  2354. loop->landingPad->GetBlockNum());
  2355. Value *const landingPadIndexValue = FindValue(landingPadSymToValueMap, indexSym);
  2356. if(!landingPadIndexValue)
  2357. {
  2358. break;
  2359. }
  2360. IntConstantBounds landingPadIndexConstantBounds;
  2361. const bool landingPadIndexValueIsLikelyInt =
  2362. landingPadIndexValue->GetValueInfo()->TryGetIntConstantBounds(&landingPadIndexConstantBounds, true);
  2363. int lowerOffset = 0, upperOffset = 0;
  2364. if(indexValue->GetValueNumber() == landingPadIndexValue->GetValueNumber())
  2365. {
  2366. Assert(landingPadIndexValueIsLikelyInt);
  2367. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Index is invariant\n"));
  2368. }
  2369. else
  2370. {
  2371. if(!landingPadIndexValueIsLikelyInt)
  2372. {
  2373. break;
  2374. }
  2375. if(searchingLower)
  2376. {
  2377. if(lowerHoistInfo.Loop() && indexValue->GetValueNumber() == lowerHoistInfo.IndexValueNumber())
  2378. {
  2379. // Prefer using the invariant sym
  2380. needLowerBoundCheck = searchingLower = false;
  2381. if(!needUpperBoundCheck)
  2382. {
  2383. return;
  2384. }
  2385. if(!searchingUpper)
  2386. {
  2387. break;
  2388. }
  2389. }
  2390. else
  2391. {
  2392. bool foundBound = false;
  2393. if(indexBounds)
  2394. {
  2395. const ValueRelativeOffset *bound;
  2396. if(indexBounds->RelativeLowerBounds().TryGetReference(landingPadIndexValue->GetValueNumber(), &bound))
  2397. {
  2398. foundBound = true;
  2399. lowerOffset = bound->Offset();
  2400. TRACE_PHASE_VERBOSE(
  2401. Js::Phase::BoundCheckHoistPhase,
  2402. 4,
  2403. _u("Found lower bound (index + %d)\n"),
  2404. lowerOffset);
  2405. }
  2406. }
  2407. if(!foundBound)
  2408. {
  2409. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Lower bound was not found\n"));
  2410. searchingLower = false;
  2411. if(!searchingUpper)
  2412. {
  2413. break;
  2414. }
  2415. }
  2416. }
  2417. }
  2418. if(searchingUpper)
  2419. {
  2420. if(upperHoistInfo.Loop() && indexValue->GetValueNumber() == upperHoistInfo.IndexValueNumber())
  2421. {
  2422. // Prefer using the invariant sym
  2423. needUpperBoundCheck = searchingUpper = false;
  2424. if(!needLowerBoundCheck)
  2425. {
  2426. return;
  2427. }
  2428. if(!searchingLower)
  2429. {
  2430. break;
  2431. }
  2432. }
  2433. else
  2434. {
  2435. bool foundBound = false;
  2436. if(indexBounds)
  2437. {
  2438. const ValueRelativeOffset *bound;
  2439. if(indexBounds->RelativeUpperBounds().TryGetReference(landingPadIndexValue->GetValueNumber(), &bound))
  2440. {
  2441. foundBound = true;
  2442. upperOffset = bound->Offset();
  2443. TRACE_PHASE_VERBOSE(
  2444. Js::Phase::BoundCheckHoistPhase,
  2445. 4,
  2446. _u("Found upper bound (index + %d)\n"),
  2447. upperOffset);
  2448. }
  2449. }
  2450. if(!foundBound)
  2451. {
  2452. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Upper bound was not found\n"));
  2453. searchingUpper = false;
  2454. if(!searchingLower)
  2455. {
  2456. break;
  2457. }
  2458. }
  2459. }
  2460. }
  2461. }
  2462. if(searchingLower)
  2463. {
  2464. if(ValueInfo::IsLessThan(
  2465. landingPadIndexValue,
  2466. landingPadIndexConstantBounds.LowerBound(),
  2467. landingPadIndexConstantBounds.UpperBound(),
  2468. nullptr,
  2469. 0,
  2470. 0))
  2471. {
  2472. // index < 0 in the landing pad; can't use the index sym
  2473. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, _u("Index < 0\n"));
  2474. searchingLower = false;
  2475. if(!searchingUpper)
  2476. {
  2477. break;
  2478. }
  2479. }
  2480. else
  2481. {
  2482. lowerHoistInfo.SetLoop(
  2483. loop,
  2484. indexSym,
  2485. lowerOffset,
  2486. landingPadIndexValue,
  2487. landingPadIndexConstantBounds);
  2488. }
  2489. }
  2490. if(!searchingUpper)
  2491. {
  2492. continue;
  2493. }
  2494. // Check if the head segment length sym is available in the landing pad
  2495. Value *const landingPadHeadSegmentLengthValue = FindValue(landingPadSymToValueMap, headSegmentLengthSym);
  2496. if(!landingPadHeadSegmentLengthValue)
  2497. {
  2498. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, _u("Head segment length is not invariant\n"));
  2499. searchingUpper = false;
  2500. if(!searchingLower)
  2501. {
  2502. break;
  2503. }
  2504. continue;
  2505. }
  2506. IntConstantBounds landingPadHeadSegmentLengthConstantBounds;
  2507. AssertVerify(
  2508. landingPadHeadSegmentLengthValue
  2509. ->GetValueInfo()
  2510. ->TryGetIntConstantBounds(&landingPadHeadSegmentLengthConstantBounds));
  2511. if(ValueInfo::IsGreaterThanOrEqualTo(
  2512. landingPadIndexValue,
  2513. landingPadIndexConstantBounds.LowerBound(),
  2514. landingPadIndexConstantBounds.UpperBound(),
  2515. landingPadHeadSegmentLengthValue,
  2516. landingPadHeadSegmentLengthConstantBounds.LowerBound(),
  2517. landingPadHeadSegmentLengthConstantBounds.UpperBound()))
  2518. {
  2519. // index >= headSegmentLength in the landing pad; can't use the index sym
  2520. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, _u("Index >= head segment length\n"));
  2521. searchingUpper = false;
  2522. if(!searchingLower)
  2523. {
  2524. break;
  2525. }
  2526. continue;
  2527. }
  2528. // We need:
  2529. // boundBase + boundOffset < headSegmentLength
  2530. // Normalize the offset such that:
  2531. // boundBase <= headSegmentLength + offset
  2532. // Where (offset = -1 - boundOffset), and -1 is to simulate < instead of <=.
  2533. upperOffset = -1 - upperOffset;
  2534. upperHoistInfo.SetLoop(
  2535. loop,
  2536. indexSym,
  2537. upperOffset,
  2538. landingPadIndexValue,
  2539. landingPadIndexConstantBounds,
  2540. landingPadHeadSegmentLengthValue,
  2541. landingPadHeadSegmentLengthConstantBounds);
  2542. }
  2543. if(needLowerBoundCheck && lowerHoistInfo.Loop())
  2544. {
  2545. needLowerBoundCheck = false;
  2546. if(!needUpperBoundCheck)
  2547. {
  2548. return;
  2549. }
  2550. }
  2551. if(needUpperBoundCheck && upperHoistInfo.Loop())
  2552. {
  2553. needUpperBoundCheck = false;
  2554. if(!needLowerBoundCheck)
  2555. {
  2556. return;
  2557. }
  2558. }
  2559. // Find an invariant lower/upper bound of the index that can be used for hoisting the bound checks
  2560. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 2, _u("Looking for invariant index bounds\n"));
  2561. searchingLower = needLowerBoundCheck;
  2562. searchingUpper = needUpperBoundCheck;
  2563. for(Loop *loop = currentLoop; loop; loop = loop->parent)
  2564. {
  2565. GlobOptBlockData &landingPadBlockData = loop->landingPad->globOptData;
  2566. GlobHashTable *const landingPadSymToValueMap = landingPadBlockData.symToValueMap;
  2567. TRACE_PHASE_VERBOSE(
  2568. Js::Phase::BoundCheckHoistPhase,
  2569. 3,
  2570. _u("Trying loop %u landing pad block %u\n"),
  2571. loop->GetLoopNumber(),
  2572. loop->landingPad->GetBlockNum());
  2573. Value *landingPadHeadSegmentLengthValue = nullptr;
  2574. IntConstantBounds landingPadHeadSegmentLengthConstantBounds;
  2575. if(searchingUpper)
  2576. {
  2577. // Check if the head segment length sym is available in the landing pad
  2578. landingPadHeadSegmentLengthValue = FindValue(landingPadSymToValueMap, headSegmentLengthSym);
  2579. if(landingPadHeadSegmentLengthValue)
  2580. {
  2581. AssertVerify(
  2582. landingPadHeadSegmentLengthValue
  2583. ->GetValueInfo()
  2584. ->TryGetIntConstantBounds(&landingPadHeadSegmentLengthConstantBounds));
  2585. }
  2586. else
  2587. {
  2588. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Head segment length is not invariant\n"));
  2589. searchingUpper = false;
  2590. if(!searchingLower)
  2591. {
  2592. break;
  2593. }
  2594. }
  2595. }
  2596. // Look for a relative bound
  2597. if(indexBounds)
  2598. {
  2599. for(int j = 0; j < 2; ++j)
  2600. {
  2601. const bool searchingRelativeLowerBounds = j == 0;
  2602. if(!(searchingRelativeLowerBounds ? searchingLower : searchingUpper))
  2603. {
  2604. continue;
  2605. }
  2606. for(auto it =
  2607. (
  2608. searchingRelativeLowerBounds
  2609. ? indexBounds->RelativeLowerBounds()
  2610. : indexBounds->RelativeUpperBounds()
  2611. ).GetIterator();
  2612. it.IsValid();
  2613. it.MoveNext())
  2614. {
  2615. const ValueRelativeOffset &indexBound = it.CurrentValue();
  2616. StackSym *const indexBoundBaseSym = indexBound.BaseSym();
  2617. if(!indexBoundBaseSym)
  2618. {
  2619. continue;
  2620. }
  2621. TRACE_PHASE_VERBOSE(
  2622. Js::Phase::BoundCheckHoistPhase,
  2623. 4,
  2624. _u("Found %S bound (s%u + %d)\n"),
  2625. searchingRelativeLowerBounds ? "lower" : "upper",
  2626. indexBoundBaseSym->m_id,
  2627. indexBound.Offset());
  2628. if(!indexBound.WasEstablishedExplicitly())
  2629. {
  2630. // Don't use a bound that was not established explicitly, as it may be too aggressive. For instance, an
  2631. // index sym used in an array will obtain an upper bound of the array's head segment length - 1. That
  2632. // bound is not established explicitly because the bound assertion is not enforced by the source code.
  2633. // Rather, it is assumed and enforced by the JIT using bailout check. Incrementing the index and using
  2634. // it in a different array may otherwise cause it to use the first array's head segment length as the
  2635. // upper bound on which to do the bound check against the second array, and that bound check would
  2636. // always fail when the arrays are the same size.
  2637. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, _u("Bound was established implicitly\n"));
  2638. continue;
  2639. }
  2640. Value *const landingPadIndexBoundBaseValue = FindValue(landingPadSymToValueMap, indexBoundBaseSym);
  2641. if(!landingPadIndexBoundBaseValue ||
  2642. landingPadIndexBoundBaseValue->GetValueNumber() != indexBound.BaseValueNumber())
  2643. {
  2644. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, _u("Bound is not invariant\n"));
  2645. continue;
  2646. }
  2647. IntConstantBounds landingPadIndexBoundBaseConstantBounds;
  2648. AssertVerify(
  2649. landingPadIndexBoundBaseValue
  2650. ->GetValueInfo()
  2651. ->TryGetIntConstantBounds(&landingPadIndexBoundBaseConstantBounds, true));
  2652. int offset = indexBound.Offset();
  2653. if(searchingRelativeLowerBounds)
  2654. {
  2655. if(offset == IntConstMin ||
  2656. ValueInfo::IsLessThan(
  2657. landingPadIndexBoundBaseValue,
  2658. landingPadIndexBoundBaseConstantBounds.LowerBound(),
  2659. landingPadIndexBoundBaseConstantBounds.UpperBound(),
  2660. nullptr,
  2661. -offset,
  2662. -offset))
  2663. {
  2664. // indexBoundBase + indexBoundOffset < 0; can't use this bound
  2665. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, _u("Bound < 0\n"));
  2666. continue;
  2667. }
  2668. lowerHoistInfo.SetLoop(
  2669. loop,
  2670. indexBoundBaseSym,
  2671. offset,
  2672. landingPadIndexBoundBaseValue,
  2673. landingPadIndexBoundBaseConstantBounds);
  2674. break;
  2675. }
  2676. if(ValueInfo::IsLessThanOrEqualTo(
  2677. landingPadHeadSegmentLengthValue,
  2678. landingPadHeadSegmentLengthConstantBounds.LowerBound(),
  2679. landingPadHeadSegmentLengthConstantBounds.UpperBound(),
  2680. landingPadIndexBoundBaseValue,
  2681. landingPadIndexBoundBaseConstantBounds.LowerBound(),
  2682. landingPadIndexBoundBaseConstantBounds.UpperBound(),
  2683. offset))
  2684. {
  2685. // indexBoundBase + indexBoundOffset >= headSegmentLength; can't use this bound
  2686. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, _u("Bound >= head segment length\n"));
  2687. continue;
  2688. }
  2689. // We need:
  2690. // boundBase + boundOffset < headSegmentLength
  2691. // Normalize the offset such that:
  2692. // boundBase <= headSegmentLength + offset
  2693. // Where (offset = -1 - boundOffset), and -1 is to simulate < instead of <=.
  2694. offset = -1 - offset;
  2695. upperHoistInfo.SetLoop(
  2696. loop,
  2697. indexBoundBaseSym,
  2698. offset,
  2699. landingPadIndexBoundBaseValue,
  2700. landingPadIndexBoundBaseConstantBounds,
  2701. landingPadHeadSegmentLengthValue,
  2702. landingPadHeadSegmentLengthConstantBounds);
  2703. break;
  2704. }
  2705. }
  2706. }
  2707. if(searchingLower && lowerHoistInfo.Loop() != loop)
  2708. {
  2709. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Lower bound was not found\n"));
  2710. searchingLower = false;
  2711. if(!searchingUpper)
  2712. {
  2713. break;
  2714. }
  2715. }
  2716. if(searchingUpper && upperHoistInfo.Loop() != loop)
  2717. {
  2718. // No useful relative bound found; look for a constant bound if the index is an induction variable. Exclude constant
  2719. // bounds of non-induction variables because those bounds may have been established through means other than a loop
  2720. // exit condition, such as math or bitwise operations. Exclude constant bounds established implicitly by <,
  2721. // <=, >, and >=. For example, for a loop condition (i < n - 1), if 'n' is not invariant and hence can't be used,
  2722. // 'i' will still have a constant upper bound of (int32 max - 2) that should be excluded.
  2723. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Relative upper bound was not found\n"));
  2724. const InductionVariable *indexInductionVariable;
  2725. if(!upperHoistInfo.Loop() &&
  2726. currentLoop->inductionVariables &&
  2727. currentLoop->inductionVariables->TryGetReference(indexSym->m_id, &indexInductionVariable) &&
  2728. indexInductionVariable->IsChangeDeterminate())
  2729. {
  2730. if(!(indexBounds && indexBounds->WasConstantUpperBoundEstablishedExplicitly()))
  2731. {
  2732. TRACE_PHASE_VERBOSE(
  2733. Js::Phase::BoundCheckHoistPhase,
  2734. 4,
  2735. _u("Constant upper bound was established implicitly\n"));
  2736. }
  2737. else
  2738. {
  2739. // See if a compatible bound check is already available
  2740. const int indexConstantBound = indexBounds->ConstantUpperBound();
  2741. TRACE_PHASE_VERBOSE(
  2742. Js::Phase::BoundCheckHoistPhase,
  2743. 4,
  2744. _u("Found constant upper bound %d, looking for a compatible bound check\n"),
  2745. indexConstantBound);
  2746. const IntBoundCheck *boundCheck;
  2747. if(blockData.availableIntBoundChecks->TryGetReference(
  2748. IntBoundCheckCompatibilityId(ZeroValueNumber, headSegmentLengthValue->GetValueNumber()),
  2749. &boundCheck))
  2750. {
  2751. // We need:
  2752. // indexConstantBound < headSegmentLength
  2753. // Normalize the offset such that:
  2754. // 0 <= headSegmentLength + compatibleBoundCheckOffset
  2755. // Where (compatibleBoundCheckOffset = -1 - indexConstantBound), and -1 is to simulate < instead of <=.
  2756. const int compatibleBoundCheckOffset = -1 - indexConstantBound;
  2757. if(boundCheck->SetBoundOffset(compatibleBoundCheckOffset))
  2758. {
  2759. TRACE_PHASE_VERBOSE(
  2760. Js::Phase::BoundCheckHoistPhase,
  2761. 5,
  2762. _u("Found in block %u\n"),
  2763. boundCheck->Block()->GetBlockNum());
  2764. upperHoistInfo.SetCompatibleBoundCheck(boundCheck->Block(), indexConstantBound);
  2765. needUpperBoundCheck = searchingUpper = false;
  2766. if(!needLowerBoundCheck)
  2767. {
  2768. return;
  2769. }
  2770. if(!searchingLower)
  2771. {
  2772. break;
  2773. }
  2774. }
  2775. else
  2776. {
  2777. failedToUpdateCompatibleUpperBoundCheck = true;
  2778. }
  2779. }
  2780. if(searchingUpper)
  2781. {
  2782. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, _u("Not found\n"));
  2783. upperHoistInfo.SetLoop(
  2784. loop,
  2785. indexConstantBound,
  2786. landingPadHeadSegmentLengthValue,
  2787. landingPadHeadSegmentLengthConstantBounds);
  2788. }
  2789. }
  2790. }
  2791. else if(!upperHoistInfo.Loop())
  2792. {
  2793. TRACE_PHASE_VERBOSE(
  2794. Js::Phase::BoundCheckHoistPhase,
  2795. 4,
  2796. _u("Index is not an induction variable, not using constant upper bound\n"));
  2797. }
  2798. if(searchingUpper && upperHoistInfo.Loop() != loop)
  2799. {
  2800. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Upper bound was not found\n"));
  2801. searchingUpper = false;
  2802. if(!searchingLower)
  2803. {
  2804. break;
  2805. }
  2806. }
  2807. }
  2808. }
  2809. if(needLowerBoundCheck && lowerHoistInfo.Loop())
  2810. {
  2811. needLowerBoundCheck = false;
  2812. if(!needUpperBoundCheck)
  2813. {
  2814. return;
  2815. }
  2816. }
  2817. if(needUpperBoundCheck && upperHoistInfo.Loop())
  2818. {
  2819. needUpperBoundCheck = false;
  2820. if(!needLowerBoundCheck)
  2821. {
  2822. return;
  2823. }
  2824. }
  2825. // Try to use the loop count to calculate a missing lower/upper bound that in turn can be used for hoisting a bound check
  2826. TRACE_PHASE_VERBOSE(
  2827. Js::Phase::BoundCheckHoistPhase,
  2828. 2,
  2829. _u("Looking for loop count based bound for loop %u landing pad block %u\n"),
  2830. currentLoop->GetLoopNumber(),
  2831. currentLoop->landingPad->GetBlockNum());
  2832. LoopCount *const loopCount = currentLoop->loopCount;
  2833. if(!loopCount)
  2834. {
  2835. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Loop was not counted\n"));
  2836. return;
  2837. }
  2838. const InductionVariable *indexInductionVariable;
  2839. if(!currentLoop->inductionVariables ||
  2840. !currentLoop->inductionVariables->TryGetReference(indexSym->m_id, &indexInductionVariable) ||
  2841. !indexInductionVariable->IsChangeDeterminate())
  2842. {
  2843. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Index is not an induction variable\n"));
  2844. return;
  2845. }
  2846. // Determine the maximum-magnitude change per iteration, and verify that the change is reasonably finite
  2847. Assert(indexInductionVariable->IsChangeUnidirectional());
  2848. GlobOptBlockData &landingPadBlockData = currentLoop->landingPad->globOptData;
  2849. GlobHashTable *const landingPadSymToValueMap = currentLoop->landingPad->globOptData.symToValueMap;
  2850. int maxMagnitudeChange = indexInductionVariable->ChangeBounds().UpperBound();
  2851. Value *landingPadHeadSegmentLengthValue;
  2852. IntConstantBounds landingPadHeadSegmentLengthConstantBounds;
  2853. if(maxMagnitudeChange > 0)
  2854. {
  2855. TRACE_PHASE_VERBOSE(
  2856. Js::Phase::BoundCheckHoistPhase,
  2857. 3,
  2858. _u("Index's maximum-magnitude change per iteration is %d\n"),
  2859. maxMagnitudeChange);
  2860. if(!needUpperBoundCheck || maxMagnitudeChange > InductionVariable::ChangeMagnitudeLimitForLoopCountBasedHoisting)
  2861. {
  2862. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Change magnitude is too large\n"));
  2863. return;
  2864. }
  2865. // Check whether the head segment length is available in the landing pad
  2866. landingPadHeadSegmentLengthValue = FindValue(landingPadSymToValueMap, headSegmentLengthSym);
  2867. Assert(!headSegmentLengthInvariantLoop || landingPadHeadSegmentLengthValue);
  2868. if(!landingPadHeadSegmentLengthValue)
  2869. {
  2870. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Head segment length is not invariant\n"));
  2871. return;
  2872. }
  2873. AssertVerify(
  2874. landingPadHeadSegmentLengthValue
  2875. ->GetValueInfo()
  2876. ->TryGetIntConstantBounds(&landingPadHeadSegmentLengthConstantBounds));
  2877. }
  2878. else
  2879. {
  2880. maxMagnitudeChange = indexInductionVariable->ChangeBounds().LowerBound();
  2881. Assert(maxMagnitudeChange < 0);
  2882. TRACE_PHASE_VERBOSE(
  2883. Js::Phase::BoundCheckHoistPhase,
  2884. 3,
  2885. _u("Index's maximum-magnitude change per iteration is %d\n"),
  2886. maxMagnitudeChange);
  2887. if(!needLowerBoundCheck || maxMagnitudeChange < -InductionVariable::ChangeMagnitudeLimitForLoopCountBasedHoisting)
  2888. {
  2889. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Change magnitude is too large\n"));
  2890. return;
  2891. }
  2892. landingPadHeadSegmentLengthValue = nullptr;
  2893. }
  2894. // Determine if the index already changed in the loop, and by how much
  2895. int indexOffset;
  2896. StackSym *indexSymToAdd;
  2897. if(DetermineSymBoundOffsetOrValueRelativeToLandingPad(
  2898. indexSym,
  2899. maxMagnitudeChange >= 0,
  2900. indexValueInfo,
  2901. indexBounds,
  2902. currentLoop->landingPad->globOptData.symToValueMap,
  2903. &indexOffset))
  2904. {
  2905. // The bound value is constant
  2906. indexSymToAdd = nullptr;
  2907. }
  2908. else
  2909. {
  2910. // The bound value is not constant, the offset needs to be added to the index sym in the landing pad
  2911. indexSymToAdd = indexSym;
  2912. }
  2913. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Index's offset from landing pad is %d\n"), indexOffset);
  2914. // The secondary induction variable bound is computed as follows:
  2915. // bound = index + indexOffset + loopCountMinusOne * maxMagnitudeChange
  2916. //
  2917. // If the loop count is constant, (inductionVariableOffset + loopCount * maxMagnitudeChange) can be folded into an offset:
  2918. // bound = index + offset
  2919. int offset;
  2920. StackSym *indexLoopCountBasedBoundBaseSym;
  2921. Value *indexLoopCountBasedBoundBaseValue;
  2922. IntConstantBounds indexLoopCountBasedBoundBaseConstantBounds;
  2923. bool generateLoopCountBasedIndexBound;
  2924. if(!loopCount->HasBeenGenerated() || loopCount->LoopCountMinusOneSym())
  2925. {
  2926. if(loopCount->HasBeenGenerated())
  2927. {
  2928. TRACE_PHASE_VERBOSE(
  2929. Js::Phase::BoundCheckHoistPhase,
  2930. 3,
  2931. _u("Loop count is assigned to s%u\n"),
  2932. loopCount->LoopCountMinusOneSym()->m_id);
  2933. }
  2934. else
  2935. {
  2936. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Loop count has not been generated yet\n"));
  2937. }
  2938. offset = indexOffset;
  2939. // Check if there is already a loop count based bound sym for the index. If not, generate it.
  2940. do
  2941. {
  2942. const SymID indexSymId = indexSym->m_id;
  2943. SymIdToStackSymMap *&loopCountBasedBoundBaseSyms = currentLoop->loopCountBasedBoundBaseSyms;
  2944. if(!loopCountBasedBoundBaseSyms)
  2945. {
  2946. loopCountBasedBoundBaseSyms = JitAnew(alloc, SymIdToStackSymMap, alloc);
  2947. }
  2948. else if(loopCountBasedBoundBaseSyms->TryGetValue(indexSymId, &indexLoopCountBasedBoundBaseSym))
  2949. {
  2950. TRACE_PHASE_VERBOSE(
  2951. Js::Phase::BoundCheckHoistPhase,
  2952. 3,
  2953. _u("Loop count based bound is assigned to s%u\n"),
  2954. indexLoopCountBasedBoundBaseSym->m_id);
  2955. indexLoopCountBasedBoundBaseValue = FindValue(landingPadSymToValueMap, indexLoopCountBasedBoundBaseSym);
  2956. Assert(indexLoopCountBasedBoundBaseValue);
  2957. AssertVerify(
  2958. indexLoopCountBasedBoundBaseValue
  2959. ->GetValueInfo()
  2960. ->TryGetIntConstantBounds(&indexLoopCountBasedBoundBaseConstantBounds));
  2961. generateLoopCountBasedIndexBound = false;
  2962. break;
  2963. }
  2964. indexLoopCountBasedBoundBaseSym = StackSym::New(TyInt32, func);
  2965. TRACE_PHASE_VERBOSE(
  2966. Js::Phase::BoundCheckHoistPhase,
  2967. 3,
  2968. _u("Assigning s%u to the loop count based bound\n"),
  2969. indexLoopCountBasedBoundBaseSym->m_id);
  2970. loopCountBasedBoundBaseSyms->Add(indexSymId, indexLoopCountBasedBoundBaseSym);
  2971. indexLoopCountBasedBoundBaseValue = NewValue(ValueInfo::New(alloc, ValueType::GetInt(true)));
  2972. SetValue(&landingPadBlockData, indexLoopCountBasedBoundBaseValue, indexLoopCountBasedBoundBaseSym);
  2973. indexLoopCountBasedBoundBaseConstantBounds = IntConstantBounds(IntConstMin, IntConstMax);
  2974. generateLoopCountBasedIndexBound = true;
  2975. } while(false);
  2976. }
  2977. else
  2978. {
  2979. // The loop count is constant, fold (indexOffset + loopCountMinusOne * maxMagnitudeChange)
  2980. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Loop count is constant, folding\n"));
  2981. if(Int32Math::Mul(loopCount->LoopCountMinusOneConstantValue(), maxMagnitudeChange, &offset) ||
  2982. Int32Math::Add(offset, indexOffset, &offset))
  2983. {
  2984. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Folding failed\n"));
  2985. return;
  2986. }
  2987. if(!indexSymToAdd)
  2988. {
  2989. // The loop count based bound is constant
  2990. const int loopCountBasedConstantBound = offset;
  2991. TRACE_PHASE_VERBOSE(
  2992. Js::Phase::BoundCheckHoistPhase,
  2993. 3,
  2994. _u("Loop count based bound is constant: %d\n"),
  2995. loopCountBasedConstantBound);
  2996. if(maxMagnitudeChange < 0)
  2997. {
  2998. if(loopCountBasedConstantBound < 0)
  2999. {
  3000. // Can't use this bound
  3001. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Bound < 0\n"));
  3002. return;
  3003. }
  3004. lowerHoistInfo.SetLoop(currentLoop, loopCountBasedConstantBound, true);
  3005. return;
  3006. }
  3007. // loopCountBasedConstantBound >= headSegmentLength is currently not possible, except when
  3008. // loopCountBasedConstantBound == int32 max
  3009. Assert(
  3010. loopCountBasedConstantBound == IntConstMax ||
  3011. !ValueInfo::IsGreaterThanOrEqualTo(
  3012. nullptr,
  3013. loopCountBasedConstantBound,
  3014. loopCountBasedConstantBound,
  3015. landingPadHeadSegmentLengthValue,
  3016. landingPadHeadSegmentLengthConstantBounds.LowerBound(),
  3017. landingPadHeadSegmentLengthConstantBounds.UpperBound()));
  3018. // See if a compatible bound check is already available
  3019. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Looking for a compatible bound check\n"));
  3020. const IntBoundCheck *boundCheck;
  3021. if(blockData.availableIntBoundChecks->TryGetReference(
  3022. IntBoundCheckCompatibilityId(ZeroValueNumber, headSegmentLengthValue->GetValueNumber()),
  3023. &boundCheck))
  3024. {
  3025. // We need:
  3026. // loopCountBasedConstantBound < headSegmentLength
  3027. // Normalize the offset such that:
  3028. // 0 <= headSegmentLength + compatibleBoundCheckOffset
  3029. // Where (compatibleBoundCheckOffset = -1 - loopCountBasedConstantBound), and -1 is to simulate < instead of <=.
  3030. const int compatibleBoundCheckOffset = -1 - loopCountBasedConstantBound;
  3031. if(boundCheck->SetBoundOffset(compatibleBoundCheckOffset, true))
  3032. {
  3033. TRACE_PHASE_VERBOSE(
  3034. Js::Phase::BoundCheckHoistPhase,
  3035. 4,
  3036. _u("Found in block %u\n"),
  3037. boundCheck->Block()->GetBlockNum());
  3038. upperHoistInfo.SetCompatibleBoundCheck(boundCheck->Block(), loopCountBasedConstantBound);
  3039. return;
  3040. }
  3041. failedToUpdateCompatibleUpperBoundCheck = true;
  3042. }
  3043. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Not found\n"));
  3044. upperHoistInfo.SetLoop(
  3045. currentLoop,
  3046. loopCountBasedConstantBound,
  3047. landingPadHeadSegmentLengthValue,
  3048. landingPadHeadSegmentLengthConstantBounds,
  3049. true);
  3050. return;
  3051. }
  3052. // The loop count based bound is not constant; we need to add the offset of the index sym in the landing pad. Instead
  3053. // of adding though, we will treat the index sym as the loop count based bound base sym and adjust the offset that will
  3054. // be used in the bound check itself.
  3055. indexLoopCountBasedBoundBaseSym = indexSymToAdd;
  3056. indexLoopCountBasedBoundBaseValue = FindValue(landingPadSymToValueMap, indexSymToAdd);
  3057. Assert(indexLoopCountBasedBoundBaseValue);
  3058. AssertVerify(
  3059. indexLoopCountBasedBoundBaseValue
  3060. ->GetValueInfo()
  3061. ->TryGetIntConstantBounds(&indexLoopCountBasedBoundBaseConstantBounds));
  3062. generateLoopCountBasedIndexBound = false;
  3063. }
  3064. if(maxMagnitudeChange >= 0)
  3065. {
  3066. // We need:
  3067. // indexLoopCountBasedBoundBase + indexOffset < headSegmentLength
  3068. // Normalize the offset such that:
  3069. // indexLoopCountBasedBoundBase <= headSegmentLength + offset
  3070. // Where (offset = -1 - indexOffset), and -1 is to simulate < instead of <=.
  3071. offset = -1 - offset;
  3072. }
  3073. if(!generateLoopCountBasedIndexBound)
  3074. {
  3075. if(maxMagnitudeChange < 0)
  3076. {
  3077. if(offset != IntConstMax &&
  3078. ValueInfo::IsGreaterThanOrEqualTo(
  3079. nullptr,
  3080. 0,
  3081. 0,
  3082. indexLoopCountBasedBoundBaseValue,
  3083. indexLoopCountBasedBoundBaseConstantBounds.LowerBound(),
  3084. indexLoopCountBasedBoundBaseConstantBounds.UpperBound(),
  3085. offset + 1)) // + 1 to simulate > instead of >=
  3086. {
  3087. // loopCountBasedBound < 0, can't use this bound
  3088. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Bound < 0\n"));
  3089. return;
  3090. }
  3091. }
  3092. else if(
  3093. ValueInfo::IsGreaterThanOrEqualTo(
  3094. indexLoopCountBasedBoundBaseValue,
  3095. indexLoopCountBasedBoundBaseConstantBounds.LowerBound(),
  3096. indexLoopCountBasedBoundBaseConstantBounds.UpperBound(),
  3097. landingPadHeadSegmentLengthValue,
  3098. landingPadHeadSegmentLengthConstantBounds.LowerBound(),
  3099. landingPadHeadSegmentLengthConstantBounds.UpperBound(),
  3100. offset))
  3101. {
  3102. // loopCountBasedBound >= headSegmentLength, can't use this bound
  3103. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Bound >= head segment length\n"));
  3104. return;
  3105. }
  3106. // See if a compatible bound check is already available
  3107. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Looking for a compatible bound check\n"));
  3108. const ValueNumber indexLoopCountBasedBoundBaseValueNumber = indexLoopCountBasedBoundBaseValue->GetValueNumber();
  3109. const IntBoundCheck *boundCheck;
  3110. if(blockData.availableIntBoundChecks->TryGetReference(
  3111. maxMagnitudeChange < 0
  3112. ? IntBoundCheckCompatibilityId(
  3113. ZeroValueNumber,
  3114. indexLoopCountBasedBoundBaseValueNumber)
  3115. : IntBoundCheckCompatibilityId(
  3116. indexLoopCountBasedBoundBaseValueNumber,
  3117. headSegmentLengthValue->GetValueNumber()),
  3118. &boundCheck))
  3119. {
  3120. if(boundCheck->SetBoundOffset(offset, true))
  3121. {
  3122. TRACE_PHASE_VERBOSE(
  3123. Js::Phase::BoundCheckHoistPhase,
  3124. 4,
  3125. _u("Found in block %u\n"),
  3126. boundCheck->Block()->GetBlockNum());
  3127. if(maxMagnitudeChange < 0)
  3128. {
  3129. lowerHoistInfo.SetCompatibleBoundCheck(
  3130. boundCheck->Block(),
  3131. indexLoopCountBasedBoundBaseSym,
  3132. offset,
  3133. indexLoopCountBasedBoundBaseValueNumber);
  3134. }
  3135. else
  3136. {
  3137. upperHoistInfo.SetCompatibleBoundCheck(
  3138. boundCheck->Block(),
  3139. indexLoopCountBasedBoundBaseSym,
  3140. offset,
  3141. indexLoopCountBasedBoundBaseValueNumber);
  3142. }
  3143. return;
  3144. }
  3145. (maxMagnitudeChange < 0 ? failedToUpdateCompatibleLowerBoundCheck : failedToUpdateCompatibleUpperBoundCheck) = true;
  3146. }
  3147. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Not found\n"));
  3148. }
  3149. if(maxMagnitudeChange < 0)
  3150. {
  3151. lowerHoistInfo.SetLoop(
  3152. currentLoop,
  3153. indexLoopCountBasedBoundBaseSym,
  3154. offset,
  3155. indexLoopCountBasedBoundBaseValue,
  3156. indexLoopCountBasedBoundBaseConstantBounds,
  3157. true);
  3158. if(generateLoopCountBasedIndexBound)
  3159. {
  3160. lowerHoistInfo.SetLoopCount(loopCount, maxMagnitudeChange);
  3161. }
  3162. return;
  3163. }
  3164. upperHoistInfo.SetLoop(
  3165. currentLoop,
  3166. indexLoopCountBasedBoundBaseSym,
  3167. offset,
  3168. indexLoopCountBasedBoundBaseValue,
  3169. indexLoopCountBasedBoundBaseConstantBounds,
  3170. landingPadHeadSegmentLengthValue,
  3171. landingPadHeadSegmentLengthConstantBounds,
  3172. true);
  3173. if(generateLoopCountBasedIndexBound)
  3174. {
  3175. upperHoistInfo.SetLoopCount(loopCount, maxMagnitudeChange);
  3176. }
  3177. }