GlobOptIntBounds.cpp 130 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446
  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(L" "); \
  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. }
  686. return IntBounds::New(constantBounds, false, alloc);
  687. }
  688. ValueInfo *GlobOpt::UpdateIntBoundsForEqual(
  689. Value *const value,
  690. const IntConstantBounds &constantBounds,
  691. Value *const boundValue,
  692. const IntConstantBounds &boundConstantBounds,
  693. const bool isExplicit)
  694. {
  695. Assert(value || constantBounds.IsConstant());
  696. Assert(boundValue || boundConstantBounds.IsConstant());
  697. if(!value)
  698. {
  699. return nullptr;
  700. }
  701. Assert(!boundValue || value->GetValueNumber() != boundValue->GetValueNumber());
  702. ValueInfo *const valueInfo = value->GetValueInfo();
  703. IntBounds *const bounds =
  704. GetIntBoundsToUpdate(valueInfo, constantBounds, true, boundConstantBounds.IsConstant(), true, isExplicit);
  705. if(bounds)
  706. {
  707. if(boundValue)
  708. {
  709. const ValueNumber valueNumber = value->GetValueNumber();
  710. bounds->SetLowerBound(valueNumber, boundValue, isExplicit);
  711. bounds->SetUpperBound(valueNumber, boundValue, isExplicit);
  712. }
  713. else
  714. {
  715. bounds->SetLowerBound(boundConstantBounds.LowerBound());
  716. bounds->SetUpperBound(boundConstantBounds.LowerBound(), isExplicit);
  717. }
  718. if(bounds->RequiresIntBoundedValueInfo(valueInfo->Type()))
  719. {
  720. return NewIntBoundedValueInfo(valueInfo, bounds);
  721. }
  722. bounds->Delete();
  723. }
  724. if(!valueInfo->IsInt())
  725. {
  726. return nullptr;
  727. }
  728. const int32 newMin = max(constantBounds.LowerBound(), boundConstantBounds.LowerBound());
  729. const int32 newMax = min(constantBounds.UpperBound(), boundConstantBounds.UpperBound());
  730. return newMin <= newMax ? NewIntRangeValueInfo(valueInfo, newMin, newMax) : nullptr;
  731. }
  732. ValueInfo *GlobOpt::UpdateIntBoundsForNotEqual(
  733. Value *const value,
  734. const IntConstantBounds &constantBounds,
  735. Value *const boundValue,
  736. const IntConstantBounds &boundConstantBounds,
  737. const bool isExplicit)
  738. {
  739. Assert(value || constantBounds.IsConstant());
  740. Assert(boundValue || boundConstantBounds.IsConstant());
  741. if(!value)
  742. {
  743. return nullptr;
  744. }
  745. Assert(!boundValue || value->GetValueNumber() != boundValue->GetValueNumber());
  746. ValueInfo *const valueInfo = value->GetValueInfo();
  747. IntBounds *const bounds =
  748. GetIntBoundsToUpdate(
  749. valueInfo,
  750. constantBounds,
  751. false,
  752. boundConstantBounds.IsConstant(),
  753. boundConstantBounds.IsConstant() && boundConstantBounds.LowerBound() == constantBounds.UpperBound(),
  754. isExplicit);
  755. if(bounds)
  756. {
  757. if(boundValue
  758. ? bounds->SetIsNot(boundValue, isExplicit)
  759. : bounds->SetIsNot(boundConstantBounds.LowerBound(), isExplicit))
  760. {
  761. if(bounds->RequiresIntBoundedValueInfo(valueInfo->Type()))
  762. {
  763. return NewIntBoundedValueInfo(valueInfo, bounds);
  764. }
  765. }
  766. else
  767. {
  768. bounds->Delete();
  769. return nullptr;
  770. }
  771. bounds->Delete();
  772. }
  773. if(!valueInfo->IsInt() || !boundConstantBounds.IsConstant())
  774. {
  775. return nullptr;
  776. }
  777. const int32 constantBound = boundConstantBounds.LowerBound();
  778. // 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
  779. int32 newMin = constantBounds.LowerBound(), newMax = constantBounds.UpperBound();
  780. if(constantBound == newMin)
  781. {
  782. Assert(newMin <= newMax);
  783. if(newMin == newMax)
  784. {
  785. return nullptr;
  786. }
  787. ++newMin;
  788. }
  789. else if(constantBound == newMax)
  790. {
  791. Assert(newMin <= newMax);
  792. if(newMin == newMax)
  793. {
  794. return nullptr;
  795. }
  796. --newMax;
  797. }
  798. else
  799. {
  800. return nullptr;
  801. }
  802. return NewIntRangeValueInfo(valueInfo, newMin, newMax);
  803. }
  804. ValueInfo *GlobOpt::UpdateIntBoundsForGreaterThanOrEqual(
  805. Value *const value,
  806. const IntConstantBounds &constantBounds,
  807. Value *const boundValue,
  808. const IntConstantBounds &boundConstantBounds,
  809. const bool isExplicit)
  810. {
  811. return UpdateIntBoundsForGreaterThanOrEqual(value, constantBounds, boundValue, boundConstantBounds, 0, isExplicit);
  812. }
  813. ValueInfo *GlobOpt::UpdateIntBoundsForGreaterThanOrEqual(
  814. Value *const value,
  815. const IntConstantBounds &constantBounds,
  816. Value *const boundValue,
  817. const IntConstantBounds &boundConstantBounds,
  818. const int boundOffset,
  819. const bool isExplicit)
  820. {
  821. Assert(value || constantBounds.IsConstant());
  822. Assert(boundValue || boundConstantBounds.IsConstant());
  823. if(!value)
  824. {
  825. return nullptr;
  826. }
  827. Assert(!boundValue || value->GetValueNumber() != boundValue->GetValueNumber());
  828. ValueInfo *const valueInfo = value->GetValueInfo();
  829. IntBounds *const bounds =
  830. GetIntBoundsToUpdate(valueInfo, constantBounds, true, boundConstantBounds.IsConstant(), false, isExplicit);
  831. if(bounds)
  832. {
  833. if(boundValue)
  834. {
  835. bounds->SetLowerBound(value->GetValueNumber(), boundValue, boundOffset, isExplicit);
  836. }
  837. else
  838. {
  839. bounds->SetLowerBound(boundConstantBounds.LowerBound(), boundOffset);
  840. }
  841. if(bounds->RequiresIntBoundedValueInfo(valueInfo->Type()))
  842. {
  843. return NewIntBoundedValueInfo(valueInfo, bounds);
  844. }
  845. bounds->Delete();
  846. }
  847. if(!valueInfo->IsInt())
  848. {
  849. return nullptr;
  850. }
  851. int32 adjustedBoundMin;
  852. if(boundOffset == 0)
  853. {
  854. adjustedBoundMin = boundConstantBounds.LowerBound();
  855. }
  856. else if(boundOffset == 1)
  857. {
  858. if(boundConstantBounds.LowerBound() + 1 <= boundConstantBounds.LowerBound())
  859. {
  860. return nullptr;
  861. }
  862. adjustedBoundMin = boundConstantBounds.LowerBound() + 1;
  863. }
  864. else if(Int32Math::Add(boundConstantBounds.LowerBound(), boundOffset, &adjustedBoundMin))
  865. {
  866. return nullptr;
  867. }
  868. const int32 newMin = max(constantBounds.LowerBound(), adjustedBoundMin);
  869. return
  870. newMin <= constantBounds.UpperBound()
  871. ? NewIntRangeValueInfo(valueInfo, newMin, constantBounds.UpperBound())
  872. : nullptr;
  873. }
  874. ValueInfo *GlobOpt::UpdateIntBoundsForGreaterThan(
  875. Value *const value,
  876. const IntConstantBounds &constantBounds,
  877. Value *const boundValue,
  878. const IntConstantBounds &boundConstantBounds,
  879. const bool isExplicit)
  880. {
  881. return UpdateIntBoundsForGreaterThanOrEqual(value, constantBounds, boundValue, boundConstantBounds, 1, isExplicit);
  882. }
  883. ValueInfo *GlobOpt::UpdateIntBoundsForLessThanOrEqual(
  884. Value *const value,
  885. const IntConstantBounds &constantBounds,
  886. Value *const boundValue,
  887. const IntConstantBounds &boundConstantBounds,
  888. const bool isExplicit)
  889. {
  890. return UpdateIntBoundsForLessThanOrEqual(value, constantBounds, boundValue, boundConstantBounds, 0, isExplicit);
  891. }
  892. ValueInfo *GlobOpt::UpdateIntBoundsForLessThanOrEqual(
  893. Value *const value,
  894. const IntConstantBounds &constantBounds,
  895. Value *const boundValue,
  896. const IntConstantBounds &boundConstantBounds,
  897. const int boundOffset,
  898. const bool isExplicit)
  899. {
  900. Assert(value || constantBounds.IsConstant());
  901. Assert(boundValue || boundConstantBounds.IsConstant());
  902. if(!value)
  903. {
  904. return nullptr;
  905. }
  906. Assert(!boundValue || value->GetValueNumber() != boundValue->GetValueNumber());
  907. ValueInfo *const valueInfo = value->GetValueInfo();
  908. IntBounds *const bounds =
  909. GetIntBoundsToUpdate(valueInfo, constantBounds, true, boundConstantBounds.IsConstant(), true, isExplicit);
  910. if(bounds)
  911. {
  912. if(boundValue)
  913. {
  914. bounds->SetUpperBound(value->GetValueNumber(), boundValue, boundOffset, isExplicit);
  915. }
  916. else
  917. {
  918. bounds->SetUpperBound(boundConstantBounds.LowerBound(), boundOffset, isExplicit);
  919. }
  920. if(bounds->RequiresIntBoundedValueInfo(valueInfo->Type()))
  921. {
  922. return NewIntBoundedValueInfo(valueInfo, bounds);
  923. }
  924. bounds->Delete();
  925. }
  926. if(!valueInfo->IsInt())
  927. {
  928. return nullptr;
  929. }
  930. int32 adjustedBoundMax;
  931. if(boundOffset == 0)
  932. {
  933. adjustedBoundMax = boundConstantBounds.UpperBound();
  934. }
  935. else if(boundOffset == -1)
  936. {
  937. if(boundConstantBounds.UpperBound() - 1 >= boundConstantBounds.UpperBound())
  938. {
  939. return nullptr;
  940. }
  941. adjustedBoundMax = boundConstantBounds.UpperBound() - 1;
  942. }
  943. else if(Int32Math::Add(boundConstantBounds.UpperBound(), boundOffset, &adjustedBoundMax))
  944. {
  945. return nullptr;
  946. }
  947. const int32 newMax = min(constantBounds.UpperBound(), adjustedBoundMax);
  948. return
  949. newMax >= constantBounds.LowerBound()
  950. ? NewIntRangeValueInfo(valueInfo, constantBounds.LowerBound(), newMax)
  951. : nullptr;
  952. }
  953. ValueInfo *GlobOpt::UpdateIntBoundsForLessThan(
  954. Value *const value,
  955. const IntConstantBounds &constantBounds,
  956. Value *const boundValue,
  957. const IntConstantBounds &boundConstantBounds,
  958. const bool isExplicit)
  959. {
  960. return UpdateIntBoundsForLessThanOrEqual(value, constantBounds, boundValue, boundConstantBounds, -1, isExplicit);
  961. }
  962. void GlobOpt::TrackIntSpecializedAddSubConstant(
  963. IR::Instr *const instr,
  964. const AddSubConstantInfo *const addSubConstantInfo,
  965. Value *const dstValue,
  966. const bool updateSourceBounds)
  967. {
  968. Assert(instr);
  969. Assert(dstValue);
  970. if(addSubConstantInfo)
  971. {
  972. Assert(addSubConstantInfo->HasInfo());
  973. Assert(!ignoredIntOverflowForCurrentInstr);
  974. do
  975. {
  976. if(!IsLoopPrePass() || !DoBoundCheckHoist())
  977. {
  978. break;
  979. }
  980. Assert(
  981. instr->m_opcode == Js::OpCode::Incr_A ||
  982. instr->m_opcode == Js::OpCode::Decr_A ||
  983. instr->m_opcode == Js::OpCode::Add_A ||
  984. instr->m_opcode == Js::OpCode::Sub_A);
  985. StackSym *sym = instr->GetDst()->AsRegOpnd()->m_sym;
  986. bool isPostfixIncDecPattern = false;
  987. if(addSubConstantInfo->SrcSym() != sym)
  988. {
  989. // Check for the following patterns.
  990. //
  991. // This pattern is used for postfix inc/dec operators:
  992. // s2 = Conv_Num s1
  993. // s1 = Inc s2
  994. //
  995. // This pattern is used for prefix inc/dec operators:
  996. // s2 = Inc s1
  997. // s1 = Ld s2
  998. IR::Instr *const prevInstr = instr->m_prev;
  999. Assert(prevInstr);
  1000. if(prevInstr->m_opcode == Js::OpCode::Conv_Num &&
  1001. prevInstr->GetSrc1()->IsRegOpnd() &&
  1002. prevInstr->GetSrc1()->AsRegOpnd()->m_sym == sym &&
  1003. prevInstr->GetDst()->AsRegOpnd()->m_sym == addSubConstantInfo->SrcSym())
  1004. {
  1005. // s2 will get a new value number, since Conv_Num cannot transfer in the prepass. For the purposes of
  1006. // induction variable tracking however, it doesn't matter, so record this case and use s1's value in the
  1007. // current block.
  1008. isPostfixIncDecPattern = true;
  1009. }
  1010. else
  1011. {
  1012. IR::Instr *const nextInstr = instr->m_next;
  1013. Assert(nextInstr);
  1014. if(nextInstr->m_opcode != Js::OpCode::Ld_A ||
  1015. !nextInstr->GetSrc1()->IsRegOpnd() ||
  1016. nextInstr->GetSrc1()->AsRegOpnd()->m_sym != sym)
  1017. {
  1018. break;
  1019. }
  1020. sym = addSubConstantInfo->SrcSym();
  1021. if(nextInstr->GetDst()->AsRegOpnd()->m_sym != sym)
  1022. {
  1023. break;
  1024. }
  1025. // In the prefix inc/dec pattern, the result of Ld currently gets a new value number, which will cause the
  1026. // induction variable info to become indeterminate. Indicate that the value number should be updated in the
  1027. // induction variable info.
  1028. // Consider: Remove this once loop prepass value transfer scheme is fixed
  1029. updateInductionVariableValueNumber = true;
  1030. }
  1031. }
  1032. // Track induction variable info
  1033. ValueNumber srcValueNumber;
  1034. if(isPostfixIncDecPattern)
  1035. {
  1036. Value *const value = FindValue(sym);
  1037. Assert(value);
  1038. srcValueNumber = value->GetValueNumber();
  1039. }
  1040. else
  1041. {
  1042. srcValueNumber = addSubConstantInfo->SrcValue()->GetValueNumber();
  1043. }
  1044. InductionVariableSet *const inductionVariables = blockData.inductionVariables;
  1045. Assert(inductionVariables);
  1046. InductionVariable *inductionVariable;
  1047. if(!inductionVariables->TryGetReference(sym->m_id, &inductionVariable))
  1048. {
  1049. // Only track changes in the current loop's prepass. In subsequent prepasses, the info is only being propagated
  1050. // for use by the parent loop, so changes in the current loop have already been tracked.
  1051. if(prePassLoop != currentBlock->loop)
  1052. {
  1053. updateInductionVariableValueNumber = false;
  1054. break;
  1055. }
  1056. // Ensure that the sym is live in the landing pad, and that its value has not changed in an unknown way yet
  1057. Value *const landingPadValue = FindValue(currentBlock->loop->landingPad->globOptData.symToValueMap, sym);
  1058. if(!landingPadValue || srcValueNumber != landingPadValue->GetValueNumber())
  1059. {
  1060. updateInductionVariableValueNumber = false;
  1061. break;
  1062. }
  1063. inductionVariables->Add(
  1064. InductionVariable(sym, dstValue->GetValueNumber(), addSubConstantInfo->Offset()));
  1065. break;
  1066. }
  1067. if(!inductionVariable->IsChangeDeterminate())
  1068. {
  1069. updateInductionVariableValueNumber = false;
  1070. break;
  1071. }
  1072. if(srcValueNumber != inductionVariable->SymValueNumber())
  1073. {
  1074. // The sym's value has changed since the last time induction variable info was recorded for it. Due to the
  1075. // unknown change, mark the info as indeterminate.
  1076. inductionVariable->SetChangeIsIndeterminate();
  1077. updateInductionVariableValueNumber = false;
  1078. break;
  1079. }
  1080. // Only track changes in the current loop's prepass. In subsequent prepasses, the info is only being propagated for
  1081. // use by the parent loop, so changes in the current loop have already been tracked. Induction variable value
  1082. // numbers are updated as changes occur, but their change bounds are preserved from the first prepass over the loop.
  1083. inductionVariable->SetSymValueNumber(dstValue->GetValueNumber());
  1084. if(prePassLoop != currentBlock->loop)
  1085. {
  1086. break;
  1087. }
  1088. if(!inductionVariable->Add(addSubConstantInfo->Offset()))
  1089. {
  1090. updateInductionVariableValueNumber = false;
  1091. }
  1092. } while(false);
  1093. if(updateSourceBounds && addSubConstantInfo->Offset() != IntConstMin)
  1094. {
  1095. // Track bounds for add or sub with a constant. For instance, consider (b = a + 2). The value of 'b' should track
  1096. // that it is equal to (the value of 'a') + 2. That part has been done above. Similarly, the value of 'a' should
  1097. // also track that it is equal to (the value of 'b') - 2.
  1098. Value *const value = addSubConstantInfo->SrcValue();
  1099. const ValueInfo *const valueInfo = value->GetValueInfo();
  1100. Assert(valueInfo->IsInt());
  1101. IntConstantBounds constantBounds;
  1102. AssertVerify(valueInfo->TryGetIntConstantBounds(&constantBounds));
  1103. IntBounds *const bounds =
  1104. GetIntBoundsToUpdate(
  1105. valueInfo,
  1106. constantBounds,
  1107. true,
  1108. dstValue->GetValueInfo()->HasIntConstantValue(),
  1109. true,
  1110. true);
  1111. if(bounds)
  1112. {
  1113. const ValueNumber valueNumber = value->GetValueNumber();
  1114. const int32 dstOffset = -addSubConstantInfo->Offset();
  1115. bounds->SetLowerBound(valueNumber, dstValue, dstOffset, true);
  1116. bounds->SetUpperBound(valueNumber, dstValue, dstOffset, true);
  1117. ChangeValueInfo(nullptr, value, NewIntBoundedValueInfo(valueInfo, bounds));
  1118. }
  1119. }
  1120. return;
  1121. }
  1122. if(!updateInductionVariableValueNumber)
  1123. {
  1124. return;
  1125. }
  1126. // See comment above where this is set to true
  1127. // Consider: Remove this once loop prepass value transfer scheme is fixed
  1128. updateInductionVariableValueNumber = false;
  1129. Assert(IsLoopPrePass());
  1130. Assert(instr->m_opcode == Js::OpCode::Ld_A);
  1131. Assert(
  1132. instr->m_prev->m_opcode == Js::OpCode::Incr_A ||
  1133. instr->m_prev->m_opcode == Js::OpCode::Decr_A ||
  1134. instr->m_prev->m_opcode == Js::OpCode::Add_A ||
  1135. instr->m_prev->m_opcode == Js::OpCode::Sub_A);
  1136. Assert(instr->m_prev->GetDst()->AsRegOpnd()->m_sym == instr->GetSrc1()->AsRegOpnd()->m_sym);
  1137. InductionVariable *inductionVariable;
  1138. AssertVerify(blockData.inductionVariables->TryGetReference(instr->GetDst()->AsRegOpnd()->m_sym->m_id, &inductionVariable));
  1139. inductionVariable->SetSymValueNumber(dstValue->GetValueNumber());
  1140. }
  1141. void GlobOpt::CloneBoundCheckHoistBlockData(
  1142. BasicBlock *const toBlock,
  1143. GlobOptBlockData *const toData,
  1144. BasicBlock *const fromBlock,
  1145. GlobOptBlockData *const fromData)
  1146. {
  1147. Assert(DoBoundCheckHoist());
  1148. Assert(toBlock);
  1149. Assert(toData);
  1150. Assert(toData == &toBlock->globOptData || toData == &blockData);
  1151. Assert(fromBlock);
  1152. Assert(fromData);
  1153. Assert(fromData == &fromBlock->globOptData);
  1154. Assert(fromData->availableIntBoundChecks);
  1155. toData->availableIntBoundChecks = fromData->availableIntBoundChecks->Clone();
  1156. if(toBlock->isLoopHeader)
  1157. {
  1158. Assert(fromBlock == toBlock->loop->landingPad);
  1159. if(prePassLoop == toBlock->loop)
  1160. {
  1161. // When the current prepass loop is the current loop, the loop header's induction variable set needs to start off
  1162. // empty to track changes in the current loop
  1163. toData->inductionVariables = JitAnew(alloc, InductionVariableSet, alloc);
  1164. return;
  1165. }
  1166. if(!IsLoopPrePass())
  1167. {
  1168. return;
  1169. }
  1170. // After the prepass on this loop, if we're still in a prepass, this must be an inner loop. Merge the landing pad info
  1171. // for use by the parent loop.
  1172. Assert(fromBlock->loop);
  1173. Assert(fromData->inductionVariables);
  1174. toData->inductionVariables = fromData->inductionVariables->Clone();
  1175. return;
  1176. }
  1177. if(!toBlock->loop || !IsLoopPrePass())
  1178. {
  1179. return;
  1180. }
  1181. Assert(fromBlock->loop);
  1182. Assert(toBlock->loop->IsDescendentOrSelf(fromBlock->loop));
  1183. Assert(fromData->inductionVariables);
  1184. toData->inductionVariables = fromData->inductionVariables->Clone();
  1185. }
  1186. void GlobOpt::MergeBoundCheckHoistBlockData(
  1187. BasicBlock *const toBlock,
  1188. GlobOptBlockData *const toData,
  1189. BasicBlock *const fromBlock,
  1190. GlobOptBlockData *const fromData)
  1191. {
  1192. Assert(DoBoundCheckHoist());
  1193. Assert(toBlock);
  1194. Assert(toData);
  1195. Assert(toData == &toBlock->globOptData || toData == &blockData);
  1196. Assert(fromBlock);
  1197. Assert(fromData);
  1198. Assert(fromData == &fromBlock->globOptData);
  1199. Assert(toData->availableIntBoundChecks);
  1200. for(auto it = toData->availableIntBoundChecks->GetIteratorWithRemovalSupport(); it.IsValid(); it.MoveNext())
  1201. {
  1202. const IntBoundCheck &toDataIntBoundCheck = it.CurrentValue();
  1203. const IntBoundCheck *fromDataIntBoundCheck;
  1204. if(!fromData->availableIntBoundChecks->TryGetReference(
  1205. toDataIntBoundCheck.CompatibilityId(),
  1206. &fromDataIntBoundCheck) ||
  1207. fromDataIntBoundCheck->Instr() != toDataIntBoundCheck.Instr())
  1208. {
  1209. it.RemoveCurrent();
  1210. }
  1211. }
  1212. InductionVariableSet *mergeInductionVariablesInto;
  1213. if(toBlock->isLoopHeader)
  1214. {
  1215. Assert(fromBlock->loop == toBlock->loop); // The flow is such that you cannot have back-edges from an inner loop
  1216. if(IsLoopPrePass())
  1217. {
  1218. // Collect info for the parent loop. Any changes to induction variables in this inner loop need to be expanded in
  1219. // the same direction for the parent loop, so merge expanded info from back-edges. Info about induction variables
  1220. // that changed before the loop but not inside the loop, can be kept intact because the landing pad dominates the
  1221. // loop.
  1222. Assert(prePassLoop != toBlock->loop);
  1223. Assert(fromData->inductionVariables);
  1224. Assert(toData->inductionVariables);
  1225. InductionVariableSet *const mergedInductionVariables = toData->inductionVariables;
  1226. for(auto it = fromData->inductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
  1227. {
  1228. InductionVariable backEdgeInductionVariable = it.CurrentValue();
  1229. backEdgeInductionVariable.ExpandInnerLoopChange();
  1230. StackSym *const sym = backEdgeInductionVariable.Sym();
  1231. InductionVariable *mergedInductionVariable;
  1232. if(mergedInductionVariables->TryGetReference(sym->m_id, &mergedInductionVariable))
  1233. {
  1234. mergedInductionVariable->Merge(backEdgeInductionVariable);
  1235. continue;
  1236. }
  1237. // Ensure that the sym is live in the parent loop's landing pad, and that its value has not changed in an
  1238. // unknown way between the parent loop's landing pad and the current loop's landing pad.
  1239. Value *const parentLandingPadValue =
  1240. FindValue(currentBlock->loop->parent->landingPad->globOptData.symToValueMap, sym);
  1241. if(!parentLandingPadValue)
  1242. {
  1243. continue;
  1244. }
  1245. Value *const landingPadValue = FindValue(currentBlock->loop->landingPad->globOptData.symToValueMap, sym);
  1246. Assert(landingPadValue);
  1247. if(landingPadValue->GetValueNumber() == parentLandingPadValue->GetValueNumber())
  1248. {
  1249. mergedInductionVariables->Add(backEdgeInductionVariable);
  1250. }
  1251. }
  1252. return;
  1253. }
  1254. // Collect info for the current loop. We want to merge only the back-edge info without the landing pad info, such that
  1255. // the loop's induction variable set reflects changes made inside this loop.
  1256. Assert(fromData->inductionVariables);
  1257. InductionVariableSet *&loopInductionVariables = toBlock->loop->inductionVariables;
  1258. if(!loopInductionVariables)
  1259. {
  1260. loopInductionVariables = fromData->inductionVariables->Clone();
  1261. return;
  1262. }
  1263. mergeInductionVariablesInto = loopInductionVariables;
  1264. }
  1265. else if(toBlock->loop && IsLoopPrePass())
  1266. {
  1267. Assert(fromBlock->loop);
  1268. Assert(toBlock->loop->IsDescendentOrSelf(fromBlock->loop));
  1269. mergeInductionVariablesInto = toData->inductionVariables;
  1270. }
  1271. else
  1272. {
  1273. return;
  1274. }
  1275. const InductionVariableSet *const fromDataInductionVariables = fromData->inductionVariables;
  1276. InductionVariableSet *const mergedInductionVariables = mergeInductionVariablesInto;
  1277. Assert(fromDataInductionVariables);
  1278. Assert(mergedInductionVariables);
  1279. for(auto it = mergedInductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
  1280. {
  1281. InductionVariable &mergedInductionVariable = it.CurrentValueReference();
  1282. if(!mergedInductionVariable.IsChangeDeterminate())
  1283. {
  1284. continue;
  1285. }
  1286. StackSym *const sym = mergedInductionVariable.Sym();
  1287. const InductionVariable *fromDataInductionVariable;
  1288. if(fromDataInductionVariables->TryGetReference(sym->m_id, &fromDataInductionVariable))
  1289. {
  1290. mergedInductionVariable.Merge(*fromDataInductionVariable);
  1291. continue;
  1292. }
  1293. // 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
  1294. // where the sym is not already marked as an induction variable.
  1295. Value *const fromDataValue = FindValue(fromData->symToValueMap, sym);
  1296. if(fromDataValue)
  1297. {
  1298. Value *const landingPadValue = FindValue(toBlock->loop->landingPad->globOptData.symToValueMap, sym);
  1299. if(landingPadValue && fromDataValue->GetValueNumber() == landingPadValue->GetValueNumber())
  1300. {
  1301. mergedInductionVariable.Merge(InductionVariable(sym, ZeroValueNumber, 0));
  1302. continue;
  1303. }
  1304. }
  1305. mergedInductionVariable.SetChangeIsIndeterminate();
  1306. }
  1307. for(auto it = fromDataInductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
  1308. {
  1309. const InductionVariable &fromDataInductionVariable = it.CurrentValue();
  1310. StackSym *const sym = fromDataInductionVariable.Sym();
  1311. if(mergedInductionVariables->ContainsKey(sym->m_id))
  1312. {
  1313. continue;
  1314. }
  1315. // 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
  1316. // where the sym is not already marked as an induction variable.
  1317. bool indeterminate = true;
  1318. Value *const toDataValue = FindValue(toData->symToValueMap, sym);
  1319. if(toDataValue)
  1320. {
  1321. Value *const landingPadValue = FindValue(toBlock->loop->landingPad->globOptData.symToValueMap, sym);
  1322. if(landingPadValue && toDataValue->GetValueNumber() == landingPadValue->GetValueNumber())
  1323. {
  1324. indeterminate = false;
  1325. }
  1326. }
  1327. InductionVariable mergedInductionVariable(sym, ZeroValueNumber, 0);
  1328. if(indeterminate)
  1329. {
  1330. mergedInductionVariable.SetChangeIsIndeterminate();
  1331. }
  1332. else
  1333. {
  1334. mergedInductionVariable.Merge(fromDataInductionVariable);
  1335. }
  1336. mergedInductionVariables->Add(mergedInductionVariable);
  1337. }
  1338. }
  1339. void GlobOpt::DetectUnknownChangesToInductionVariables(GlobOptBlockData *const blockData)
  1340. {
  1341. Assert(DoBoundCheckHoist());
  1342. Assert(IsLoopPrePass());
  1343. Assert(blockData);
  1344. Assert(blockData->inductionVariables);
  1345. // Check induction variable value numbers, and mark those that changed in an unknown way as indeterminate. They must remain
  1346. // in the set though, for merging purposes.
  1347. GlobHashTable *const symToValueMap = blockData->symToValueMap;
  1348. for(auto it = blockData->inductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
  1349. {
  1350. InductionVariable &inductionVariable = it.CurrentValueReference();
  1351. if(!inductionVariable.IsChangeDeterminate())
  1352. {
  1353. continue;
  1354. }
  1355. Value *const value = FindValue(symToValueMap, inductionVariable.Sym());
  1356. if(!value || value->GetValueNumber() != inductionVariable.SymValueNumber())
  1357. {
  1358. inductionVariable.SetChangeIsIndeterminate();
  1359. }
  1360. }
  1361. }
  1362. void GlobOpt::SetInductionVariableValueNumbers(GlobOptBlockData *const blockData)
  1363. {
  1364. Assert(DoBoundCheckHoist());
  1365. Assert(IsLoopPrePass());
  1366. Assert(blockData == &this->blockData);
  1367. Assert(blockData->inductionVariables);
  1368. // Now that all values have been merged, update value numbers in the induction variable info.
  1369. GlobHashTable *const symToValueMap = blockData->symToValueMap;
  1370. for(auto it = blockData->inductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
  1371. {
  1372. InductionVariable &inductionVariable = it.CurrentValueReference();
  1373. if(!inductionVariable.IsChangeDeterminate())
  1374. {
  1375. continue;
  1376. }
  1377. Value *const value = FindValue(symToValueMap, inductionVariable.Sym());
  1378. if(value)
  1379. {
  1380. inductionVariable.SetSymValueNumber(value->GetValueNumber());
  1381. }
  1382. else
  1383. {
  1384. inductionVariable.SetChangeIsIndeterminate();
  1385. }
  1386. }
  1387. }
  1388. void GlobOpt::FinalizeInductionVariables(Loop *const loop, GlobOptBlockData *const headerData)
  1389. {
  1390. Assert(DoBoundCheckHoist());
  1391. Assert(!IsLoopPrePass());
  1392. Assert(loop);
  1393. Assert(loop->GetHeadBlock() == currentBlock);
  1394. Assert(loop->inductionVariables);
  1395. Assert(currentBlock->isLoopHeader);
  1396. Assert(headerData == &this->blockData);
  1397. // Clean up induction variables and for each, install a relationship between its values inside and outside the loop.
  1398. GlobHashTable *const symToValueMap = headerData->symToValueMap;
  1399. GlobOptBlockData &landingPadBlockData = loop->landingPad->globOptData;
  1400. GlobHashTable *const landingPadSymToValueMap = landingPadBlockData.symToValueMap;
  1401. for(auto it = loop->inductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
  1402. {
  1403. InductionVariable &inductionVariable = it.CurrentValueReference();
  1404. if(!inductionVariable.IsChangeDeterminate())
  1405. {
  1406. continue;
  1407. }
  1408. if(!inductionVariable.IsChangeUnidirectional())
  1409. {
  1410. inductionVariable.SetChangeIsIndeterminate();
  1411. continue;
  1412. }
  1413. StackSym *const sym = inductionVariable.Sym();
  1414. if(!IsInt32TypeSpecialized(sym, headerData))
  1415. {
  1416. inductionVariable.SetChangeIsIndeterminate();
  1417. continue;
  1418. }
  1419. Assert(IsInt32TypeSpecialized(sym, &landingPadBlockData));
  1420. Value *const value = FindValue(symToValueMap, sym);
  1421. if(!value)
  1422. {
  1423. inductionVariable.SetChangeIsIndeterminate();
  1424. continue;
  1425. }
  1426. Value *const landingPadValue = FindValue(landingPadSymToValueMap, sym);
  1427. Assert(landingPadValue);
  1428. IntConstantBounds constantBounds, landingPadConstantBounds;
  1429. AssertVerify(value->GetValueInfo()->TryGetIntConstantBounds(&constantBounds));
  1430. AssertVerify(landingPadValue->GetValueInfo()->TryGetIntConstantBounds(&landingPadConstantBounds, true));
  1431. // For an induction variable i, update the value of i inside the loop to indicate that it is bounded by the value of i
  1432. // just before the loop.
  1433. if(inductionVariable.ChangeBounds().LowerBound() >= 0)
  1434. {
  1435. ValueInfo *const newValueInfo =
  1436. UpdateIntBoundsForGreaterThanOrEqual(value, constantBounds, landingPadValue, landingPadConstantBounds, true);
  1437. ChangeValueInfo(nullptr, value, newValueInfo);
  1438. if(inductionVariable.ChangeBounds().UpperBound() == 0)
  1439. {
  1440. AssertVerify(newValueInfo->TryGetIntConstantBounds(&constantBounds, true));
  1441. }
  1442. }
  1443. if(inductionVariable.ChangeBounds().UpperBound() <= 0)
  1444. {
  1445. ValueInfo *const newValueInfo =
  1446. UpdateIntBoundsForLessThanOrEqual(value, constantBounds, landingPadValue, landingPadConstantBounds, true);
  1447. ChangeValueInfo(nullptr, value, newValueInfo);
  1448. }
  1449. }
  1450. }
  1451. bool GlobOpt::DetermineSymBoundOffsetOrValueRelativeToLandingPad(
  1452. StackSym *const sym,
  1453. const bool landingPadValueIsLowerBound,
  1454. ValueInfo *const valueInfo,
  1455. const IntBounds *const bounds,
  1456. GlobHashTable *const landingPadSymToValueMap,
  1457. int *const boundOffsetOrValueRef)
  1458. {
  1459. Assert(sym);
  1460. Assert(!sym->IsTypeSpec());
  1461. Assert(valueInfo);
  1462. Assert(landingPadSymToValueMap);
  1463. Assert(boundOffsetOrValueRef);
  1464. Assert(valueInfo->IsInt());
  1465. int constantValue;
  1466. if(valueInfo->TryGetIntConstantValue(&constantValue))
  1467. {
  1468. // The sym's constant value is the constant bound value, so just return that. This is possible in loops such as
  1469. // for(; i === 1; ++i){...}, where 'i' is an induction variable but has a constant value inside the loop, or in blocks
  1470. // inside the loop such as if(i === 1){...}
  1471. *boundOffsetOrValueRef = constantValue;
  1472. return true; // 'true' indicates that *boundOffsetOrValueRef contains the constant bound value
  1473. }
  1474. Value *const landingPadValue = FindValue(landingPadSymToValueMap, sym);
  1475. Assert(landingPadValue);
  1476. Assert(landingPadValue->GetValueInfo()->IsInt());
  1477. int landingPadConstantValue;
  1478. if(landingPadValue->GetValueInfo()->TryGetIntConstantValue(&landingPadConstantValue))
  1479. {
  1480. // The sym's bound already takes the landing pad constant value into consideration, unless the landing pad value was
  1481. // updated to have a more aggressive range (and hence, now a constant value) as part of hoisting a bound check or some
  1482. // other hoisting operation. The sym's bound also takes into consideration the change to the sym so far inside the loop,
  1483. // and the landing pad constant value does not, so use the sym's bound by default.
  1484. int constantBound;
  1485. if(bounds)
  1486. {
  1487. constantBound = landingPadValueIsLowerBound ? bounds->ConstantLowerBound() : bounds->ConstantUpperBound();
  1488. }
  1489. else
  1490. {
  1491. AssertVerify(
  1492. landingPadValueIsLowerBound
  1493. ? valueInfo->TryGetIntConstantLowerBound(&constantBound)
  1494. : valueInfo->TryGetIntConstantUpperBound(&constantBound));
  1495. }
  1496. if(landingPadValueIsLowerBound ? landingPadConstantValue > constantBound : landingPadConstantValue < constantBound)
  1497. {
  1498. // The landing pad value became a constant value as part of a hoisting operation. The landing pad constant value is
  1499. // a more aggressive bound, so use that instead, and take into consideration the change to the sym so far inside the
  1500. // loop, using the relative bound to the landing pad value.
  1501. AnalysisAssert(bounds);
  1502. const ValueRelativeOffset *bound;
  1503. AssertVerify(
  1504. (landingPadValueIsLowerBound ? bounds->RelativeLowerBounds() : bounds->RelativeUpperBounds())
  1505. .TryGetReference(landingPadValue->GetValueNumber(), &bound));
  1506. constantBound = landingPadConstantValue + bound->Offset();
  1507. }
  1508. *boundOffsetOrValueRef = constantBound;
  1509. return true; // 'true' indicates that *boundOffsetOrValueRef contains the constant bound value
  1510. }
  1511. AnalysisAssert(bounds);
  1512. const ValueRelativeOffset *bound;
  1513. AssertVerify(
  1514. (landingPadValueIsLowerBound ? bounds->RelativeLowerBounds() : bounds->RelativeUpperBounds())
  1515. .TryGetReference(landingPadValue->GetValueNumber(), &bound));
  1516. *boundOffsetOrValueRef = bound->Offset();
  1517. // 'false' indicates that *boundOffsetOrValueRef contains the bound offset, which must be added to the sym's value in the
  1518. // landing pad to get the bound value
  1519. return false;
  1520. }
  1521. void GlobOpt::DetermineDominatingLoopCountableBlock(Loop *const loop, BasicBlock *const headerBlock)
  1522. {
  1523. Assert(DoLoopCountBasedBoundCheckHoist());
  1524. Assert(!IsLoopPrePass());
  1525. Assert(loop);
  1526. Assert(headerBlock);
  1527. Assert(headerBlock->isLoopHeader);
  1528. Assert(headerBlock->loop == loop);
  1529. // Determine if the loop header has a unique successor that is inside the loop. If so, then all other paths out of the loop
  1530. // header exit the loop, allowing a loop count to be established and used from the unique in-loop successor block.
  1531. Assert(!loop->dominatingLoopCountableBlock);
  1532. FOREACH_SUCCESSOR_BLOCK(successor, headerBlock)
  1533. {
  1534. if(successor->loop != loop)
  1535. {
  1536. Assert(!successor->loop || successor->loop->IsDescendentOrSelf(loop->parent));
  1537. continue;
  1538. }
  1539. if(loop->dominatingLoopCountableBlock)
  1540. {
  1541. // Found a second successor inside the loop
  1542. loop->dominatingLoopCountableBlock = nullptr;
  1543. break;
  1544. }
  1545. loop->dominatingLoopCountableBlock = successor;
  1546. } NEXT_SUCCESSOR_BLOCK;
  1547. }
  1548. void GlobOpt::DetermineLoopCount(Loop *const loop)
  1549. {
  1550. Assert(DoLoopCountBasedBoundCheckHoist());
  1551. Assert(loop);
  1552. GlobOptBlockData &landingPadBlockData = loop->landingPad->globOptData;
  1553. GlobHashTable *const landingPadSymToValueMap = landingPadBlockData.symToValueMap;
  1554. const InductionVariableSet *const inductionVariables = loop->inductionVariables;
  1555. Assert(inductionVariables);
  1556. for(auto it = inductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
  1557. {
  1558. InductionVariable &inductionVariable = it.CurrentValueReference();
  1559. if(!inductionVariable.IsChangeDeterminate())
  1560. {
  1561. continue;
  1562. }
  1563. // Determine the minimum-magnitude change per iteration, and verify that the change is nonzero and finite
  1564. Assert(inductionVariable.IsChangeUnidirectional());
  1565. int minMagnitudeChange = inductionVariable.ChangeBounds().LowerBound();
  1566. if(minMagnitudeChange >= 0)
  1567. {
  1568. if(minMagnitudeChange == 0 || minMagnitudeChange == IntConstMax)
  1569. {
  1570. continue;
  1571. }
  1572. }
  1573. else
  1574. {
  1575. minMagnitudeChange = inductionVariable.ChangeBounds().UpperBound();
  1576. Assert(minMagnitudeChange <= 0);
  1577. if(minMagnitudeChange == 0 || minMagnitudeChange == IntConstMin)
  1578. {
  1579. continue;
  1580. }
  1581. }
  1582. StackSym *const inductionVariableVarSym = inductionVariable.Sym();
  1583. if(!IsInt32TypeSpecialized(inductionVariableVarSym, &blockData))
  1584. {
  1585. inductionVariable.SetChangeIsIndeterminate();
  1586. continue;
  1587. }
  1588. Assert(IsInt32TypeSpecialized(inductionVariableVarSym, &landingPadBlockData));
  1589. Value *const inductionVariableValue = FindValue(inductionVariableVarSym);
  1590. if(!inductionVariableValue)
  1591. {
  1592. inductionVariable.SetChangeIsIndeterminate();
  1593. continue;
  1594. }
  1595. ValueInfo *const inductionVariableValueInfo = inductionVariableValue->GetValueInfo();
  1596. const IntBounds *const inductionVariableBounds =
  1597. inductionVariableValueInfo->IsIntBounded() ? inductionVariableValueInfo->AsIntBounded()->Bounds() : nullptr;
  1598. // Look for an invariant bound in the direction of change
  1599. StackSym *boundBaseVarSym = nullptr;
  1600. int boundOffset = 0;
  1601. {
  1602. bool foundBound = false;
  1603. if(inductionVariableBounds)
  1604. {
  1605. // Look for a relative bound
  1606. for(auto it =
  1607. (
  1608. minMagnitudeChange >= 0
  1609. ? inductionVariableBounds->RelativeUpperBounds()
  1610. : inductionVariableBounds->RelativeLowerBounds()
  1611. ).GetIterator();
  1612. it.IsValid();
  1613. it.MoveNext())
  1614. {
  1615. const ValueRelativeOffset &bound = it.CurrentValue();
  1616. boundBaseVarSym = bound.BaseSym();
  1617. if(!boundBaseVarSym || !IsInt32TypeSpecialized(boundBaseVarSym, &landingPadBlockData))
  1618. {
  1619. continue;
  1620. }
  1621. Value *const boundBaseValue = FindValue(boundBaseVarSym);
  1622. const ValueNumber boundBaseValueNumber = bound.BaseValueNumber();
  1623. if(!boundBaseValue || boundBaseValue->GetValueNumber() != boundBaseValueNumber)
  1624. {
  1625. continue;
  1626. }
  1627. Value *const landingPadBoundBaseValue = FindValue(landingPadSymToValueMap, boundBaseVarSym);
  1628. if(!landingPadBoundBaseValue || landingPadBoundBaseValue->GetValueNumber() != boundBaseValueNumber)
  1629. {
  1630. continue;
  1631. }
  1632. boundOffset = bound.Offset();
  1633. foundBound = true;
  1634. break;
  1635. }
  1636. }
  1637. if(!foundBound)
  1638. {
  1639. // No useful relative bound found; look for a constant bound. Exclude large constant bounds established implicitly by
  1640. // <, <=, >, and >=. For example, for a loop condition (i < n), if 'n' is not invariant and hence can't be used,
  1641. // 'i' will still have a constant upper bound of (int32 max - 1) that should be excluded as it's too large. Any
  1642. // other constant bounds must have been established explicitly by the loop condition, and are safe to use.
  1643. boundBaseVarSym = nullptr;
  1644. if(minMagnitudeChange >= 0)
  1645. {
  1646. if(inductionVariableBounds)
  1647. {
  1648. boundOffset = inductionVariableBounds->ConstantUpperBound();
  1649. }
  1650. else
  1651. {
  1652. AssertVerify(inductionVariableValueInfo->TryGetIntConstantUpperBound(&boundOffset));
  1653. }
  1654. if(boundOffset >= IntConstMax - 1)
  1655. {
  1656. continue;
  1657. }
  1658. }
  1659. else
  1660. {
  1661. if(inductionVariableBounds)
  1662. {
  1663. boundOffset = inductionVariableBounds->ConstantLowerBound();
  1664. }
  1665. else
  1666. {
  1667. AssertVerify(inductionVariableValueInfo->TryGetIntConstantLowerBound(&boundOffset));
  1668. }
  1669. if(boundOffset <= IntConstMin + 1)
  1670. {
  1671. continue;
  1672. }
  1673. }
  1674. }
  1675. }
  1676. // Determine if the induction variable already changed in the loop, and by how much
  1677. int inductionVariableOffset;
  1678. StackSym *inductionVariableSymToAdd;
  1679. if(DetermineSymBoundOffsetOrValueRelativeToLandingPad(
  1680. inductionVariableVarSym,
  1681. minMagnitudeChange >= 0,
  1682. inductionVariableValueInfo,
  1683. inductionVariableBounds,
  1684. landingPadSymToValueMap,
  1685. &inductionVariableOffset))
  1686. {
  1687. // The bound value is constant
  1688. inductionVariableSymToAdd = nullptr;
  1689. }
  1690. else
  1691. {
  1692. // The bound value is not constant, the offset needs to be added to the induction variable in the landing pad
  1693. inductionVariableSymToAdd = inductionVariableVarSym->GetInt32EquivSym(nullptr);
  1694. Assert(inductionVariableSymToAdd);
  1695. }
  1696. // Int operands are required
  1697. StackSym *boundBaseSym;
  1698. if(boundBaseVarSym)
  1699. {
  1700. boundBaseSym = boundBaseVarSym->IsVar() ? boundBaseVarSym->GetInt32EquivSym(nullptr) : boundBaseVarSym;
  1701. Assert(boundBaseSym);
  1702. Assert(boundBaseSym->GetType() == TyInt32 || boundBaseSym->GetType() == TyUint32);
  1703. }
  1704. else
  1705. {
  1706. boundBaseSym = nullptr;
  1707. }
  1708. // The loop count is computed as follows. We're actually computing the loop count minus one, because the value is used
  1709. // to determine the bound of a secondary induction variable in its direction of change, and at that point the secondary
  1710. // induction variable's information already accounts for changes in the first loop iteration.
  1711. //
  1712. // If the induction variable increases in the loop:
  1713. // loopCountMinusOne = (upperBound - inductionVariable) / abs(minMagnitudeChange)
  1714. // Or more precisely:
  1715. // loopCountMinusOne =
  1716. // ((boundBase - inductionVariable) + (boundOffset - inductionVariableOffset)) / abs(minMagnitudeChange)
  1717. //
  1718. // If the induction variable decreases in the loop, the subtract operands are just reversed to yield a nonnegative
  1719. // number, and the rest is similar. The two offsets are also constant and can be folded. So in general:
  1720. // loopCountMinusOne = (left - right + offset) / abs(minMagnitudeChange)
  1721. // Determine the left and right information
  1722. StackSym *leftSym, *rightSym;
  1723. int leftOffset, rightOffset;
  1724. if(minMagnitudeChange >= 0)
  1725. {
  1726. leftSym = boundBaseSym;
  1727. leftOffset = boundOffset;
  1728. rightSym = inductionVariableSymToAdd;
  1729. rightOffset = inductionVariableOffset;
  1730. }
  1731. else
  1732. {
  1733. minMagnitudeChange = -minMagnitudeChange;
  1734. leftSym = inductionVariableSymToAdd;
  1735. leftOffset = inductionVariableOffset;
  1736. rightSym = boundBaseSym;
  1737. rightOffset = boundOffset;
  1738. }
  1739. // Determine the combined offset, and save the info necessary to generate the loop count
  1740. int offset;
  1741. if(Int32Math::Sub(leftOffset, rightOffset, &offset))
  1742. {
  1743. continue;
  1744. }
  1745. void *const loopCountBuffer = JitAnewArray(this->func->GetTopFunc()->m_fg->alloc, byte, sizeof(LoopCount));
  1746. if(!rightSym)
  1747. {
  1748. if(!leftSym)
  1749. {
  1750. loop->loopCount = new(loopCountBuffer) LoopCount(offset / minMagnitudeChange);
  1751. break;
  1752. }
  1753. if(offset == 0 && minMagnitudeChange == 1)
  1754. {
  1755. loop->loopCount = new(loopCountBuffer) LoopCount(leftSym);
  1756. break;
  1757. }
  1758. }
  1759. loop->loopCount = new(loopCountBuffer) LoopCount(leftSym, rightSym, offset, minMagnitudeChange);
  1760. break;
  1761. }
  1762. }
  1763. void GlobOpt::GenerateLoopCount(Loop *const loop, LoopCount *const loopCount)
  1764. {
  1765. Assert(DoLoopCountBasedBoundCheckHoist());
  1766. Assert(loop);
  1767. Assert(loopCount);
  1768. Assert(loopCount == loop->loopCount);
  1769. Assert(!loopCount->HasBeenGenerated());
  1770. // loopCountMinusOne = (left - right + offset) / minMagnitudeChange
  1771. // Prepare the landing pad for bailouts and instruction insertion
  1772. BailOutInfo *const bailOutInfo = loop->bailOutInfo;
  1773. Assert(bailOutInfo);
  1774. const IR::BailOutKind bailOutKind = IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck;
  1775. IR::Instr *const insertBeforeInstr = bailOutInfo->bailOutInstr;
  1776. Assert(insertBeforeInstr);
  1777. Func *const func = bailOutInfo->bailOutFunc;
  1778. // intermediateValue = left - right
  1779. IR::IntConstOpnd *offset =
  1780. loopCount->Offset() == 0 ? nullptr : IR::IntConstOpnd::New(loopCount->Offset(), TyInt32, func, true);
  1781. StackSym *const rightSym = loopCount->RightSym();
  1782. StackSym *intermediateValueSym;
  1783. if(rightSym)
  1784. {
  1785. IR::BailOutInstr *const instr = IR::BailOutInstr::New(Js::OpCode::Sub_I4, bailOutKind, bailOutInfo, func);
  1786. instr->SetSrc2(IR::RegOpnd::New(rightSym, rightSym->GetType(), func));
  1787. instr->GetSrc2()->SetIsJITOptimizedReg(true);
  1788. StackSym *const leftSym = loopCount->LeftSym();
  1789. if(leftSym)
  1790. {
  1791. // intermediateValue = left - right
  1792. instr->SetSrc1(IR::RegOpnd::New(leftSym, leftSym->GetType(), func));
  1793. instr->GetSrc1()->SetIsJITOptimizedReg(true);
  1794. }
  1795. else if(offset)
  1796. {
  1797. // intermediateValue = offset - right
  1798. instr->SetSrc1(offset);
  1799. offset = nullptr;
  1800. }
  1801. else
  1802. {
  1803. // intermediateValue = -right
  1804. instr->m_opcode = Js::OpCode::Neg_I4;
  1805. instr->SetSrc1(instr->UnlinkSrc2());
  1806. }
  1807. intermediateValueSym = StackSym::New(TyInt32, func);
  1808. instr->SetDst(IR::RegOpnd::New(intermediateValueSym, intermediateValueSym->GetType(), func));
  1809. instr->GetDst()->SetIsJITOptimizedReg(true);
  1810. instr->SetByteCodeOffset(insertBeforeInstr);
  1811. insertBeforeInstr->InsertBefore(instr);
  1812. }
  1813. else
  1814. {
  1815. // intermediateValue = left
  1816. Assert(loopCount->LeftSym());
  1817. intermediateValueSym = loopCount->LeftSym();
  1818. }
  1819. // intermediateValue += offset
  1820. if(offset)
  1821. {
  1822. IR::BailOutInstr *const instr = IR::BailOutInstr::New(Js::OpCode::Add_I4, bailOutKind, bailOutInfo, func);
  1823. instr->SetSrc1(IR::RegOpnd::New(intermediateValueSym, intermediateValueSym->GetType(), func));
  1824. instr->GetSrc1()->SetIsJITOptimizedReg(true);
  1825. if(offset->GetValue() < 0 && offset->GetValue() != IntConstMin)
  1826. {
  1827. instr->m_opcode = Js::OpCode::Sub_I4;
  1828. offset->SetValue(-offset->GetValue());
  1829. }
  1830. instr->SetSrc2(offset);
  1831. if(intermediateValueSym == loopCount->LeftSym())
  1832. {
  1833. intermediateValueSym = StackSym::New(TyInt32, func);
  1834. }
  1835. instr->SetDst(IR::RegOpnd::New(intermediateValueSym, intermediateValueSym->GetType(), func));
  1836. instr->GetDst()->SetIsJITOptimizedReg(true);
  1837. instr->SetByteCodeOffset(insertBeforeInstr);
  1838. insertBeforeInstr->InsertBefore(instr);
  1839. }
  1840. // intermediateValue /= minMagnitudeChange
  1841. const int minMagnitudeChange = loopCount->MinMagnitudeChange();
  1842. if(minMagnitudeChange != 1)
  1843. {
  1844. IR::Instr *const instr = IR::Instr::New(Js::OpCode::Div_I4, func);
  1845. instr->SetSrc1(IR::RegOpnd::New(intermediateValueSym, intermediateValueSym->GetType(), func));
  1846. instr->GetSrc1()->SetIsJITOptimizedReg(true);
  1847. Assert(minMagnitudeChange != 0); // bailout is not needed
  1848. instr->SetSrc2(IR::IntConstOpnd::New(minMagnitudeChange, TyInt32, func, true));
  1849. if(intermediateValueSym == loopCount->LeftSym())
  1850. {
  1851. intermediateValueSym = StackSym::New(TyInt32, func);
  1852. }
  1853. instr->SetDst(IR::RegOpnd::New(intermediateValueSym, intermediateValueSym->GetType(), func));
  1854. instr->GetDst()->SetIsJITOptimizedReg(true);
  1855. instr->SetByteCodeOffset(insertBeforeInstr);
  1856. insertBeforeInstr->InsertBefore(instr);
  1857. }
  1858. else
  1859. {
  1860. Assert(intermediateValueSym != loopCount->LeftSym());
  1861. }
  1862. // loopCountMinusOne = intermediateValue
  1863. loopCount->SetLoopCountMinusOneSym(intermediateValueSym);
  1864. }
  1865. void GlobOpt::GenerateLoopCountPlusOne(Loop *const loop, LoopCount *const loopCount)
  1866. {
  1867. Assert(loop);
  1868. Assert(loopCount);
  1869. Assert(loopCount == loop->loopCount);
  1870. if (loopCount->HasGeneratedLoopCountSym())
  1871. {
  1872. return;
  1873. }
  1874. if (!loopCount->HasBeenGenerated())
  1875. {
  1876. GenerateLoopCount(loop, loopCount);
  1877. }
  1878. Assert(loopCount->HasBeenGenerated());
  1879. // If this is null then the loop count is a constant and there is nothing more to do here
  1880. if (loopCount->LoopCountMinusOneSym())
  1881. {
  1882. // Prepare the landing pad for bailouts and instruction insertion
  1883. BailOutInfo *const bailOutInfo = loop->bailOutInfo;
  1884. Assert(bailOutInfo);
  1885. IR::Instr *const insertBeforeInstr = bailOutInfo->bailOutInstr;
  1886. Assert(insertBeforeInstr);
  1887. Func *const func = bailOutInfo->bailOutFunc;
  1888. IRType type = loopCount->LoopCountMinusOneSym()->GetType();
  1889. // loop count is off by one, so add one
  1890. IR::RegOpnd *loopCountOpnd = IR::RegOpnd::New(type, func);
  1891. IR::RegOpnd *minusOneOpnd = IR::RegOpnd::New(loopCount->LoopCountMinusOneSym(), type, func);
  1892. minusOneOpnd->SetIsJITOptimizedReg(true);
  1893. insertBeforeInstr->InsertBefore(IR::Instr::New(Js::OpCode::Add_I4,
  1894. loopCountOpnd,
  1895. minusOneOpnd,
  1896. IR::IntConstOpnd::New(1, type, func, true),
  1897. func));
  1898. loopCount->SetLoopCountSym(loopCountOpnd->GetStackSym());
  1899. }
  1900. }
  1901. void GlobOpt::GenerateSecondaryInductionVariableBound(
  1902. Loop *const loop,
  1903. StackSym *const inductionVariableSym,
  1904. const LoopCount *const loopCount,
  1905. const int maxMagnitudeChange,
  1906. StackSym *const boundSym)
  1907. {
  1908. Assert(loop);
  1909. Assert(inductionVariableSym);
  1910. Assert(inductionVariableSym->GetType() == TyInt32 || inductionVariableSym->GetType() == TyUint32);
  1911. Assert(loopCount);
  1912. Assert(loopCount == loop->loopCount);
  1913. Assert(loopCount->LoopCountMinusOneSym());
  1914. Assert(maxMagnitudeChange != 0);
  1915. Assert(maxMagnitudeChange >= -InductionVariable::ChangeMagnitudeLimitForLoopCountBasedHoisting);
  1916. Assert(maxMagnitudeChange <= InductionVariable::ChangeMagnitudeLimitForLoopCountBasedHoisting);
  1917. Assert(boundSym);
  1918. Assert(boundSym->IsInt32());
  1919. // bound = inductionVariable + loopCountMinusOne * maxMagnitudeChange
  1920. // Prepare the landing pad for bailouts and instruction insertion
  1921. BailOutInfo *const bailOutInfo = loop->bailOutInfo;
  1922. Assert(bailOutInfo);
  1923. const IR::BailOutKind bailOutKind = IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck;
  1924. IR::Instr *const insertBeforeInstr = bailOutInfo->bailOutInstr;
  1925. Assert(insertBeforeInstr);
  1926. Func *const func = bailOutInfo->bailOutFunc;
  1927. // intermediateValue = loopCount * maxMagnitudeChange
  1928. StackSym *intermediateValueSym;
  1929. if(maxMagnitudeChange == 1 || maxMagnitudeChange == -1)
  1930. {
  1931. intermediateValueSym = loopCount->LoopCountMinusOneSym();
  1932. }
  1933. else
  1934. {
  1935. IR::BailOutInstr *const instr = IR::BailOutInstr::New(Js::OpCode::Mul_I4, bailOutKind, bailOutInfo, func);
  1936. instr->SetSrc1(
  1937. IR::RegOpnd::New(loopCount->LoopCountMinusOneSym(), loopCount->LoopCountMinusOneSym()->GetType(), func));
  1938. instr->GetSrc1()->SetIsJITOptimizedReg(true);
  1939. instr->SetSrc2(IR::IntConstOpnd::New(maxMagnitudeChange, TyInt32, func, true));
  1940. intermediateValueSym = boundSym;
  1941. instr->SetDst(IR::RegOpnd::New(intermediateValueSym, intermediateValueSym->GetType(), func));
  1942. instr->GetDst()->SetIsJITOptimizedReg(true);
  1943. instr->SetByteCodeOffset(insertBeforeInstr);
  1944. insertBeforeInstr->InsertBefore(instr);
  1945. }
  1946. // bound = intermediateValue + inductionVariable
  1947. {
  1948. IR::BailOutInstr *const instr = IR::BailOutInstr::New(Js::OpCode::Add_I4, bailOutKind, bailOutInfo, func);
  1949. instr->SetSrc1(IR::RegOpnd::New(intermediateValueSym, intermediateValueSym->GetType(), func));
  1950. instr->GetSrc1()->SetIsJITOptimizedReg(true);
  1951. instr->SetSrc2(IR::RegOpnd::New(inductionVariableSym, inductionVariableSym->GetType(), func));
  1952. instr->GetSrc2()->SetIsJITOptimizedReg(true);
  1953. if(maxMagnitudeChange == -1)
  1954. {
  1955. // bound = inductionVariable - intermediateValue[loopCount]
  1956. instr->m_opcode = Js::OpCode::Sub_I4;
  1957. instr->SwapOpnds();
  1958. }
  1959. instr->SetDst(IR::RegOpnd::New(boundSym, boundSym->GetType(), func));
  1960. instr->GetDst()->SetIsJITOptimizedReg(true);
  1961. instr->SetByteCodeOffset(insertBeforeInstr);
  1962. insertBeforeInstr->InsertBefore(instr);
  1963. }
  1964. }
  1965. void GlobOpt::DetermineArrayBoundCheckHoistability(
  1966. bool needLowerBoundCheck,
  1967. bool needUpperBoundCheck,
  1968. ArrayLowerBoundCheckHoistInfo &lowerHoistInfo,
  1969. ArrayUpperBoundCheckHoistInfo &upperHoistInfo,
  1970. const bool isJsArray,
  1971. StackSym *const indexSym,
  1972. Value *const indexValue,
  1973. const IntConstantBounds &indexConstantBounds,
  1974. StackSym *const headSegmentLengthSym,
  1975. Value *const headSegmentLengthValue,
  1976. const IntConstantBounds &headSegmentLengthConstantBounds,
  1977. Loop *const headSegmentLengthInvariantLoop,
  1978. bool &failedToUpdateCompatibleLowerBoundCheck,
  1979. bool &failedToUpdateCompatibleUpperBoundCheck)
  1980. {
  1981. Assert(DoBoundCheckHoist());
  1982. Assert(needLowerBoundCheck || needUpperBoundCheck);
  1983. Assert(!lowerHoistInfo.HasAnyInfo());
  1984. Assert(!upperHoistInfo.HasAnyInfo());
  1985. Assert(!indexSym == !indexValue);
  1986. Assert(!needUpperBoundCheck || headSegmentLengthSym);
  1987. Assert(!headSegmentLengthSym == !headSegmentLengthValue);
  1988. Assert(!failedToUpdateCompatibleLowerBoundCheck);
  1989. Assert(!failedToUpdateCompatibleUpperBoundCheck);
  1990. Loop *const currentLoop = currentBlock->loop;
  1991. if(!indexValue)
  1992. {
  1993. Assert(!needLowerBoundCheck);
  1994. Assert(needUpperBoundCheck);
  1995. Assert(indexConstantBounds.IsConstant());
  1996. // The index is a constant value, so a bound check on it can be hoisted as far as desired. Just find a compatible bound
  1997. // check that is already available, or the loop in which the head segment length is invariant.
  1998. TRACE_PHASE_VERBOSE(
  1999. Js::Phase::BoundCheckHoistPhase,
  2000. 2,
  2001. L"Index is constant, looking for a compatible upper bound check\n");
  2002. const int indexConstantValue = indexConstantBounds.LowerBound();
  2003. Assert(indexConstantValue != IntConstMax);
  2004. const IntBoundCheck *compatibleBoundCheck;
  2005. if(blockData.availableIntBoundChecks->TryGetReference(
  2006. IntBoundCheckCompatibilityId(ZeroValueNumber, headSegmentLengthValue->GetValueNumber()),
  2007. &compatibleBoundCheck))
  2008. {
  2009. // We need:
  2010. // index < headSegmentLength
  2011. // Normalize the offset such that:
  2012. // 0 <= headSegmentLength + compatibleBoundCheckOffset
  2013. // Where (compatibleBoundCheckOffset = -1 - index), and -1 is to simulate < instead of <=.
  2014. const int compatibleBoundCheckOffset = -1 - indexConstantValue;
  2015. if(compatibleBoundCheck->SetBoundOffset(compatibleBoundCheckOffset))
  2016. {
  2017. TRACE_PHASE_VERBOSE(
  2018. Js::Phase::BoundCheckHoistPhase,
  2019. 3,
  2020. L"Found in block %u\n",
  2021. compatibleBoundCheck->Block()->GetBlockNum());
  2022. upperHoistInfo.SetCompatibleBoundCheck(compatibleBoundCheck->Block(), indexConstantValue);
  2023. return;
  2024. }
  2025. failedToUpdateCompatibleUpperBoundCheck = true;
  2026. }
  2027. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, L"Not found\n");
  2028. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 2, L"Looking for invariant head segment length\n");
  2029. Loop *invariantLoop;
  2030. Value *landingPadHeadSegmentLengthValue = nullptr;
  2031. if(headSegmentLengthInvariantLoop)
  2032. {
  2033. invariantLoop = headSegmentLengthInvariantLoop;
  2034. landingPadHeadSegmentLengthValue =
  2035. FindValue(invariantLoop->landingPad->globOptData.symToValueMap, headSegmentLengthSym);
  2036. }
  2037. else if(currentLoop)
  2038. {
  2039. invariantLoop = nullptr;
  2040. for(Loop *loop = currentLoop; loop; loop = loop->parent)
  2041. {
  2042. GlobOptBlockData &landingPadBlockData = loop->landingPad->globOptData;
  2043. GlobHashTable *const landingPadSymToValueMap = landingPadBlockData.symToValueMap;
  2044. Value *const value = FindValue(landingPadSymToValueMap, headSegmentLengthSym);
  2045. if(!value)
  2046. {
  2047. break;
  2048. }
  2049. invariantLoop = loop;
  2050. landingPadHeadSegmentLengthValue = value;
  2051. }
  2052. if(!invariantLoop)
  2053. {
  2054. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, L"Not found\n");
  2055. return;
  2056. }
  2057. }
  2058. else
  2059. {
  2060. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, L"Not found, block is not in a loop\n");
  2061. return;
  2062. }
  2063. TRACE_PHASE_VERBOSE(
  2064. Js::Phase::BoundCheckHoistPhase,
  2065. 3,
  2066. L"Found in loop %u landing pad block %u\n",
  2067. invariantLoop->GetLoopNumber(),
  2068. invariantLoop->landingPad->GetBlockNum());
  2069. IntConstantBounds landingPadHeadSegmentLengthConstantBounds;
  2070. AssertVerify(
  2071. landingPadHeadSegmentLengthValue
  2072. ->GetValueInfo()
  2073. ->TryGetIntConstantBounds(&landingPadHeadSegmentLengthConstantBounds));
  2074. if(isJsArray)
  2075. {
  2076. // index >= headSegmentLength is currently not possible for JS arrays (except when index == int32 max, which is
  2077. // covered above).
  2078. Assert(
  2079. !ValueInfo::IsGreaterThanOrEqualTo(
  2080. nullptr,
  2081. indexConstantValue,
  2082. indexConstantValue,
  2083. landingPadHeadSegmentLengthValue,
  2084. landingPadHeadSegmentLengthConstantBounds.LowerBound(),
  2085. landingPadHeadSegmentLengthConstantBounds.UpperBound()));
  2086. }
  2087. else if(
  2088. ValueInfo::IsGreaterThanOrEqualTo(
  2089. nullptr,
  2090. indexConstantValue,
  2091. indexConstantValue,
  2092. landingPadHeadSegmentLengthValue,
  2093. landingPadHeadSegmentLengthConstantBounds.LowerBound(),
  2094. landingPadHeadSegmentLengthConstantBounds.UpperBound()))
  2095. {
  2096. // index >= headSegmentLength in the landing pad, can't use the index sym. This is possible for typed arrays through
  2097. // conditions on array.length in user code.
  2098. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 2, L"Index >= head segment length\n");
  2099. return;
  2100. }
  2101. upperHoistInfo.SetLoop(
  2102. invariantLoop,
  2103. indexConstantValue,
  2104. landingPadHeadSegmentLengthValue,
  2105. landingPadHeadSegmentLengthConstantBounds);
  2106. return;
  2107. }
  2108. Assert(!indexConstantBounds.IsConstant());
  2109. ValueInfo *const indexValueInfo = indexValue->GetValueInfo();
  2110. const IntBounds *const indexBounds = indexValueInfo->IsIntBounded() ? indexValueInfo->AsIntBounded()->Bounds() : nullptr;
  2111. {
  2112. // See if a compatible bound check is already available
  2113. TRACE_PHASE_VERBOSE(
  2114. Js::Phase::BoundCheckHoistPhase,
  2115. 2,
  2116. L"Looking for compatible bound checks for index bounds\n");
  2117. bool searchingLower = needLowerBoundCheck;
  2118. bool searchingUpper = needUpperBoundCheck;
  2119. Assert(searchingLower || searchingUpper);
  2120. bool foundLowerBoundCheck = false;
  2121. const IntBoundCheck *lowerBoundCheck = nullptr;
  2122. ValueNumber lowerHoistBlockIndexValueNumber = InvalidValueNumber;
  2123. int lowerBoundOffset = 0;
  2124. if(searchingLower &&
  2125. blockData.availableIntBoundChecks->TryGetReference(
  2126. IntBoundCheckCompatibilityId(ZeroValueNumber, indexValue->GetValueNumber()),
  2127. &lowerBoundCheck))
  2128. {
  2129. if(lowerBoundCheck->SetBoundOffset(0))
  2130. {
  2131. foundLowerBoundCheck = true;
  2132. lowerHoistBlockIndexValueNumber = indexValue->GetValueNumber();
  2133. lowerBoundOffset = 0;
  2134. searchingLower = false;
  2135. }
  2136. else
  2137. {
  2138. failedToUpdateCompatibleLowerBoundCheck = true;
  2139. }
  2140. }
  2141. bool foundUpperBoundCheck = false;
  2142. const IntBoundCheck *upperBoundCheck = nullptr;
  2143. ValueNumber upperHoistBlockIndexValueNumber = InvalidValueNumber;
  2144. int upperBoundOffset = 0;
  2145. if(searchingUpper &&
  2146. blockData.availableIntBoundChecks->TryGetReference(
  2147. IntBoundCheckCompatibilityId(indexValue->GetValueNumber(), headSegmentLengthValue->GetValueNumber()),
  2148. &upperBoundCheck))
  2149. {
  2150. if(upperBoundCheck->SetBoundOffset(-1)) // -1 is to simulate < instead of <=
  2151. {
  2152. foundUpperBoundCheck = true;
  2153. upperHoistBlockIndexValueNumber = indexValue->GetValueNumber();
  2154. upperBoundOffset = 0;
  2155. searchingUpper = false;
  2156. }
  2157. else
  2158. {
  2159. failedToUpdateCompatibleUpperBoundCheck = true;
  2160. }
  2161. }
  2162. if(indexBounds)
  2163. {
  2164. searchingLower = searchingLower && indexBounds->RelativeLowerBounds().Count() != 0;
  2165. searchingUpper = searchingUpper && indexBounds->RelativeUpperBounds().Count() != 0;
  2166. if(searchingLower || searchingUpper)
  2167. {
  2168. for(auto it = blockData.availableIntBoundChecks->GetIterator(); it.IsValid(); it.MoveNext())
  2169. {
  2170. const IntBoundCheck &boundCheck = it.CurrentValue();
  2171. if(searchingLower && boundCheck.LeftValueNumber() == ZeroValueNumber)
  2172. {
  2173. lowerHoistBlockIndexValueNumber = boundCheck.RightValueNumber();
  2174. const ValueRelativeOffset *bound;
  2175. if(indexBounds->RelativeLowerBounds().TryGetReference(lowerHoistBlockIndexValueNumber, &bound))
  2176. {
  2177. // We need:
  2178. // 0 <= boundBase + boundOffset
  2179. const int offset = bound->Offset();
  2180. if(boundCheck.SetBoundOffset(offset))
  2181. {
  2182. foundLowerBoundCheck = true;
  2183. lowerBoundCheck = &boundCheck;
  2184. lowerBoundOffset = offset;
  2185. searchingLower = false;
  2186. if(!searchingUpper)
  2187. {
  2188. break;
  2189. }
  2190. }
  2191. else
  2192. {
  2193. failedToUpdateCompatibleLowerBoundCheck = true;
  2194. }
  2195. }
  2196. }
  2197. if(searchingUpper && boundCheck.RightValueNumber() == headSegmentLengthValue->GetValueNumber())
  2198. {
  2199. upperHoistBlockIndexValueNumber = boundCheck.LeftValueNumber();
  2200. const ValueRelativeOffset *bound;
  2201. if(indexBounds->RelativeUpperBounds().TryGetReference(upperHoistBlockIndexValueNumber, &bound))
  2202. {
  2203. // We need:
  2204. // boundBase + boundOffset < headSegmentLength
  2205. // Normalize the offset such that:
  2206. // boundBase <= headSegmentLength + compatibleBoundCheckOffset
  2207. // Where (compatibleBoundCheckOffset = -1 - boundOffset), and -1 is to simulate < instead of <=.
  2208. const int offset = -1 - bound->Offset();
  2209. if(boundCheck.SetBoundOffset(offset))
  2210. {
  2211. foundUpperBoundCheck = true;
  2212. upperBoundCheck = &boundCheck;
  2213. upperBoundOffset = bound->Offset();
  2214. searchingUpper = false;
  2215. if(!searchingLower)
  2216. {
  2217. break;
  2218. }
  2219. }
  2220. else
  2221. {
  2222. failedToUpdateCompatibleUpperBoundCheck = true;
  2223. }
  2224. }
  2225. }
  2226. }
  2227. }
  2228. }
  2229. if(foundLowerBoundCheck)
  2230. {
  2231. // A bound check takes the form src1 <= src2 + dst
  2232. Assert(lowerBoundCheck->Instr()->GetSrc2());
  2233. Assert(
  2234. lowerBoundCheck->Instr()->GetSrc2()->AsRegOpnd()->m_sym->GetType() == TyInt32 ||
  2235. lowerBoundCheck->Instr()->GetSrc2()->AsRegOpnd()->m_sym->GetType() == TyUint32);
  2236. StackSym *boundCheckIndexSym = lowerBoundCheck->Instr()->GetSrc2()->AsRegOpnd()->m_sym;
  2237. if(boundCheckIndexSym->IsTypeSpec())
  2238. {
  2239. boundCheckIndexSym = boundCheckIndexSym->GetVarEquivSym(nullptr);
  2240. Assert(boundCheckIndexSym);
  2241. }
  2242. TRACE_PHASE_VERBOSE(
  2243. Js::Phase::BoundCheckHoistPhase,
  2244. 3,
  2245. L"Found lower bound (s%u + %d) in block %u\n",
  2246. boundCheckIndexSym->m_id,
  2247. lowerBoundOffset,
  2248. lowerBoundCheck->Block()->GetBlockNum());
  2249. lowerHoistInfo.SetCompatibleBoundCheck(
  2250. lowerBoundCheck->Block(),
  2251. boundCheckIndexSym,
  2252. lowerBoundOffset,
  2253. lowerHoistBlockIndexValueNumber);
  2254. Assert(!searchingLower);
  2255. needLowerBoundCheck = false;
  2256. if(!needUpperBoundCheck)
  2257. {
  2258. return;
  2259. }
  2260. }
  2261. if(foundUpperBoundCheck)
  2262. {
  2263. // A bound check takes the form src1 <= src2 + dst
  2264. Assert(upperBoundCheck->Instr()->GetSrc1());
  2265. Assert(
  2266. upperBoundCheck->Instr()->GetSrc1()->AsRegOpnd()->m_sym->GetType() == TyInt32 ||
  2267. upperBoundCheck->Instr()->GetSrc1()->AsRegOpnd()->m_sym->GetType() == TyUint32);
  2268. StackSym *boundCheckIndexSym = upperBoundCheck->Instr()->GetSrc1()->AsRegOpnd()->m_sym;
  2269. if(boundCheckIndexSym->IsTypeSpec())
  2270. {
  2271. boundCheckIndexSym = boundCheckIndexSym->GetVarEquivSym(nullptr);
  2272. Assert(boundCheckIndexSym);
  2273. }
  2274. TRACE_PHASE_VERBOSE(
  2275. Js::Phase::BoundCheckHoistPhase,
  2276. 3,
  2277. L"Found upper bound (s%u + %d) in block %u\n",
  2278. boundCheckIndexSym->m_id,
  2279. upperBoundOffset,
  2280. upperBoundCheck->Block()->GetBlockNum());
  2281. upperHoistInfo.SetCompatibleBoundCheck(
  2282. upperBoundCheck->Block(),
  2283. boundCheckIndexSym,
  2284. -1 - upperBoundOffset,
  2285. upperHoistBlockIndexValueNumber);
  2286. Assert(!searchingUpper);
  2287. needUpperBoundCheck = false;
  2288. if(!needLowerBoundCheck)
  2289. {
  2290. return;
  2291. }
  2292. }
  2293. Assert(needLowerBoundCheck || needUpperBoundCheck);
  2294. Assert(!needLowerBoundCheck || !lowerHoistInfo.CompatibleBoundCheckBlock());
  2295. Assert(!needUpperBoundCheck || !upperHoistInfo.CompatibleBoundCheckBlock());
  2296. }
  2297. if(!currentLoop)
  2298. {
  2299. return;
  2300. }
  2301. // 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
  2302. // index value in the current block
  2303. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 2, L"Looking for invariant index or index bounded by itself\n");
  2304. bool searchingLower = needLowerBoundCheck, searchingUpper = needUpperBoundCheck;
  2305. for(Loop *loop = currentLoop; loop; loop = loop->parent)
  2306. {
  2307. GlobOptBlockData &landingPadBlockData = loop->landingPad->globOptData;
  2308. GlobHashTable *const landingPadSymToValueMap = landingPadBlockData.symToValueMap;
  2309. TRACE_PHASE_VERBOSE(
  2310. Js::Phase::BoundCheckHoistPhase,
  2311. 3,
  2312. L"Trying loop %u landing pad block %u\n",
  2313. loop->GetLoopNumber(),
  2314. loop->landingPad->GetBlockNum());
  2315. Value *const landingPadIndexValue = FindValue(landingPadSymToValueMap, indexSym);
  2316. if(!landingPadIndexValue)
  2317. {
  2318. break;
  2319. }
  2320. IntConstantBounds landingPadIndexConstantBounds;
  2321. const bool landingPadIndexValueIsLikelyInt =
  2322. landingPadIndexValue->GetValueInfo()->TryGetIntConstantBounds(&landingPadIndexConstantBounds, true);
  2323. int lowerOffset = 0, upperOffset = 0;
  2324. if(indexValue->GetValueNumber() == landingPadIndexValue->GetValueNumber())
  2325. {
  2326. Assert(landingPadIndexValueIsLikelyInt);
  2327. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, L"Index is invariant\n");
  2328. }
  2329. else
  2330. {
  2331. if(!landingPadIndexValueIsLikelyInt)
  2332. {
  2333. break;
  2334. }
  2335. if(searchingLower)
  2336. {
  2337. if(lowerHoistInfo.Loop() && indexValue->GetValueNumber() == lowerHoistInfo.IndexValueNumber())
  2338. {
  2339. // Prefer using the invariant sym
  2340. needLowerBoundCheck = searchingLower = false;
  2341. if(!needUpperBoundCheck)
  2342. {
  2343. return;
  2344. }
  2345. if(!searchingUpper)
  2346. {
  2347. break;
  2348. }
  2349. }
  2350. else
  2351. {
  2352. bool foundBound = false;
  2353. if(indexBounds)
  2354. {
  2355. const ValueRelativeOffset *bound;
  2356. if(indexBounds->RelativeLowerBounds().TryGetReference(landingPadIndexValue->GetValueNumber(), &bound))
  2357. {
  2358. foundBound = true;
  2359. lowerOffset = bound->Offset();
  2360. TRACE_PHASE_VERBOSE(
  2361. Js::Phase::BoundCheckHoistPhase,
  2362. 4,
  2363. L"Found lower bound (index + %d)\n",
  2364. lowerOffset);
  2365. }
  2366. }
  2367. if(!foundBound)
  2368. {
  2369. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, L"Lower bound was not found\n");
  2370. searchingLower = false;
  2371. if(!searchingUpper)
  2372. {
  2373. break;
  2374. }
  2375. }
  2376. }
  2377. }
  2378. if(searchingUpper)
  2379. {
  2380. if(upperHoistInfo.Loop() && indexValue->GetValueNumber() == upperHoistInfo.IndexValueNumber())
  2381. {
  2382. // Prefer using the invariant sym
  2383. needUpperBoundCheck = searchingUpper = false;
  2384. if(!needLowerBoundCheck)
  2385. {
  2386. return;
  2387. }
  2388. if(!searchingLower)
  2389. {
  2390. break;
  2391. }
  2392. }
  2393. else
  2394. {
  2395. bool foundBound = false;
  2396. if(indexBounds)
  2397. {
  2398. const ValueRelativeOffset *bound;
  2399. if(indexBounds->RelativeUpperBounds().TryGetReference(landingPadIndexValue->GetValueNumber(), &bound))
  2400. {
  2401. foundBound = true;
  2402. upperOffset = bound->Offset();
  2403. TRACE_PHASE_VERBOSE(
  2404. Js::Phase::BoundCheckHoistPhase,
  2405. 4,
  2406. L"Found upper bound (index + %d)\n",
  2407. upperOffset);
  2408. }
  2409. }
  2410. if(!foundBound)
  2411. {
  2412. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, L"Upper bound was not found\n");
  2413. searchingUpper = false;
  2414. if(!searchingLower)
  2415. {
  2416. break;
  2417. }
  2418. }
  2419. }
  2420. }
  2421. }
  2422. if(searchingLower)
  2423. {
  2424. if(ValueInfo::IsLessThan(
  2425. landingPadIndexValue,
  2426. landingPadIndexConstantBounds.LowerBound(),
  2427. landingPadIndexConstantBounds.UpperBound(),
  2428. nullptr,
  2429. 0,
  2430. 0))
  2431. {
  2432. // index < 0 in the landing pad; can't use the index sym
  2433. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, L"Index < 0\n");
  2434. searchingLower = false;
  2435. if(!searchingUpper)
  2436. {
  2437. break;
  2438. }
  2439. }
  2440. else
  2441. {
  2442. lowerHoistInfo.SetLoop(
  2443. loop,
  2444. indexSym,
  2445. lowerOffset,
  2446. landingPadIndexValue,
  2447. landingPadIndexConstantBounds);
  2448. }
  2449. }
  2450. if(!searchingUpper)
  2451. {
  2452. continue;
  2453. }
  2454. // Check if the head segment length sym is available in the landing pad
  2455. Value *const landingPadHeadSegmentLengthValue = FindValue(landingPadSymToValueMap, headSegmentLengthSym);
  2456. if(!landingPadHeadSegmentLengthValue)
  2457. {
  2458. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, L"Head segment length is not invariant\n");
  2459. searchingUpper = false;
  2460. if(!searchingLower)
  2461. {
  2462. break;
  2463. }
  2464. continue;
  2465. }
  2466. IntConstantBounds landingPadHeadSegmentLengthConstantBounds;
  2467. AssertVerify(
  2468. landingPadHeadSegmentLengthValue
  2469. ->GetValueInfo()
  2470. ->TryGetIntConstantBounds(&landingPadHeadSegmentLengthConstantBounds));
  2471. if(ValueInfo::IsGreaterThanOrEqualTo(
  2472. landingPadIndexValue,
  2473. landingPadIndexConstantBounds.LowerBound(),
  2474. landingPadIndexConstantBounds.UpperBound(),
  2475. landingPadHeadSegmentLengthValue,
  2476. landingPadHeadSegmentLengthConstantBounds.LowerBound(),
  2477. landingPadHeadSegmentLengthConstantBounds.UpperBound()))
  2478. {
  2479. // index >= headSegmentLength in the landing pad; can't use the index sym
  2480. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, L"Index >= head segment length\n");
  2481. searchingUpper = false;
  2482. if(!searchingLower)
  2483. {
  2484. break;
  2485. }
  2486. continue;
  2487. }
  2488. // We need:
  2489. // boundBase + boundOffset < headSegmentLength
  2490. // Normalize the offset such that:
  2491. // boundBase <= headSegmentLength + offset
  2492. // Where (offset = -1 - boundOffset), and -1 is to simulate < instead of <=.
  2493. upperOffset = -1 - upperOffset;
  2494. upperHoistInfo.SetLoop(
  2495. loop,
  2496. indexSym,
  2497. upperOffset,
  2498. landingPadIndexValue,
  2499. landingPadIndexConstantBounds,
  2500. landingPadHeadSegmentLengthValue,
  2501. landingPadHeadSegmentLengthConstantBounds);
  2502. }
  2503. if(needLowerBoundCheck && lowerHoistInfo.Loop())
  2504. {
  2505. needLowerBoundCheck = false;
  2506. if(!needUpperBoundCheck)
  2507. {
  2508. return;
  2509. }
  2510. }
  2511. if(needUpperBoundCheck && upperHoistInfo.Loop())
  2512. {
  2513. needUpperBoundCheck = false;
  2514. if(!needLowerBoundCheck)
  2515. {
  2516. return;
  2517. }
  2518. }
  2519. // Find an invariant lower/upper bound of the index that can be used for hoisting the bound checks
  2520. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 2, L"Looking for invariant index bounds\n");
  2521. searchingLower = needLowerBoundCheck;
  2522. searchingUpper = needUpperBoundCheck;
  2523. for(Loop *loop = currentLoop; loop; loop = loop->parent)
  2524. {
  2525. GlobOptBlockData &landingPadBlockData = loop->landingPad->globOptData;
  2526. GlobHashTable *const landingPadSymToValueMap = landingPadBlockData.symToValueMap;
  2527. TRACE_PHASE_VERBOSE(
  2528. Js::Phase::BoundCheckHoistPhase,
  2529. 3,
  2530. L"Trying loop %u landing pad block %u\n",
  2531. loop->GetLoopNumber(),
  2532. loop->landingPad->GetBlockNum());
  2533. Value *landingPadHeadSegmentLengthValue = nullptr;
  2534. IntConstantBounds landingPadHeadSegmentLengthConstantBounds;
  2535. if(searchingUpper)
  2536. {
  2537. // Check if the head segment length sym is available in the landing pad
  2538. landingPadHeadSegmentLengthValue = FindValue(landingPadSymToValueMap, headSegmentLengthSym);
  2539. if(landingPadHeadSegmentLengthValue)
  2540. {
  2541. AssertVerify(
  2542. landingPadHeadSegmentLengthValue
  2543. ->GetValueInfo()
  2544. ->TryGetIntConstantBounds(&landingPadHeadSegmentLengthConstantBounds));
  2545. }
  2546. else
  2547. {
  2548. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, L"Head segment length is not invariant\n");
  2549. searchingUpper = false;
  2550. if(!searchingLower)
  2551. {
  2552. break;
  2553. }
  2554. }
  2555. }
  2556. // Look for a relative bound
  2557. if(indexBounds)
  2558. {
  2559. for(int i = 0; i < 2; ++i)
  2560. {
  2561. const bool searchingRelativeLowerBounds = i == 0;
  2562. if(!(searchingRelativeLowerBounds ? searchingLower : searchingUpper))
  2563. {
  2564. continue;
  2565. }
  2566. for(auto it =
  2567. (
  2568. searchingRelativeLowerBounds
  2569. ? indexBounds->RelativeLowerBounds()
  2570. : indexBounds->RelativeUpperBounds()
  2571. ).GetIterator();
  2572. it.IsValid();
  2573. it.MoveNext())
  2574. {
  2575. const ValueRelativeOffset &indexBound = it.CurrentValue();
  2576. StackSym *const indexBoundBaseSym = indexBound.BaseSym();
  2577. if(!indexBoundBaseSym)
  2578. {
  2579. continue;
  2580. }
  2581. TRACE_PHASE_VERBOSE(
  2582. Js::Phase::BoundCheckHoistPhase,
  2583. 4,
  2584. L"Found %S bound (s%u + %d)\n",
  2585. searchingRelativeLowerBounds ? "lower" : "upper",
  2586. indexBoundBaseSym->m_id,
  2587. indexBound.Offset());
  2588. if(!indexBound.WasEstablishedExplicitly())
  2589. {
  2590. // Don't use a bound that was not established explicitly, as it may be too aggressive. For instance, an
  2591. // index sym used in an array will obtain an upper bound of the array's head segment length - 1. That
  2592. // bound is not established explicitly because the bound assertion is not enforced by the source code.
  2593. // Rather, it is assumed and enforced by the JIT using bailout check. Incrementing the index and using
  2594. // it in a different array may otherwise cause it to use the first array's head segment length as the
  2595. // upper bound on which to do the bound check against the second array, and that bound check would
  2596. // always fail when the arrays are the same size.
  2597. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, L"Bound was established implicitly\n");
  2598. continue;
  2599. }
  2600. Value *const landingPadIndexBoundBaseValue = FindValue(landingPadSymToValueMap, indexBoundBaseSym);
  2601. if(!landingPadIndexBoundBaseValue ||
  2602. landingPadIndexBoundBaseValue->GetValueNumber() != indexBound.BaseValueNumber())
  2603. {
  2604. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, L"Bound is not invariant\n");
  2605. continue;
  2606. }
  2607. IntConstantBounds landingPadIndexBoundBaseConstantBounds;
  2608. AssertVerify(
  2609. landingPadIndexBoundBaseValue
  2610. ->GetValueInfo()
  2611. ->TryGetIntConstantBounds(&landingPadIndexBoundBaseConstantBounds, true));
  2612. int offset = indexBound.Offset();
  2613. if(searchingRelativeLowerBounds)
  2614. {
  2615. if(offset == IntConstMin ||
  2616. ValueInfo::IsLessThan(
  2617. landingPadIndexBoundBaseValue,
  2618. landingPadIndexBoundBaseConstantBounds.LowerBound(),
  2619. landingPadIndexBoundBaseConstantBounds.UpperBound(),
  2620. nullptr,
  2621. -offset,
  2622. -offset))
  2623. {
  2624. // indexBoundBase + indexBoundOffset < 0; can't use this bound
  2625. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, L"Bound < 0\n");
  2626. continue;
  2627. }
  2628. lowerHoistInfo.SetLoop(
  2629. loop,
  2630. indexBoundBaseSym,
  2631. offset,
  2632. landingPadIndexBoundBaseValue,
  2633. landingPadIndexBoundBaseConstantBounds);
  2634. break;
  2635. }
  2636. if(ValueInfo::IsLessThanOrEqualTo(
  2637. landingPadHeadSegmentLengthValue,
  2638. landingPadHeadSegmentLengthConstantBounds.LowerBound(),
  2639. landingPadHeadSegmentLengthConstantBounds.UpperBound(),
  2640. landingPadIndexBoundBaseValue,
  2641. landingPadIndexBoundBaseConstantBounds.LowerBound(),
  2642. landingPadIndexBoundBaseConstantBounds.UpperBound(),
  2643. offset))
  2644. {
  2645. // indexBoundBase + indexBoundOffset >= headSegmentLength; can't use this bound
  2646. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, L"Bound >= head segment length\n");
  2647. continue;
  2648. }
  2649. // We need:
  2650. // boundBase + boundOffset < headSegmentLength
  2651. // Normalize the offset such that:
  2652. // boundBase <= headSegmentLength + offset
  2653. // Where (offset = -1 - boundOffset), and -1 is to simulate < instead of <=.
  2654. offset = -1 - offset;
  2655. upperHoistInfo.SetLoop(
  2656. loop,
  2657. indexBoundBaseSym,
  2658. offset,
  2659. landingPadIndexBoundBaseValue,
  2660. landingPadIndexBoundBaseConstantBounds,
  2661. landingPadHeadSegmentLengthValue,
  2662. landingPadHeadSegmentLengthConstantBounds);
  2663. break;
  2664. }
  2665. }
  2666. }
  2667. if(searchingLower && lowerHoistInfo.Loop() != loop)
  2668. {
  2669. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, L"Lower bound was not found\n");
  2670. searchingLower = false;
  2671. if(!searchingUpper)
  2672. {
  2673. break;
  2674. }
  2675. }
  2676. if(searchingUpper && upperHoistInfo.Loop() != loop)
  2677. {
  2678. // No useful relative bound found; look for a constant bound if the index is an induction variable. Exclude constant
  2679. // bounds of non-induction variables because those bounds may have been established through means other than a loop
  2680. // exit condition, such as math or bitwise operations. Exclude constant bounds established implicitly by <,
  2681. // <=, >, and >=. For example, for a loop condition (i < n - 1), if 'n' is not invariant and hence can't be used,
  2682. // 'i' will still have a constant upper bound of (int32 max - 2) that should be excluded.
  2683. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, L"Relative upper bound was not found\n");
  2684. const InductionVariable *indexInductionVariable;
  2685. if(!upperHoistInfo.Loop() &&
  2686. currentLoop->inductionVariables &&
  2687. currentLoop->inductionVariables->TryGetReference(indexSym->m_id, &indexInductionVariable) &&
  2688. indexInductionVariable->IsChangeDeterminate())
  2689. {
  2690. if(!(indexBounds && indexBounds->WasConstantUpperBoundEstablishedExplicitly()))
  2691. {
  2692. TRACE_PHASE_VERBOSE(
  2693. Js::Phase::BoundCheckHoistPhase,
  2694. 4,
  2695. L"Constant upper bound was established implicitly\n");
  2696. }
  2697. else
  2698. {
  2699. // See if a compatible bound check is already available
  2700. const int indexConstantBound = indexBounds->ConstantUpperBound();
  2701. TRACE_PHASE_VERBOSE(
  2702. Js::Phase::BoundCheckHoistPhase,
  2703. 4,
  2704. L"Found constant upper bound %d, looking for a compatible bound check\n",
  2705. indexConstantBound);
  2706. const IntBoundCheck *boundCheck;
  2707. if(blockData.availableIntBoundChecks->TryGetReference(
  2708. IntBoundCheckCompatibilityId(ZeroValueNumber, headSegmentLengthValue->GetValueNumber()),
  2709. &boundCheck))
  2710. {
  2711. // We need:
  2712. // indexConstantBound < headSegmentLength
  2713. // Normalize the offset such that:
  2714. // 0 <= headSegmentLength + compatibleBoundCheckOffset
  2715. // Where (compatibleBoundCheckOffset = -1 - indexConstantBound), and -1 is to simulate < instead of <=.
  2716. const int compatibleBoundCheckOffset = -1 - indexConstantBound;
  2717. if(boundCheck->SetBoundOffset(compatibleBoundCheckOffset))
  2718. {
  2719. TRACE_PHASE_VERBOSE(
  2720. Js::Phase::BoundCheckHoistPhase,
  2721. 5,
  2722. L"Found in block %u\n",
  2723. boundCheck->Block()->GetBlockNum());
  2724. upperHoistInfo.SetCompatibleBoundCheck(boundCheck->Block(), indexConstantBound);
  2725. needUpperBoundCheck = searchingUpper = false;
  2726. if(!needLowerBoundCheck)
  2727. {
  2728. return;
  2729. }
  2730. if(!searchingLower)
  2731. {
  2732. break;
  2733. }
  2734. }
  2735. else
  2736. {
  2737. failedToUpdateCompatibleUpperBoundCheck = true;
  2738. }
  2739. }
  2740. if(searchingUpper)
  2741. {
  2742. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, L"Not found\n");
  2743. upperHoistInfo.SetLoop(
  2744. loop,
  2745. indexConstantBound,
  2746. landingPadHeadSegmentLengthValue,
  2747. landingPadHeadSegmentLengthConstantBounds);
  2748. }
  2749. }
  2750. }
  2751. else if(!upperHoistInfo.Loop())
  2752. {
  2753. TRACE_PHASE_VERBOSE(
  2754. Js::Phase::BoundCheckHoistPhase,
  2755. 4,
  2756. L"Index is not an induction variable, not using constant upper bound\n");
  2757. }
  2758. if(searchingUpper && upperHoistInfo.Loop() != loop)
  2759. {
  2760. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, L"Upper bound was not found\n");
  2761. searchingUpper = false;
  2762. if(!searchingLower)
  2763. {
  2764. break;
  2765. }
  2766. }
  2767. }
  2768. }
  2769. if(needLowerBoundCheck && lowerHoistInfo.Loop())
  2770. {
  2771. needLowerBoundCheck = false;
  2772. if(!needUpperBoundCheck)
  2773. {
  2774. return;
  2775. }
  2776. }
  2777. if(needUpperBoundCheck && upperHoistInfo.Loop())
  2778. {
  2779. needUpperBoundCheck = false;
  2780. if(!needLowerBoundCheck)
  2781. {
  2782. return;
  2783. }
  2784. }
  2785. // Try to use the loop count to calculate a missing lower/upper bound that in turn can be used for hoisting a bound check
  2786. TRACE_PHASE_VERBOSE(
  2787. Js::Phase::BoundCheckHoistPhase,
  2788. 2,
  2789. L"Looking for loop count based bound for loop %u landing pad block %u\n",
  2790. currentLoop->GetLoopNumber(),
  2791. currentLoop->landingPad->GetBlockNum());
  2792. LoopCount *const loopCount = currentLoop->loopCount;
  2793. if(!loopCount)
  2794. {
  2795. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, L"Loop was not counted\n");
  2796. return;
  2797. }
  2798. const InductionVariable *indexInductionVariable;
  2799. if(!currentLoop->inductionVariables ||
  2800. !currentLoop->inductionVariables->TryGetReference(indexSym->m_id, &indexInductionVariable) ||
  2801. !indexInductionVariable->IsChangeDeterminate())
  2802. {
  2803. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, L"Index is not an induction variable\n");
  2804. return;
  2805. }
  2806. // Determine the maximum-magnitude change per iteration, and verify that the change is reasonably finite
  2807. Assert(indexInductionVariable->IsChangeUnidirectional());
  2808. GlobOptBlockData &landingPadBlockData = currentLoop->landingPad->globOptData;
  2809. GlobHashTable *const landingPadSymToValueMap = currentLoop->landingPad->globOptData.symToValueMap;
  2810. int maxMagnitudeChange = indexInductionVariable->ChangeBounds().UpperBound();
  2811. Value *landingPadHeadSegmentLengthValue;
  2812. IntConstantBounds landingPadHeadSegmentLengthConstantBounds;
  2813. if(maxMagnitudeChange > 0)
  2814. {
  2815. TRACE_PHASE_VERBOSE(
  2816. Js::Phase::BoundCheckHoistPhase,
  2817. 3,
  2818. L"Index's maximum-magnitude change per iteration is %d\n",
  2819. maxMagnitudeChange);
  2820. if(!needUpperBoundCheck || maxMagnitudeChange > InductionVariable::ChangeMagnitudeLimitForLoopCountBasedHoisting)
  2821. {
  2822. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, L"Change magnitude is too large\n");
  2823. return;
  2824. }
  2825. // Check whether the head segment length is available in the landing pad
  2826. landingPadHeadSegmentLengthValue = FindValue(landingPadSymToValueMap, headSegmentLengthSym);
  2827. Assert(!headSegmentLengthInvariantLoop || landingPadHeadSegmentLengthValue);
  2828. if(!landingPadHeadSegmentLengthValue)
  2829. {
  2830. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, L"Head segment length is not invariant\n");
  2831. return;
  2832. }
  2833. AssertVerify(
  2834. landingPadHeadSegmentLengthValue
  2835. ->GetValueInfo()
  2836. ->TryGetIntConstantBounds(&landingPadHeadSegmentLengthConstantBounds));
  2837. }
  2838. else
  2839. {
  2840. maxMagnitudeChange = indexInductionVariable->ChangeBounds().LowerBound();
  2841. Assert(maxMagnitudeChange < 0);
  2842. TRACE_PHASE_VERBOSE(
  2843. Js::Phase::BoundCheckHoistPhase,
  2844. 3,
  2845. L"Index's maximum-magnitude change per iteration is %d\n",
  2846. maxMagnitudeChange);
  2847. if(!needLowerBoundCheck || maxMagnitudeChange < -InductionVariable::ChangeMagnitudeLimitForLoopCountBasedHoisting)
  2848. {
  2849. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, L"Change magnitude is too large\n");
  2850. return;
  2851. }
  2852. landingPadHeadSegmentLengthValue = nullptr;
  2853. }
  2854. // Determine if the index already changed in the loop, and by how much
  2855. int indexOffset;
  2856. StackSym *indexSymToAdd;
  2857. if(DetermineSymBoundOffsetOrValueRelativeToLandingPad(
  2858. indexSym,
  2859. maxMagnitudeChange >= 0,
  2860. indexValueInfo,
  2861. indexBounds,
  2862. currentLoop->landingPad->globOptData.symToValueMap,
  2863. &indexOffset))
  2864. {
  2865. // The bound value is constant
  2866. indexSymToAdd = nullptr;
  2867. }
  2868. else
  2869. {
  2870. // The bound value is not constant, the offset needs to be added to the index sym in the landing pad
  2871. indexSymToAdd = indexSym;
  2872. }
  2873. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, L"Index's offset from landing pad is %d\n", indexOffset);
  2874. // The secondary induction variable bound is computed as follows:
  2875. // bound = index + indexOffset + loopCountMinusOne * maxMagnitudeChange
  2876. //
  2877. // If the loop count is constant, (inductionVariableOffset + loopCount * maxMagnitudeChange) can be folded into an offset:
  2878. // bound = index + offset
  2879. int offset;
  2880. StackSym *indexLoopCountBasedBoundBaseSym;
  2881. Value *indexLoopCountBasedBoundBaseValue;
  2882. IntConstantBounds indexLoopCountBasedBoundBaseConstantBounds;
  2883. bool generateLoopCountBasedIndexBound;
  2884. if(!loopCount->HasBeenGenerated() || loopCount->LoopCountMinusOneSym())
  2885. {
  2886. if(loopCount->HasBeenGenerated())
  2887. {
  2888. TRACE_PHASE_VERBOSE(
  2889. Js::Phase::BoundCheckHoistPhase,
  2890. 3,
  2891. L"Loop count is assigned to s%u\n",
  2892. loopCount->LoopCountMinusOneSym()->m_id);
  2893. }
  2894. else
  2895. {
  2896. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, L"Loop count has not been generated yet\n");
  2897. }
  2898. offset = indexOffset;
  2899. // Check if there is already a loop count based bound sym for the index. If not, generate it.
  2900. do
  2901. {
  2902. const SymID indexSymId = indexSym->m_id;
  2903. SymIdToStackSymMap *&loopCountBasedBoundBaseSyms = currentLoop->loopCountBasedBoundBaseSyms;
  2904. if(!loopCountBasedBoundBaseSyms)
  2905. {
  2906. loopCountBasedBoundBaseSyms = JitAnew(alloc, SymIdToStackSymMap, alloc);
  2907. }
  2908. else if(loopCountBasedBoundBaseSyms->TryGetValue(indexSymId, &indexLoopCountBasedBoundBaseSym))
  2909. {
  2910. TRACE_PHASE_VERBOSE(
  2911. Js::Phase::BoundCheckHoistPhase,
  2912. 3,
  2913. L"Loop count based bound is assigned to s%u\n",
  2914. indexLoopCountBasedBoundBaseSym->m_id);
  2915. indexLoopCountBasedBoundBaseValue = FindValue(landingPadSymToValueMap, indexLoopCountBasedBoundBaseSym);
  2916. Assert(indexLoopCountBasedBoundBaseValue);
  2917. AssertVerify(
  2918. indexLoopCountBasedBoundBaseValue
  2919. ->GetValueInfo()
  2920. ->TryGetIntConstantBounds(&indexLoopCountBasedBoundBaseConstantBounds));
  2921. generateLoopCountBasedIndexBound = false;
  2922. break;
  2923. }
  2924. indexLoopCountBasedBoundBaseSym = StackSym::New(TyInt32, func);
  2925. TRACE_PHASE_VERBOSE(
  2926. Js::Phase::BoundCheckHoistPhase,
  2927. 3,
  2928. L"Assigning s%u to the loop count based bound\n",
  2929. indexLoopCountBasedBoundBaseSym->m_id);
  2930. loopCountBasedBoundBaseSyms->Add(indexSymId, indexLoopCountBasedBoundBaseSym);
  2931. indexLoopCountBasedBoundBaseValue = NewValue(ValueInfo::New(alloc, ValueType::GetInt(true)));
  2932. SetValue(&landingPadBlockData, indexLoopCountBasedBoundBaseValue, indexLoopCountBasedBoundBaseSym);
  2933. indexLoopCountBasedBoundBaseConstantBounds = IntConstantBounds(IntConstMin, IntConstMax);
  2934. generateLoopCountBasedIndexBound = true;
  2935. } while(false);
  2936. }
  2937. else
  2938. {
  2939. // The loop count is constant, fold (indexOffset + loopCountMinusOne * maxMagnitudeChange)
  2940. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, L"Loop count is constant, folding\n");
  2941. if(Int32Math::Mul(loopCount->LoopCountMinusOneConstantValue(), maxMagnitudeChange, &offset) ||
  2942. Int32Math::Add(offset, indexOffset, &offset))
  2943. {
  2944. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, L"Folding failed\n");
  2945. return;
  2946. }
  2947. if(!indexSymToAdd)
  2948. {
  2949. // The loop count based bound is constant
  2950. const int loopCountBasedConstantBound = offset;
  2951. TRACE_PHASE_VERBOSE(
  2952. Js::Phase::BoundCheckHoistPhase,
  2953. 3,
  2954. L"Loop count based bound is constant: %d\n",
  2955. loopCountBasedConstantBound);
  2956. if(maxMagnitudeChange < 0)
  2957. {
  2958. if(loopCountBasedConstantBound < 0)
  2959. {
  2960. // Can't use this bound
  2961. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, L"Bound < 0\n");
  2962. return;
  2963. }
  2964. lowerHoistInfo.SetLoop(currentLoop, loopCountBasedConstantBound, true);
  2965. return;
  2966. }
  2967. // loopCountBasedConstantBound >= headSegmentLength is currently not possible, except when
  2968. // loopCountBasedConstantBound == int32 max
  2969. Assert(
  2970. loopCountBasedConstantBound == IntConstMax ||
  2971. !ValueInfo::IsGreaterThanOrEqualTo(
  2972. nullptr,
  2973. loopCountBasedConstantBound,
  2974. loopCountBasedConstantBound,
  2975. landingPadHeadSegmentLengthValue,
  2976. landingPadHeadSegmentLengthConstantBounds.LowerBound(),
  2977. landingPadHeadSegmentLengthConstantBounds.UpperBound()));
  2978. // See if a compatible bound check is already available
  2979. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, L"Looking for a compatible bound check\n");
  2980. const IntBoundCheck *boundCheck;
  2981. if(blockData.availableIntBoundChecks->TryGetReference(
  2982. IntBoundCheckCompatibilityId(ZeroValueNumber, headSegmentLengthValue->GetValueNumber()),
  2983. &boundCheck))
  2984. {
  2985. // We need:
  2986. // loopCountBasedConstantBound < headSegmentLength
  2987. // Normalize the offset such that:
  2988. // 0 <= headSegmentLength + compatibleBoundCheckOffset
  2989. // Where (compatibleBoundCheckOffset = -1 - loopCountBasedConstantBound), and -1 is to simulate < instead of <=.
  2990. const int compatibleBoundCheckOffset = -1 - loopCountBasedConstantBound;
  2991. if(boundCheck->SetBoundOffset(compatibleBoundCheckOffset, true))
  2992. {
  2993. TRACE_PHASE_VERBOSE(
  2994. Js::Phase::BoundCheckHoistPhase,
  2995. 4,
  2996. L"Found in block %u\n",
  2997. boundCheck->Block()->GetBlockNum());
  2998. upperHoistInfo.SetCompatibleBoundCheck(boundCheck->Block(), loopCountBasedConstantBound);
  2999. return;
  3000. }
  3001. failedToUpdateCompatibleUpperBoundCheck = true;
  3002. }
  3003. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, L"Not found\n");
  3004. upperHoistInfo.SetLoop(
  3005. currentLoop,
  3006. loopCountBasedConstantBound,
  3007. landingPadHeadSegmentLengthValue,
  3008. landingPadHeadSegmentLengthConstantBounds,
  3009. true);
  3010. return;
  3011. }
  3012. // The loop count based bound is not constant; we need to add the offset of the index sym in the landing pad. Instead
  3013. // of adding though, we will treat the index sym as the loop count based bound base sym and adjust the offset that will
  3014. // be used in the bound check itself.
  3015. indexLoopCountBasedBoundBaseSym = indexSymToAdd;
  3016. indexLoopCountBasedBoundBaseValue = FindValue(landingPadSymToValueMap, indexSymToAdd);
  3017. Assert(indexLoopCountBasedBoundBaseValue);
  3018. AssertVerify(
  3019. indexLoopCountBasedBoundBaseValue
  3020. ->GetValueInfo()
  3021. ->TryGetIntConstantBounds(&indexLoopCountBasedBoundBaseConstantBounds));
  3022. generateLoopCountBasedIndexBound = false;
  3023. }
  3024. if(maxMagnitudeChange >= 0)
  3025. {
  3026. // We need:
  3027. // indexLoopCountBasedBoundBase + indexOffset < headSegmentLength
  3028. // Normalize the offset such that:
  3029. // indexLoopCountBasedBoundBase <= headSegmentLength + offset
  3030. // Where (offset = -1 - indexOffset), and -1 is to simulate < instead of <=.
  3031. offset = -1 - offset;
  3032. }
  3033. if(!generateLoopCountBasedIndexBound)
  3034. {
  3035. if(maxMagnitudeChange < 0)
  3036. {
  3037. if(offset != IntConstMax &&
  3038. ValueInfo::IsGreaterThanOrEqualTo(
  3039. nullptr,
  3040. 0,
  3041. 0,
  3042. indexLoopCountBasedBoundBaseValue,
  3043. indexLoopCountBasedBoundBaseConstantBounds.LowerBound(),
  3044. indexLoopCountBasedBoundBaseConstantBounds.UpperBound(),
  3045. offset + 1)) // + 1 to simulate > instead of >=
  3046. {
  3047. // loopCountBasedBound < 0, can't use this bound
  3048. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, L"Bound < 0\n");
  3049. return;
  3050. }
  3051. }
  3052. else if(
  3053. ValueInfo::IsGreaterThanOrEqualTo(
  3054. indexLoopCountBasedBoundBaseValue,
  3055. indexLoopCountBasedBoundBaseConstantBounds.LowerBound(),
  3056. indexLoopCountBasedBoundBaseConstantBounds.UpperBound(),
  3057. landingPadHeadSegmentLengthValue,
  3058. landingPadHeadSegmentLengthConstantBounds.LowerBound(),
  3059. landingPadHeadSegmentLengthConstantBounds.UpperBound(),
  3060. offset))
  3061. {
  3062. // loopCountBasedBound >= headSegmentLength, can't use this bound
  3063. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, L"Bound >= head segment length\n");
  3064. return;
  3065. }
  3066. // See if a compatible bound check is already available
  3067. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, L"Looking for a compatible bound check\n");
  3068. const ValueNumber indexLoopCountBasedBoundBaseValueNumber = indexLoopCountBasedBoundBaseValue->GetValueNumber();
  3069. const IntBoundCheck *boundCheck;
  3070. if(blockData.availableIntBoundChecks->TryGetReference(
  3071. maxMagnitudeChange < 0
  3072. ? IntBoundCheckCompatibilityId(
  3073. ZeroValueNumber,
  3074. indexLoopCountBasedBoundBaseValueNumber)
  3075. : IntBoundCheckCompatibilityId(
  3076. indexLoopCountBasedBoundBaseValueNumber,
  3077. headSegmentLengthValue->GetValueNumber()),
  3078. &boundCheck))
  3079. {
  3080. if(boundCheck->SetBoundOffset(offset, true))
  3081. {
  3082. TRACE_PHASE_VERBOSE(
  3083. Js::Phase::BoundCheckHoistPhase,
  3084. 4,
  3085. L"Found in block %u\n",
  3086. boundCheck->Block()->GetBlockNum());
  3087. if(maxMagnitudeChange < 0)
  3088. {
  3089. lowerHoistInfo.SetCompatibleBoundCheck(
  3090. boundCheck->Block(),
  3091. indexLoopCountBasedBoundBaseSym,
  3092. offset,
  3093. indexLoopCountBasedBoundBaseValueNumber);
  3094. }
  3095. else
  3096. {
  3097. upperHoistInfo.SetCompatibleBoundCheck(
  3098. boundCheck->Block(),
  3099. indexLoopCountBasedBoundBaseSym,
  3100. offset,
  3101. indexLoopCountBasedBoundBaseValueNumber);
  3102. }
  3103. return;
  3104. }
  3105. (maxMagnitudeChange < 0 ? failedToUpdateCompatibleLowerBoundCheck : failedToUpdateCompatibleUpperBoundCheck) = true;
  3106. }
  3107. TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, L"Not found\n");
  3108. }
  3109. if(maxMagnitudeChange < 0)
  3110. {
  3111. lowerHoistInfo.SetLoop(
  3112. currentLoop,
  3113. indexLoopCountBasedBoundBaseSym,
  3114. offset,
  3115. indexLoopCountBasedBoundBaseValue,
  3116. indexLoopCountBasedBoundBaseConstantBounds,
  3117. true);
  3118. if(generateLoopCountBasedIndexBound)
  3119. {
  3120. lowerHoistInfo.SetLoopCount(loopCount, maxMagnitudeChange);
  3121. }
  3122. return;
  3123. }
  3124. upperHoistInfo.SetLoop(
  3125. currentLoop,
  3126. indexLoopCountBasedBoundBaseSym,
  3127. offset,
  3128. indexLoopCountBasedBoundBaseValue,
  3129. indexLoopCountBasedBoundBaseConstantBounds,
  3130. landingPadHeadSegmentLengthValue,
  3131. landingPadHeadSegmentLengthConstantBounds,
  3132. true);
  3133. if(generateLoopCountBasedIndexBound)
  3134. {
  3135. upperHoistInfo.SetLoopCount(loopCount, maxMagnitudeChange);
  3136. }
  3137. }