| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "Backend.h"
- #if ENABLE_DEBUG_CONFIG_OPTIONS && DBG_DUMP
- #define TRACE_PHASE_VERBOSE(phase, indent, ...) \
- if(PHASE_VERBOSE_TRACE(phase, this->func)) \
- { \
- for(int i = 0; i < static_cast<int>(indent); ++i) \
- { \
- Output::Print(_u(" ")); \
- } \
- Output::Print(__VA_ARGS__); \
- Output::Flush(); \
- }
- #else
- #define TRACE_PHASE_VERBOSE(phase, indent, ...)
- #endif
- void GlobOpt::AddSubConstantInfo::Set(
- StackSym *const srcSym,
- Value *const srcValue,
- const bool srcValueIsLikelyConstant,
- const int32 offset)
- {
- Assert(srcSym);
- Assert(!srcSym->IsTypeSpec());
- Assert(srcValue);
- Assert(srcValue->GetValueInfo()->IsLikelyInt());
- this->srcSym = srcSym;
- this->srcValue = srcValue;
- this->srcValueIsLikelyConstant = srcValueIsLikelyConstant;
- this->offset = offset;
- }
- void GlobOpt::ArrayLowerBoundCheckHoistInfo::SetCompatibleBoundCheck(
- BasicBlock *const compatibleBoundCheckBlock,
- StackSym *const indexSym,
- const int offset,
- const ValueNumber indexValueNumber)
- {
- Assert(!Loop());
- Assert(compatibleBoundCheckBlock);
- Assert(indexSym);
- Assert(!indexSym->IsTypeSpec());
- Assert(indexValueNumber != InvalidValueNumber);
- this->compatibleBoundCheckBlock = compatibleBoundCheckBlock;
- this->indexSym = indexSym;
- this->offset = offset;
- this->indexValueNumber = indexValueNumber;
- }
- void GlobOpt::ArrayLowerBoundCheckHoistInfo::SetLoop(
- ::Loop *const loop,
- const int indexConstantValue,
- const bool isLoopCountBasedBound)
- {
- Assert(!CompatibleBoundCheckBlock());
- Assert(loop);
- this->loop = loop;
- indexSym = nullptr;
- offset = 0;
- indexValue = nullptr;
- indexConstantBounds = IntConstantBounds(indexConstantValue, indexConstantValue);
- this->isLoopCountBasedBound = isLoopCountBasedBound;
- loopCount = nullptr;
- }
- void GlobOpt::ArrayLowerBoundCheckHoistInfo::SetLoop(
- ::Loop *const loop,
- StackSym *const indexSym,
- const int offset,
- Value *const indexValue,
- const IntConstantBounds &indexConstantBounds,
- const bool isLoopCountBasedBound)
- {
- Assert(!CompatibleBoundCheckBlock());
- Assert(loop);
- Assert(indexSym);
- Assert(!indexSym->IsTypeSpec());
- Assert(indexValue);
- this->loop = loop;
- this->indexSym = indexSym;
- this->offset = offset;
- this->indexValueNumber = indexValue->GetValueNumber();
- this->indexValue = indexValue;
- this->indexConstantBounds = indexConstantBounds;
- this->isLoopCountBasedBound = isLoopCountBasedBound;
- loopCount = nullptr;
- }
- void GlobOpt::ArrayLowerBoundCheckHoistInfo::SetLoopCount(::LoopCount *const loopCount, const int maxMagnitudeChange)
- {
- Assert(Loop());
- Assert(loopCount);
- Assert(maxMagnitudeChange != 0);
- this->loopCount = loopCount;
- this->maxMagnitudeChange = maxMagnitudeChange;
- }
- void GlobOpt::ArrayUpperBoundCheckHoistInfo::SetCompatibleBoundCheck(
- BasicBlock *const compatibleBoundCheckBlock,
- const int indexConstantValue)
- {
- Assert(!Loop());
- Assert(compatibleBoundCheckBlock);
- this->compatibleBoundCheckBlock = compatibleBoundCheckBlock;
- indexSym = nullptr;
- offset = -1; // simulate < instead of <=
- indexConstantBounds = IntConstantBounds(indexConstantValue, indexConstantValue);
- }
- void GlobOpt::ArrayUpperBoundCheckHoistInfo::SetLoop(
- ::Loop *const loop,
- const int indexConstantValue,
- Value *const headSegmentLengthValue,
- const IntConstantBounds &headSegmentLengthConstantBounds,
- const bool isLoopCountBasedBound)
- {
- Assert(!CompatibleBoundCheckBlock());
- Assert(loop);
- Assert(headSegmentLengthValue);
- SetLoop(loop, indexConstantValue, isLoopCountBasedBound);
- offset = -1; // simulate < instead of <=
- this->headSegmentLengthValue = headSegmentLengthValue;
- this->headSegmentLengthConstantBounds = headSegmentLengthConstantBounds;
- }
- void GlobOpt::ArrayUpperBoundCheckHoistInfo::SetLoop(
- ::Loop *const loop,
- StackSym *const indexSym,
- const int offset,
- Value *const indexValue,
- const IntConstantBounds &indexConstantBounds,
- Value *const headSegmentLengthValue,
- const IntConstantBounds &headSegmentLengthConstantBounds,
- const bool isLoopCountBasedBound)
- {
- Assert(headSegmentLengthValue);
- SetLoop(loop, indexSym, offset, indexValue, indexConstantBounds, isLoopCountBasedBound);
- this->headSegmentLengthValue = headSegmentLengthValue;
- this->headSegmentLengthConstantBounds = headSegmentLengthConstantBounds;
- }
- void GlobOpt::UpdateIntBoundsForEqualBranch(
- Value *const src1Value,
- Value *const src2Value,
- const int32 src2ConstantValue)
- {
- Assert(src1Value);
- if(!DoPathDependentValues() || (src2Value && src1Value->GetValueNumber() == src2Value->GetValueNumber()))
- {
- return;
- }
- #if DBG
- if(!IsLoopPrePass() && DoAggressiveIntTypeSpec() && DoConstFold())
- {
- IntConstantBounds src1ConstantBounds, src2ConstantBounds;
- AssertVerify(src1Value->GetValueInfo()->TryGetIntConstantBounds(&src1ConstantBounds, true));
- if(src2Value)
- {
- AssertVerify(src2Value->GetValueInfo()->TryGetIntConstantBounds(&src2ConstantBounds, true));
- }
- else
- {
- src2ConstantBounds = IntConstantBounds(src2ConstantValue, src2ConstantValue);
- }
- Assert(
- !ValueInfo::IsEqualTo(
- src1Value,
- src1ConstantBounds.LowerBound(),
- src1ConstantBounds.UpperBound(),
- src2Value,
- src2ConstantBounds.LowerBound(),
- src2ConstantBounds.UpperBound()));
- Assert(
- !ValueInfo::IsNotEqualTo(
- src1Value,
- src1ConstantBounds.LowerBound(),
- src1ConstantBounds.UpperBound(),
- src2Value,
- src2ConstantBounds.LowerBound(),
- src2ConstantBounds.UpperBound()));
- }
- #endif
- SetPathDependentInfo(
- true,
- PathDependentInfo(PathDependentRelationship::Equal, src1Value, src2Value, src2ConstantValue));
- SetPathDependentInfo(
- false,
- PathDependentInfo(PathDependentRelationship::NotEqual, src1Value, src2Value, src2ConstantValue));
- }
- void GlobOpt::UpdateIntBoundsForNotEqualBranch(
- Value *const src1Value,
- Value *const src2Value,
- const int32 src2ConstantValue)
- {
- Assert(src1Value);
- if(!DoPathDependentValues() || (src2Value && src1Value->GetValueNumber() == src2Value->GetValueNumber()))
- {
- return;
- }
- #if DBG
- if(!IsLoopPrePass() && DoAggressiveIntTypeSpec() && DoConstFold())
- {
- IntConstantBounds src1ConstantBounds, src2ConstantBounds;
- AssertVerify(src1Value->GetValueInfo()->TryGetIntConstantBounds(&src1ConstantBounds, true));
- if(src2Value)
- {
- AssertVerify(src2Value->GetValueInfo()->TryGetIntConstantBounds(&src2ConstantBounds, true));
- }
- else
- {
- src2ConstantBounds = IntConstantBounds(src2ConstantValue, src2ConstantValue);
- }
- Assert(
- !ValueInfo::IsEqualTo(
- src1Value,
- src1ConstantBounds.LowerBound(),
- src1ConstantBounds.UpperBound(),
- src2Value,
- src2ConstantBounds.LowerBound(),
- src2ConstantBounds.UpperBound()));
- Assert(
- !ValueInfo::IsNotEqualTo(
- src1Value,
- src1ConstantBounds.LowerBound(),
- src1ConstantBounds.UpperBound(),
- src2Value,
- src2ConstantBounds.LowerBound(),
- src2ConstantBounds.UpperBound()));
- }
- #endif
- SetPathDependentInfo(
- true, PathDependentInfo(PathDependentRelationship::NotEqual, src1Value, src2Value, src2ConstantValue));
- SetPathDependentInfo(
- false, PathDependentInfo(PathDependentRelationship::Equal, src1Value, src2Value, src2ConstantValue));
- }
- void GlobOpt::UpdateIntBoundsForGreaterThanOrEqualBranch(Value *const src1Value, Value *const src2Value)
- {
- Assert(src1Value);
- Assert(src2Value);
- if(!DoPathDependentValues() || src1Value->GetValueNumber() == src2Value->GetValueNumber())
- {
- return;
- }
- #if DBG
- if(!IsLoopPrePass() && DoAggressiveIntTypeSpec() && DoConstFold())
- {
- IntConstantBounds src1ConstantBounds, src2ConstantBounds;
- AssertVerify(src1Value->GetValueInfo()->TryGetIntConstantBounds(&src1ConstantBounds, true));
- AssertVerify(src2Value->GetValueInfo()->TryGetIntConstantBounds(&src2ConstantBounds, true));
- Assert(
- !ValueInfo::IsGreaterThanOrEqualTo(
- src1Value,
- src1ConstantBounds.LowerBound(),
- src1ConstantBounds.UpperBound(),
- src2Value,
- src2ConstantBounds.LowerBound(),
- src2ConstantBounds.UpperBound()));
- Assert(
- !ValueInfo::IsLessThan(
- src1Value,
- src1ConstantBounds.LowerBound(),
- src1ConstantBounds.UpperBound(),
- src2Value,
- src2ConstantBounds.LowerBound(),
- src2ConstantBounds.UpperBound()));
- }
- #endif
- SetPathDependentInfo(true, PathDependentInfo(PathDependentRelationship::GreaterThanOrEqual, src1Value, src2Value));
- SetPathDependentInfo(false, PathDependentInfo(PathDependentRelationship::LessThan, src1Value, src2Value));
- }
- void GlobOpt::UpdateIntBoundsForGreaterThanBranch(Value *const src1Value, Value *const src2Value)
- {
- return UpdateIntBoundsForLessThanBranch(src2Value, src1Value);
- }
- void GlobOpt::UpdateIntBoundsForLessThanOrEqualBranch(Value *const src1Value, Value *const src2Value)
- {
- return UpdateIntBoundsForGreaterThanOrEqualBranch(src2Value, src1Value);
- }
- void GlobOpt::UpdateIntBoundsForLessThanBranch(Value *const src1Value, Value *const src2Value)
- {
- Assert(src1Value);
- Assert(src2Value);
- if(!DoPathDependentValues() || src1Value->GetValueNumber() == src2Value->GetValueNumber())
- {
- return;
- }
- #if DBG
- if(!IsLoopPrePass() && DoAggressiveIntTypeSpec() && DoConstFold())
- {
- IntConstantBounds src1ConstantBounds, src2ConstantBounds;
- AssertVerify(src1Value->GetValueInfo()->TryGetIntConstantBounds(&src1ConstantBounds, true));
- AssertVerify(src2Value->GetValueInfo()->TryGetIntConstantBounds(&src2ConstantBounds, true));
- Assert(
- !ValueInfo::IsGreaterThanOrEqualTo(
- src1Value,
- src1ConstantBounds.LowerBound(),
- src1ConstantBounds.UpperBound(),
- src2Value,
- src2ConstantBounds.LowerBound(),
- src2ConstantBounds.UpperBound()));
- Assert(
- !ValueInfo::IsLessThan(
- src1Value,
- src1ConstantBounds.LowerBound(),
- src1ConstantBounds.UpperBound(),
- src2Value,
- src2ConstantBounds.LowerBound(),
- src2ConstantBounds.UpperBound()));
- }
- #endif
- SetPathDependentInfo(true, PathDependentInfo(PathDependentRelationship::LessThan, src1Value, src2Value));
- SetPathDependentInfo(false, PathDependentInfo(PathDependentRelationship::GreaterThanOrEqual, src1Value, src2Value));
- }
- IntBounds *GlobOpt::GetIntBoundsToUpdate(
- const ValueInfo *const valueInfo,
- const IntConstantBounds &constantBounds,
- const bool isSettingNewBound,
- const bool isBoundConstant,
- const bool isSettingUpperBound,
- const bool isExplicit)
- {
- Assert(valueInfo);
- Assert(valueInfo->IsLikelyInt());
- if(!DoTrackRelativeIntBounds())
- {
- return nullptr;
- }
- if(valueInfo->IsIntBounded())
- {
- const IntBounds *const bounds = valueInfo->AsIntBounded()->Bounds();
- if(bounds->RequiresIntBoundedValueInfo(valueInfo->Type()))
- {
- return bounds->Clone();
- }
- }
- if(valueInfo->IsInt())
- {
- if(constantBounds.IsConstant())
- {
- // Don't start tracking relative bounds for int constant values, just retain existing relative bounds. Will use
- // IntConstantValueInfo instead.
- return nullptr;
- }
- if(isBoundConstant)
- {
- // There are no relative bounds to track
- if(!(isSettingUpperBound && isExplicit))
- {
- // We are not setting a constant upper bound that is established explicitly, will use IntRangeValueInfo instead
- return nullptr;
- }
- }
- else if(!isSettingNewBound)
- {
- // New relative bounds are not being set, will use IntRangeValueInfo instead
- return nullptr;
- }
- return IntBounds::New(constantBounds, false, alloc);
- }
- return nullptr;
- }
- ValueInfo *GlobOpt::UpdateIntBoundsForEqual(
- Value *const value,
- const IntConstantBounds &constantBounds,
- Value *const boundValue,
- const IntConstantBounds &boundConstantBounds,
- const bool isExplicit)
- {
- Assert(value || constantBounds.IsConstant());
- Assert(boundValue || boundConstantBounds.IsConstant());
- if(!value)
- {
- return nullptr;
- }
- Assert(!boundValue || value->GetValueNumber() != boundValue->GetValueNumber());
- ValueInfo *const valueInfo = value->GetValueInfo();
- IntBounds *const bounds =
- GetIntBoundsToUpdate(valueInfo, constantBounds, true, boundConstantBounds.IsConstant(), true, isExplicit);
- if(bounds)
- {
- if(boundValue)
- {
- const ValueNumber valueNumber = value->GetValueNumber();
- bounds->SetLowerBound(valueNumber, boundValue, isExplicit);
- bounds->SetUpperBound(valueNumber, boundValue, isExplicit);
- }
- else
- {
- bounds->SetLowerBound(boundConstantBounds.LowerBound());
- bounds->SetUpperBound(boundConstantBounds.LowerBound(), isExplicit);
- }
- if(bounds->RequiresIntBoundedValueInfo(valueInfo->Type()))
- {
- return NewIntBoundedValueInfo(valueInfo, bounds);
- }
- bounds->Delete();
- }
- if(!valueInfo->IsInt())
- {
- return nullptr;
- }
- const int32 newMin = max(constantBounds.LowerBound(), boundConstantBounds.LowerBound());
- const int32 newMax = min(constantBounds.UpperBound(), boundConstantBounds.UpperBound());
- return newMin <= newMax ? NewIntRangeValueInfo(valueInfo, newMin, newMax) : nullptr;
- }
- ValueInfo *GlobOpt::UpdateIntBoundsForNotEqual(
- Value *const value,
- const IntConstantBounds &constantBounds,
- Value *const boundValue,
- const IntConstantBounds &boundConstantBounds,
- const bool isExplicit)
- {
- Assert(value || constantBounds.IsConstant());
- Assert(boundValue || boundConstantBounds.IsConstant());
- if(!value)
- {
- return nullptr;
- }
- Assert(!boundValue || value->GetValueNumber() != boundValue->GetValueNumber());
- ValueInfo *const valueInfo = value->GetValueInfo();
- IntBounds *const bounds =
- GetIntBoundsToUpdate(
- valueInfo,
- constantBounds,
- false,
- boundConstantBounds.IsConstant(),
- boundConstantBounds.IsConstant() && boundConstantBounds.LowerBound() == constantBounds.UpperBound(),
- isExplicit);
- if(bounds)
- {
- if(boundValue
- ? bounds->SetIsNot(boundValue, isExplicit)
- : bounds->SetIsNot(boundConstantBounds.LowerBound(), isExplicit))
- {
- if(bounds->RequiresIntBoundedValueInfo(valueInfo->Type()))
- {
- return NewIntBoundedValueInfo(valueInfo, bounds);
- }
- }
- else
- {
- bounds->Delete();
- return nullptr;
- }
- bounds->Delete();
- }
- if(!valueInfo->IsInt() || !boundConstantBounds.IsConstant())
- {
- return nullptr;
- }
- const int32 constantBound = boundConstantBounds.LowerBound();
- // 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
- int32 newMin = constantBounds.LowerBound(), newMax = constantBounds.UpperBound();
- if(constantBound == newMin)
- {
- Assert(newMin <= newMax);
- if(newMin == newMax)
- {
- return nullptr;
- }
- ++newMin;
- }
- else if(constantBound == newMax)
- {
- Assert(newMin <= newMax);
- if(newMin == newMax)
- {
- return nullptr;
- }
- --newMax;
- }
- else
- {
- return nullptr;
- }
- return NewIntRangeValueInfo(valueInfo, newMin, newMax);
- }
- ValueInfo *GlobOpt::UpdateIntBoundsForGreaterThanOrEqual(
- Value *const value,
- const IntConstantBounds &constantBounds,
- Value *const boundValue,
- const IntConstantBounds &boundConstantBounds,
- const bool isExplicit)
- {
- return UpdateIntBoundsForGreaterThanOrEqual(value, constantBounds, boundValue, boundConstantBounds, 0, isExplicit);
- }
- ValueInfo *GlobOpt::UpdateIntBoundsForGreaterThanOrEqual(
- Value *const value,
- const IntConstantBounds &constantBounds,
- Value *const boundValue,
- const IntConstantBounds &boundConstantBounds,
- const int boundOffset,
- const bool isExplicit)
- {
- Assert(value || constantBounds.IsConstant());
- Assert(boundValue || boundConstantBounds.IsConstant());
- if(!value)
- {
- return nullptr;
- }
- Assert(!boundValue || value->GetValueNumber() != boundValue->GetValueNumber());
- ValueInfo *const valueInfo = value->GetValueInfo();
- IntBounds *const bounds =
- GetIntBoundsToUpdate(valueInfo, constantBounds, true, boundConstantBounds.IsConstant(), false, isExplicit);
- if(bounds)
- {
- if(boundValue)
- {
- bounds->SetLowerBound(value->GetValueNumber(), boundValue, boundOffset, isExplicit);
- }
- else
- {
- bounds->SetLowerBound(boundConstantBounds.LowerBound(), boundOffset);
- }
- if(bounds->RequiresIntBoundedValueInfo(valueInfo->Type()))
- {
- return NewIntBoundedValueInfo(valueInfo, bounds);
- }
- bounds->Delete();
- }
- if(!valueInfo->IsInt())
- {
- return nullptr;
- }
- int32 adjustedBoundMin;
- if(boundOffset == 0)
- {
- adjustedBoundMin = boundConstantBounds.LowerBound();
- }
- else if(boundOffset == 1)
- {
- if(boundConstantBounds.LowerBound() + 1 <= boundConstantBounds.LowerBound())
- {
- return nullptr;
- }
- adjustedBoundMin = boundConstantBounds.LowerBound() + 1;
- }
- else if(Int32Math::Add(boundConstantBounds.LowerBound(), boundOffset, &adjustedBoundMin))
- {
- return nullptr;
- }
- const int32 newMin = max(constantBounds.LowerBound(), adjustedBoundMin);
- return
- newMin <= constantBounds.UpperBound()
- ? NewIntRangeValueInfo(valueInfo, newMin, constantBounds.UpperBound())
- : nullptr;
- }
- ValueInfo *GlobOpt::UpdateIntBoundsForGreaterThan(
- Value *const value,
- const IntConstantBounds &constantBounds,
- Value *const boundValue,
- const IntConstantBounds &boundConstantBounds,
- const bool isExplicit)
- {
- return UpdateIntBoundsForGreaterThanOrEqual(value, constantBounds, boundValue, boundConstantBounds, 1, isExplicit);
- }
- ValueInfo *GlobOpt::UpdateIntBoundsForLessThanOrEqual(
- Value *const value,
- const IntConstantBounds &constantBounds,
- Value *const boundValue,
- const IntConstantBounds &boundConstantBounds,
- const bool isExplicit)
- {
- return UpdateIntBoundsForLessThanOrEqual(value, constantBounds, boundValue, boundConstantBounds, 0, isExplicit);
- }
- ValueInfo *GlobOpt::UpdateIntBoundsForLessThanOrEqual(
- Value *const value,
- const IntConstantBounds &constantBounds,
- Value *const boundValue,
- const IntConstantBounds &boundConstantBounds,
- const int boundOffset,
- const bool isExplicit)
- {
- Assert(value || constantBounds.IsConstant());
- Assert(boundValue || boundConstantBounds.IsConstant());
- if(!value)
- {
- return nullptr;
- }
- Assert(!boundValue || value->GetValueNumber() != boundValue->GetValueNumber());
- ValueInfo *const valueInfo = value->GetValueInfo();
- IntBounds *const bounds =
- GetIntBoundsToUpdate(valueInfo, constantBounds, true, boundConstantBounds.IsConstant(), true, isExplicit);
- if(bounds)
- {
- if(boundValue)
- {
- bounds->SetUpperBound(value->GetValueNumber(), boundValue, boundOffset, isExplicit);
- }
- else
- {
- bounds->SetUpperBound(boundConstantBounds.LowerBound(), boundOffset, isExplicit);
- }
- if(bounds->RequiresIntBoundedValueInfo(valueInfo->Type()))
- {
- return NewIntBoundedValueInfo(valueInfo, bounds);
- }
- bounds->Delete();
- }
- if(!valueInfo->IsInt())
- {
- return nullptr;
- }
- int32 adjustedBoundMax;
- if(boundOffset == 0)
- {
- adjustedBoundMax = boundConstantBounds.UpperBound();
- }
- else if(boundOffset == -1)
- {
- if(boundConstantBounds.UpperBound() - 1 >= boundConstantBounds.UpperBound())
- {
- return nullptr;
- }
- adjustedBoundMax = boundConstantBounds.UpperBound() - 1;
- }
- else if(Int32Math::Add(boundConstantBounds.UpperBound(), boundOffset, &adjustedBoundMax))
- {
- return nullptr;
- }
- const int32 newMax = min(constantBounds.UpperBound(), adjustedBoundMax);
- return
- newMax >= constantBounds.LowerBound()
- ? NewIntRangeValueInfo(valueInfo, constantBounds.LowerBound(), newMax)
- : nullptr;
- }
- ValueInfo *GlobOpt::UpdateIntBoundsForLessThan(
- Value *const value,
- const IntConstantBounds &constantBounds,
- Value *const boundValue,
- const IntConstantBounds &boundConstantBounds,
- const bool isExplicit)
- {
- return UpdateIntBoundsForLessThanOrEqual(value, constantBounds, boundValue, boundConstantBounds, -1, isExplicit);
- }
- void GlobOpt::TrackIntSpecializedAddSubConstant(
- IR::Instr *const instr,
- const AddSubConstantInfo *const addSubConstantInfo,
- Value *const dstValue,
- const bool updateSourceBounds)
- {
- Assert(instr);
- Assert(dstValue);
- if(addSubConstantInfo)
- {
- Assert(addSubConstantInfo->HasInfo());
- Assert(!ignoredIntOverflowForCurrentInstr);
- do
- {
- if(!IsLoopPrePass() || !DoBoundCheckHoist())
- {
- break;
- }
- Assert(
- instr->m_opcode == Js::OpCode::Incr_A ||
- instr->m_opcode == Js::OpCode::Decr_A ||
- instr->m_opcode == Js::OpCode::Add_A ||
- instr->m_opcode == Js::OpCode::Sub_A);
- StackSym *sym = instr->GetDst()->AsRegOpnd()->m_sym;
- bool isPostfixIncDecPattern = false;
- if(addSubConstantInfo->SrcSym() != sym)
- {
- // Check for the following patterns.
- //
- // This pattern is used for postfix inc/dec operators:
- // s2 = Conv_Num s1
- // s1 = Inc s2
- //
- // This pattern is used for prefix inc/dec operators:
- // s2 = Inc s1
- // s1 = Ld s2
- IR::Instr *const prevInstr = instr->m_prev;
- Assert(prevInstr);
- if(prevInstr->m_opcode == Js::OpCode::Conv_Num &&
- prevInstr->GetSrc1()->IsRegOpnd() &&
- prevInstr->GetSrc1()->AsRegOpnd()->m_sym == sym &&
- prevInstr->GetDst()->AsRegOpnd()->m_sym == addSubConstantInfo->SrcSym())
- {
- // s2 will get a new value number, since Conv_Num cannot transfer in the prepass. For the purposes of
- // induction variable tracking however, it doesn't matter, so record this case and use s1's value in the
- // current block.
- isPostfixIncDecPattern = true;
- }
- else
- {
- IR::Instr *const nextInstr = instr->m_next;
- Assert(nextInstr);
- if(nextInstr->m_opcode != Js::OpCode::Ld_A ||
- !nextInstr->GetSrc1()->IsRegOpnd() ||
- nextInstr->GetSrc1()->AsRegOpnd()->m_sym != sym)
- {
- break;
- }
- sym = addSubConstantInfo->SrcSym();
- if(nextInstr->GetDst()->AsRegOpnd()->m_sym != sym)
- {
- break;
- }
- // In the prefix inc/dec pattern, the result of Ld currently gets a new value number, which will cause the
- // induction variable info to become indeterminate. Indicate that the value number should be updated in the
- // induction variable info.
- // Consider: Remove this once loop prepass value transfer scheme is fixed
- updateInductionVariableValueNumber = true;
- }
- }
- // Track induction variable info
- ValueNumber srcValueNumber;
- if(isPostfixIncDecPattern)
- {
- Value *const value = this->currentBlock->globOptData.FindValue(sym);
- Assert(value);
- srcValueNumber = value->GetValueNumber();
- }
- else
- {
- srcValueNumber = addSubConstantInfo->SrcValue()->GetValueNumber();
- }
- InductionVariableSet *const inductionVariables = currentBlock->globOptData.inductionVariables;
- Assert(inductionVariables);
- InductionVariable *inductionVariable;
- if(!inductionVariables->TryGetReference(sym->m_id, &inductionVariable))
- {
- // Only track changes in the current loop's prepass. In subsequent prepasses, the info is only being propagated
- // for use by the parent loop, so changes in the current loop have already been tracked.
- if(prePassLoop != currentBlock->loop)
- {
- updateInductionVariableValueNumber = false;
- break;
- }
- // Ensure that the sym is live in the landing pad, and that its value has not changed in an unknown way yet
- Value *const landingPadValue = currentBlock->loop->landingPad->globOptData.FindValue(sym);
- if(!landingPadValue || srcValueNumber != landingPadValue->GetValueNumber())
- {
- updateInductionVariableValueNumber = false;
- break;
- }
- inductionVariables->Add(
- InductionVariable(sym, dstValue->GetValueNumber(), addSubConstantInfo->Offset()));
- break;
- }
- if(!inductionVariable->IsChangeDeterminate())
- {
- updateInductionVariableValueNumber = false;
- break;
- }
- if(srcValueNumber != inductionVariable->SymValueNumber())
- {
- // The sym's value has changed since the last time induction variable info was recorded for it. Due to the
- // unknown change, mark the info as indeterminate.
- inductionVariable->SetChangeIsIndeterminate();
- updateInductionVariableValueNumber = false;
- break;
- }
- // Only track changes in the current loop's prepass. In subsequent prepasses, the info is only being propagated for
- // use by the parent loop, so changes in the current loop have already been tracked. Induction variable value
- // numbers are updated as changes occur, but their change bounds are preserved from the first prepass over the loop.
- inductionVariable->SetSymValueNumber(dstValue->GetValueNumber());
- if(prePassLoop != currentBlock->loop)
- {
- break;
- }
- if(!inductionVariable->Add(addSubConstantInfo->Offset()))
- {
- updateInductionVariableValueNumber = false;
- }
- } while(false);
- if(updateSourceBounds && addSubConstantInfo->Offset() != IntConstMin)
- {
- // Track bounds for add or sub with a constant. For instance, consider (b = a + 2). The value of 'b' should track
- // that it is equal to (the value of 'a') + 2. That part has been done above. Similarly, the value of 'a' should
- // also track that it is equal to (the value of 'b') - 2.
- Value *const value = addSubConstantInfo->SrcValue();
- const ValueInfo *const valueInfo = value->GetValueInfo();
- Assert(valueInfo->IsInt());
- IntConstantBounds constantBounds;
- AssertVerify(valueInfo->TryGetIntConstantBounds(&constantBounds));
- IntBounds *const bounds =
- GetIntBoundsToUpdate(
- valueInfo,
- constantBounds,
- true,
- dstValue->GetValueInfo()->HasIntConstantValue(),
- true,
- true);
- if(bounds)
- {
- const ValueNumber valueNumber = value->GetValueNumber();
- const int32 dstOffset = -addSubConstantInfo->Offset();
- bounds->SetLowerBound(valueNumber, dstValue, dstOffset, true);
- bounds->SetUpperBound(valueNumber, dstValue, dstOffset, true);
- ChangeValueInfo(nullptr, value, NewIntBoundedValueInfo(valueInfo, bounds));
- }
- }
- return;
- }
- if(!updateInductionVariableValueNumber)
- {
- return;
- }
- // See comment above where this is set to true
- // Consider: Remove this once loop prepass value transfer scheme is fixed
- updateInductionVariableValueNumber = false;
- Assert(IsLoopPrePass());
- Assert(instr->m_opcode == Js::OpCode::Ld_A);
- Assert(
- instr->m_prev->m_opcode == Js::OpCode::Incr_A ||
- instr->m_prev->m_opcode == Js::OpCode::Decr_A ||
- instr->m_prev->m_opcode == Js::OpCode::Add_A ||
- instr->m_prev->m_opcode == Js::OpCode::Sub_A);
- Assert(instr->m_prev->GetDst()->AsRegOpnd()->m_sym == instr->GetSrc1()->AsRegOpnd()->m_sym);
- InductionVariable *inductionVariable;
- AssertVerify(currentBlock->globOptData.inductionVariables->TryGetReference(instr->GetDst()->AsRegOpnd()->m_sym->m_id, &inductionVariable));
- inductionVariable->SetSymValueNumber(dstValue->GetValueNumber());
- }
- void GlobOpt::CloneBoundCheckHoistBlockData(
- BasicBlock *const toBlock,
- GlobOptBlockData *const toData,
- BasicBlock *const fromBlock,
- GlobOptBlockData *const fromData)
- {
- Assert(DoBoundCheckHoist());
- Assert(toBlock);
- Assert(toData);
- //Assert(toData == &toBlock->globOptData || toData == ¤tBlock->globOptData);
- Assert(fromBlock);
- Assert(fromData);
- Assert(fromData == &fromBlock->globOptData);
- Assert(fromData->availableIntBoundChecks);
- toData->availableIntBoundChecks = fromData->availableIntBoundChecks->Clone();
- if(toBlock->isLoopHeader)
- {
- Assert(fromBlock == toBlock->loop->landingPad);
- if(prePassLoop == toBlock->loop)
- {
- // When the current prepass loop is the current loop, the loop header's induction variable set needs to start off
- // empty to track changes in the current loop
- toData->inductionVariables = JitAnew(alloc, InductionVariableSet, alloc);
- return;
- }
- if(!IsLoopPrePass())
- {
- return;
- }
- // After the prepass on this loop, if we're still in a prepass, this must be an inner loop. Merge the landing pad info
- // for use by the parent loop.
- Assert(fromBlock->loop);
- Assert(fromData->inductionVariables);
- toData->inductionVariables = fromData->inductionVariables->Clone();
- return;
- }
- if(!toBlock->loop || !IsLoopPrePass())
- {
- return;
- }
- Assert(fromBlock->loop);
- Assert(toBlock->loop->IsDescendentOrSelf(fromBlock->loop));
- Assert(fromData->inductionVariables);
- toData->inductionVariables = fromData->inductionVariables->Clone();
- }
- void GlobOpt::MergeBoundCheckHoistBlockData(
- BasicBlock *const toBlock,
- GlobOptBlockData *const toData,
- BasicBlock *const fromBlock,
- GlobOptBlockData *const fromData)
- {
- Assert(DoBoundCheckHoist());
- Assert(toBlock);
- Assert(toData);
- //Assert(toData == &toBlock->globOptData || toData == ¤tBlock->globOptData);
- Assert(fromBlock);
- Assert(fromData);
- Assert(fromData == &fromBlock->globOptData);
- Assert(toData->availableIntBoundChecks);
- for(auto it = toData->availableIntBoundChecks->GetIteratorWithRemovalSupport(); it.IsValid(); it.MoveNext())
- {
- const IntBoundCheck &toDataIntBoundCheck = it.CurrentValue();
- const IntBoundCheck *fromDataIntBoundCheck;
- if(!fromData->availableIntBoundChecks->TryGetReference(
- toDataIntBoundCheck.CompatibilityId(),
- &fromDataIntBoundCheck) ||
- fromDataIntBoundCheck->Instr() != toDataIntBoundCheck.Instr())
- {
- it.RemoveCurrent();
- }
- }
- InductionVariableSet *mergeInductionVariablesInto;
- if(toBlock->isLoopHeader)
- {
- Assert(fromBlock->loop == toBlock->loop); // The flow is such that you cannot have back-edges from an inner loop
- if(IsLoopPrePass())
- {
- // Collect info for the parent loop. Any changes to induction variables in this inner loop need to be expanded in
- // the same direction for the parent loop, so merge expanded info from back-edges. Info about induction variables
- // that changed before the loop but not inside the loop, can be kept intact because the landing pad dominates the
- // loop.
- Assert(prePassLoop != toBlock->loop);
- Assert(fromData->inductionVariables);
- Assert(toData->inductionVariables);
- InductionVariableSet *const mergedInductionVariables = toData->inductionVariables;
- for(auto it = fromData->inductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
- {
- InductionVariable backEdgeInductionVariable = it.CurrentValue();
- backEdgeInductionVariable.ExpandInnerLoopChange();
- StackSym *const sym = backEdgeInductionVariable.Sym();
- InductionVariable *mergedInductionVariable;
- if(mergedInductionVariables->TryGetReference(sym->m_id, &mergedInductionVariable))
- {
- mergedInductionVariable->Merge(backEdgeInductionVariable);
- continue;
- }
- // Ensure that the sym is live in the parent loop's landing pad, and that its value has not changed in an
- // unknown way between the parent loop's landing pad and the current loop's landing pad.
- Value *const parentLandingPadValue = currentBlock->loop->parent->landingPad->globOptData.FindValue(sym);
- if(!parentLandingPadValue)
- {
- continue;
- }
- Value *const landingPadValue = currentBlock->loop->landingPad->globOptData.FindValue(sym);
- Assert(landingPadValue);
- if(landingPadValue->GetValueNumber() == parentLandingPadValue->GetValueNumber())
- {
- mergedInductionVariables->Add(backEdgeInductionVariable);
- }
- }
- const InductionVariableSet *const fromDataInductionVariables = fromData->inductionVariables;
- for (auto it = mergedInductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
- {
- InductionVariable &mergedInductionVariable = it.CurrentValueReference();
- if (!mergedInductionVariable.IsChangeDeterminate())
- {
- continue;
- }
- StackSym *const sym = mergedInductionVariable.Sym();
- const InductionVariable *fromDataInductionVariable;
- if (fromDataInductionVariables->TryGetReference(sym->m_id, &fromDataInductionVariable))
- {
- continue;
- }
- // Process the set of symbols that are induction variables due to prior loops that share the same parent loop, but are not induction variables in the current loop
- // If the current loop is initializing such carried over induction variables, then their value numbers will differ from the current loop's landing pad
- // Such induction variables should be marked as indeterminate going forward, such the induction variable analysis accurately flows to the parent loop.
- Value *const fromDataValue = fromData->FindValue(sym);
- if (fromDataValue)
- {
- Value *const landingPadValue = toBlock->loop->landingPad->globOptData.FindValue(sym);
- if (landingPadValue && fromDataValue->GetValueNumber() != landingPadValue->GetValueNumber())
- {
- mergedInductionVariable.SetChangeIsIndeterminate();
- }
- }
- }
- return;
- }
- // Collect info for the current loop. We want to merge only the back-edge info without the landing pad info, such that
- // the loop's induction variable set reflects changes made inside this loop.
- Assert(fromData->inductionVariables);
- InductionVariableSet *&loopInductionVariables = toBlock->loop->inductionVariables;
- if(!loopInductionVariables)
- {
- loopInductionVariables = fromData->inductionVariables->Clone();
- return;
- }
- mergeInductionVariablesInto = loopInductionVariables;
- }
- else if(toBlock->loop && IsLoopPrePass())
- {
- Assert(fromBlock->loop);
- Assert(toBlock->loop->IsDescendentOrSelf(fromBlock->loop));
- mergeInductionVariablesInto = toData->inductionVariables;
- }
- else
- {
- return;
- }
- const InductionVariableSet *const fromDataInductionVariables = fromData->inductionVariables;
- InductionVariableSet *const mergedInductionVariables = mergeInductionVariablesInto;
- Assert(fromDataInductionVariables);
- Assert(mergedInductionVariables);
- for(auto it = mergedInductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
- {
- InductionVariable &mergedInductionVariable = it.CurrentValueReference();
- if(!mergedInductionVariable.IsChangeDeterminate())
- {
- continue;
- }
- StackSym *const sym = mergedInductionVariable.Sym();
- const InductionVariable *fromDataInductionVariable;
- if(fromDataInductionVariables->TryGetReference(sym->m_id, &fromDataInductionVariable))
- {
- mergedInductionVariable.Merge(*fromDataInductionVariable);
- continue;
- }
- // 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
- // where the sym is not already marked as an induction variable.
- Value *const fromDataValue = fromData->FindValue(sym);
- if(fromDataValue)
- {
- Value *const landingPadValue = toBlock->loop->landingPad->globOptData.FindValue(sym);
- if(landingPadValue && fromDataValue->GetValueNumber() == landingPadValue->GetValueNumber())
- {
- mergedInductionVariable.Merge(InductionVariable(sym, ZeroValueNumber, 0));
- continue;
- }
- }
- mergedInductionVariable.SetChangeIsIndeterminate();
- }
- for(auto it = fromDataInductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
- {
- const InductionVariable &fromDataInductionVariable = it.CurrentValue();
- StackSym *const sym = fromDataInductionVariable.Sym();
- if(mergedInductionVariables->ContainsKey(sym->m_id))
- {
- continue;
- }
- // 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
- // where the sym is not already marked as an induction variable.
- bool indeterminate = true;
- Value *const toDataValue = toData->FindValue(sym);
- if(toDataValue)
- {
- Value *const landingPadValue = toBlock->loop->landingPad->globOptData.FindValue(sym);
- if(landingPadValue && toDataValue->GetValueNumber() == landingPadValue->GetValueNumber())
- {
- indeterminate = false;
- }
- }
- InductionVariable mergedInductionVariable(sym, ZeroValueNumber, 0);
- if(indeterminate)
- {
- mergedInductionVariable.SetChangeIsIndeterminate();
- }
- else
- {
- mergedInductionVariable.Merge(fromDataInductionVariable);
- }
- mergedInductionVariables->Add(mergedInductionVariable);
- }
- }
- void GlobOpt::DetectUnknownChangesToInductionVariables(GlobOptBlockData *const blockData)
- {
- Assert(DoBoundCheckHoist());
- Assert(IsLoopPrePass());
- Assert(blockData);
- Assert(blockData->inductionVariables);
- // Check induction variable value numbers, and mark those that changed in an unknown way as indeterminate. They must remain
- // in the set though, for merging purposes.
- for(auto it = blockData->inductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
- {
- InductionVariable &inductionVariable = it.CurrentValueReference();
- if(!inductionVariable.IsChangeDeterminate())
- {
- continue;
- }
- Value *const value = blockData->FindValue(inductionVariable.Sym());
- if(!value || value->GetValueNumber() != inductionVariable.SymValueNumber())
- {
- inductionVariable.SetChangeIsIndeterminate();
- }
- }
- }
- void GlobOpt::SetInductionVariableValueNumbers(GlobOptBlockData *const blockData)
- {
- Assert(DoBoundCheckHoist());
- Assert(IsLoopPrePass());
- //Assert(blockData == &this->currentBlock->globOptData);
- Assert(blockData->inductionVariables);
- // Now that all values have been merged, update value numbers in the induction variable info.
- for(auto it = blockData->inductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
- {
- InductionVariable &inductionVariable = it.CurrentValueReference();
- if(!inductionVariable.IsChangeDeterminate())
- {
- continue;
- }
- Value *const value = blockData->FindValue(inductionVariable.Sym());
- if(value)
- {
- inductionVariable.SetSymValueNumber(value->GetValueNumber());
- }
- else
- {
- inductionVariable.SetChangeIsIndeterminate();
- }
- }
- }
- void GlobOpt::FinalizeInductionVariables(Loop *const loop, GlobOptBlockData *const headerData)
- {
- Assert(DoBoundCheckHoist());
- Assert(!IsLoopPrePass());
- Assert(loop);
- Assert(loop->GetHeadBlock() == currentBlock);
- Assert(loop->inductionVariables);
- Assert(currentBlock->isLoopHeader);
- //Assert(headerData == &this->currentBlock->globOptData);
- // Clean up induction variables and for each, install a relationship between its values inside and outside the loop.
- GlobOptBlockData &landingPadBlockData = loop->landingPad->globOptData;
- for(auto it = loop->inductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
- {
- InductionVariable &inductionVariable = it.CurrentValueReference();
- if(!inductionVariable.IsChangeDeterminate())
- {
- continue;
- }
- if(!inductionVariable.IsChangeUnidirectional())
- {
- inductionVariable.SetChangeIsIndeterminate();
- continue;
- }
- StackSym *const sym = inductionVariable.Sym();
- if(!headerData->IsInt32TypeSpecialized(sym))
- {
- inductionVariable.SetChangeIsIndeterminate();
- continue;
- }
- Assert(landingPadBlockData.IsInt32TypeSpecialized(sym));
- Value *const value = headerData->FindValue(sym);
- if(!value)
- {
- inductionVariable.SetChangeIsIndeterminate();
- continue;
- }
- Value *const landingPadValue = landingPadBlockData.FindValue(sym);
- Assert(landingPadValue);
- IntConstantBounds constantBounds, landingPadConstantBounds;
- AssertVerify(value->GetValueInfo()->TryGetIntConstantBounds(&constantBounds));
- AssertVerify(landingPadValue->GetValueInfo()->TryGetIntConstantBounds(&landingPadConstantBounds, true));
- // For an induction variable i, update the value of i inside the loop to indicate that it is bounded by the value of i
- // just before the loop.
- if(inductionVariable.ChangeBounds().LowerBound() >= 0)
- {
- ValueInfo *const newValueInfo =
- UpdateIntBoundsForGreaterThanOrEqual(value, constantBounds, landingPadValue, landingPadConstantBounds, true);
- ChangeValueInfo(nullptr, value, newValueInfo);
- if(inductionVariable.ChangeBounds().UpperBound() == 0)
- {
- AssertVerify(newValueInfo->TryGetIntConstantBounds(&constantBounds, true));
- }
- }
- if(inductionVariable.ChangeBounds().UpperBound() <= 0)
- {
- ValueInfo *const newValueInfo =
- UpdateIntBoundsForLessThanOrEqual(value, constantBounds, landingPadValue, landingPadConstantBounds, true);
- ChangeValueInfo(nullptr, value, newValueInfo);
- }
- }
- }
- GlobOpt::SymBoundType GlobOpt::DetermineSymBoundOffsetOrValueRelativeToLandingPad(
- StackSym *const sym,
- const bool landingPadValueIsLowerBound,
- ValueInfo *const valueInfo,
- const IntBounds *const bounds,
- GlobOptBlockData *const landingPadGlobOptBlockData,
- int *const boundOffsetOrValueRef)
- {
- Assert(sym);
- Assert(!sym->IsTypeSpec());
- Assert(valueInfo);
- Assert(landingPadGlobOptBlockData);
- Assert(boundOffsetOrValueRef);
- Assert(valueInfo->IsInt());
- int constantValue;
- if(valueInfo->TryGetIntConstantValue(&constantValue))
- {
- // The sym's constant value is the constant bound value, so just return that. This is possible in loops such as
- // for(; i === 1; ++i){...}, where 'i' is an induction variable but has a constant value inside the loop, or in blocks
- // inside the loop such as if(i === 1){...}
- *boundOffsetOrValueRef = constantValue;
- return SymBoundType::VALUE;
- }
- if (bounds)
- {
- Value *const landingPadValue = landingPadGlobOptBlockData->FindValue(sym);
- Assert(landingPadValue);
- Assert(landingPadValue->GetValueInfo()->IsInt());
- int landingPadConstantValue;
- const ValueRelativeOffset* bound = nullptr;
- const RelativeIntBoundSet& boundSet = landingPadValueIsLowerBound ? bounds->RelativeLowerBounds() : bounds->RelativeUpperBounds();
- if (landingPadValue->GetValueInfo()->TryGetIntConstantValue(&landingPadConstantValue))
- {
- // The sym's bound already takes the landing pad constant value into consideration, unless the landing pad value was
- // updated to have a more aggressive range (and hence, now a constant value) as part of hoisting a bound check or some
- // other hoisting operation. The sym's bound also takes into consideration the change to the sym so far inside the loop,
- // and the landing pad constant value does not, so use the sym's bound by default.
- int constantBound = landingPadValueIsLowerBound ? bounds->ConstantLowerBound() : bounds->ConstantUpperBound();
- if(landingPadValueIsLowerBound ? landingPadConstantValue > constantBound : landingPadConstantValue < constantBound)
- {
- // The landing pad value became a constant value as part of a hoisting operation. The landing pad constant value is
- // a more aggressive bound, so use that instead, and take into consideration the change to the sym so far inside the
- // loop, using the relative bound to the landing pad value.
- if (!boundSet.TryGetReference(landingPadValue->GetValueNumber(), &bound))
- {
- return SymBoundType::UNKNOWN;
- }
- constantBound = landingPadConstantValue + bound->Offset();
- }
- *boundOffsetOrValueRef = constantBound;
- return SymBoundType::VALUE;
- }
- if (!boundSet.TryGetReference(landingPadValue->GetValueNumber(), &bound))
- {
- return SymBoundType::UNKNOWN;
- }
- *boundOffsetOrValueRef = bound->Offset();
- return SymBoundType::OFFSET;
- }
- AssertVerify(
- landingPadValueIsLowerBound
- ? valueInfo->TryGetIntConstantLowerBound(boundOffsetOrValueRef)
- : valueInfo->TryGetIntConstantUpperBound(boundOffsetOrValueRef));
- return SymBoundType::VALUE;
- }
- void GlobOpt::DetermineDominatingLoopCountableBlock(Loop *const loop, BasicBlock *const headerBlock)
- {
- Assert(DoLoopCountBasedBoundCheckHoist());
- Assert(!IsLoopPrePass());
- Assert(loop);
- Assert(headerBlock);
- Assert(headerBlock->isLoopHeader);
- Assert(headerBlock->loop == loop);
- // Determine if the loop header has a unique successor that is inside the loop. If so, then all other paths out of the loop
- // header exit the loop, allowing a loop count to be established and used from the unique in-loop successor block.
- Assert(!loop->dominatingLoopCountableBlock);
- FOREACH_SUCCESSOR_BLOCK(successor, headerBlock)
- {
- if(successor->loop != loop)
- {
- Assert(!successor->loop || successor->loop->IsDescendentOrSelf(loop->parent));
- continue;
- }
- if(loop->dominatingLoopCountableBlock)
- {
- // Found a second successor inside the loop
- loop->dominatingLoopCountableBlock = nullptr;
- break;
- }
- loop->dominatingLoopCountableBlock = successor;
- } NEXT_SUCCESSOR_BLOCK;
- }
- void GlobOpt::DetermineLoopCount(Loop *const loop)
- {
- Assert(DoLoopCountBasedBoundCheckHoist());
- Assert(loop);
- GlobOptBlockData &landingPadBlockData = loop->landingPad->globOptData;
- const InductionVariableSet *const inductionVariables = loop->inductionVariables;
- Assert(inductionVariables);
- for(auto inductionVariablesIterator = inductionVariables->GetIterator(); inductionVariablesIterator.IsValid(); inductionVariablesIterator.MoveNext())
- {
- InductionVariable &inductionVariable = inductionVariablesIterator.CurrentValueReference();
- if(!inductionVariable.IsChangeDeterminate())
- {
- continue;
- }
- // Determine the minimum-magnitude change per iteration, and verify that the change is nonzero and finite
- Assert(inductionVariable.IsChangeUnidirectional());
- int minMagnitudeChange = inductionVariable.ChangeBounds().LowerBound();
- if(minMagnitudeChange >= 0)
- {
- if(minMagnitudeChange == 0 || minMagnitudeChange == IntConstMax)
- {
- continue;
- }
- }
- else
- {
- minMagnitudeChange = inductionVariable.ChangeBounds().UpperBound();
- Assert(minMagnitudeChange <= 0);
- if(minMagnitudeChange == 0 || minMagnitudeChange == IntConstMin)
- {
- continue;
- }
- }
- StackSym *const inductionVariableVarSym = inductionVariable.Sym();
- if(!this->currentBlock->globOptData.IsInt32TypeSpecialized(inductionVariableVarSym))
- {
- inductionVariable.SetChangeIsIndeterminate();
- continue;
- }
- Assert(landingPadBlockData.IsInt32TypeSpecialized(inductionVariableVarSym));
- Value *const inductionVariableValue = this->currentBlock->globOptData.FindValue(inductionVariableVarSym);
- if(!inductionVariableValue)
- {
- inductionVariable.SetChangeIsIndeterminate();
- continue;
- }
- ValueInfo *const inductionVariableValueInfo = inductionVariableValue->GetValueInfo();
- const IntBounds *const inductionVariableBounds =
- inductionVariableValueInfo->IsIntBounded() ? inductionVariableValueInfo->AsIntBounded()->Bounds() : nullptr;
- // Look for an invariant bound in the direction of change
- StackSym *boundBaseVarSym = nullptr;
- int boundOffset = 0;
- {
- bool foundBound = false;
- if(inductionVariableBounds)
- {
- // Look for a relative bound
- for(auto it =
- (
- minMagnitudeChange >= 0
- ? inductionVariableBounds->RelativeUpperBounds()
- : inductionVariableBounds->RelativeLowerBounds()
- ).GetIterator();
- it.IsValid();
- it.MoveNext())
- {
- const ValueRelativeOffset &bound = it.CurrentValue();
- StackSym *currentBoundBaseVarSym = bound.BaseSym();
- if(!currentBoundBaseVarSym || !landingPadBlockData.IsInt32TypeSpecialized(currentBoundBaseVarSym))
- {
- continue;
- }
- Value *const boundBaseValue = this->currentBlock->globOptData.FindValue(currentBoundBaseVarSym);
- const ValueNumber boundBaseValueNumber = bound.BaseValueNumber();
- if(!boundBaseValue || boundBaseValue->GetValueNumber() != boundBaseValueNumber)
- {
- continue;
- }
- Value *const landingPadBoundBaseValue = landingPadBlockData.FindValue(currentBoundBaseVarSym);
- if(!landingPadBoundBaseValue || landingPadBoundBaseValue->GetValueNumber() != boundBaseValueNumber)
- {
- continue;
- }
- if (foundBound)
- {
- // We used to pick the first usable bound we saw in this list, but the list contains both
- // the loop counter's bound *and* relative bounds of the primary bound. These secondary bounds
- // are not guaranteed to be correct, so if the bound we found on a previous iteration is itself
- // a bound for the current bound, then choose the current bound.
- if (!boundBaseValue->GetValueInfo()->IsIntBounded())
- {
- continue;
- }
- // currentBoundBaseVarSym has relative bounds of its own. If we find the saved boundBaseVarSym
- // in currentBoundBaseVarSym's relative bounds list, let currentBoundBaseVarSym be the
- // chosen bound.
- const IntBounds *const currentBounds = boundBaseValue->GetValueInfo()->AsIntBounded()->Bounds();
- bool foundSecondaryBound = false;
- for (auto it2 =
- (
- minMagnitudeChange >= 0
- ? currentBounds->RelativeUpperBounds()
- : currentBounds->RelativeLowerBounds()
- ).GetIterator();
- it2.IsValid();
- it2.MoveNext())
- {
- const ValueRelativeOffset &bound2 = it2.CurrentValue();
- if (bound2.BaseSym() == boundBaseVarSym)
- {
- // boundBaseVarSym is a secondary bound. Use currentBoundBaseVarSym instead.
- foundSecondaryBound = true;
- break;
- }
- }
- if (!foundSecondaryBound)
- {
- // boundBaseVarSym is not a relative bound of currentBoundBaseVarSym, so continue
- // to use boundBaseVarSym.
- continue;
- }
- }
- boundBaseVarSym = bound.BaseSym();
- boundOffset = bound.Offset();
- foundBound = true;
- }
- }
- if(!foundBound)
- {
- // No useful relative bound found; look for a constant bound. Exclude large constant bounds established implicitly by
- // <, <=, >, and >=. For example, for a loop condition (i < n), if 'n' is not invariant and hence can't be used,
- // 'i' will still have a constant upper bound of (int32 max - 1) that should be excluded as it's too large. Any
- // other constant bounds must have been established explicitly by the loop condition, and are safe to use.
- boundBaseVarSym = nullptr;
- if(minMagnitudeChange >= 0)
- {
- if(inductionVariableBounds)
- {
- boundOffset = inductionVariableBounds->ConstantUpperBound();
- }
- else
- {
- AssertVerify(inductionVariableValueInfo->TryGetIntConstantUpperBound(&boundOffset));
- }
- if(boundOffset >= IntConstMax - 1)
- {
- continue;
- }
- }
- else
- {
- if(inductionVariableBounds)
- {
- boundOffset = inductionVariableBounds->ConstantLowerBound();
- }
- else
- {
- AssertVerify(inductionVariableValueInfo->TryGetIntConstantLowerBound(&boundOffset));
- }
- if(boundOffset <= IntConstMin + 1)
- {
- continue;
- }
- }
- }
- }
- // Determine if the induction variable already changed in the loop, and by how much
- int inductionVariableOffset = 0;
- StackSym *inductionVariableSymToAdd = nullptr;
- SymBoundType symBoundType = DetermineSymBoundOffsetOrValueRelativeToLandingPad(
- inductionVariableVarSym,
- minMagnitudeChange >= 0,
- inductionVariableValueInfo,
- inductionVariableBounds,
- &landingPadBlockData,
- &inductionVariableOffset);
- if (symBoundType == SymBoundType::VALUE)
- {
- // The bound value is constant
- inductionVariableSymToAdd = nullptr;
- }
- else if (symBoundType == SymBoundType::OFFSET)
- {
- // The bound value is not constant, the offset needs to be added to the induction variable in the landing pad
- inductionVariableSymToAdd = inductionVariableVarSym->GetInt32EquivSym(nullptr);
- Assert(inductionVariableSymToAdd);
- }
- else
- {
- Assert(symBoundType == SymBoundType::UNKNOWN);
- // We were unable to determine the sym bound offset or value
- continue;
- }
- // Int operands are required
- StackSym *boundBaseSym;
- if(boundBaseVarSym)
- {
- boundBaseSym = boundBaseVarSym->IsVar() ? boundBaseVarSym->GetInt32EquivSym(nullptr) : boundBaseVarSym;
- Assert(boundBaseSym);
- Assert(boundBaseSym->GetType() == TyInt32 || boundBaseSym->GetType() == TyUint32);
- }
- else
- {
- boundBaseSym = nullptr;
- }
- // The loop count is computed as follows. We're actually computing the loop count minus one, because the value is used
- // to determine the bound of a secondary induction variable in its direction of change, and at that point the secondary
- // induction variable's information already accounts for changes in the first loop iteration.
- //
- // If the induction variable increases in the loop:
- // loopCountMinusOne = (upperBound - inductionVariable) / abs(minMagnitudeChange)
- // Or more precisely:
- // loopCountMinusOne =
- // ((boundBase - inductionVariable) + (boundOffset - inductionVariableOffset)) / abs(minMagnitudeChange)
- //
- // If the induction variable decreases in the loop, the subtract operands are just reversed to yield a nonnegative
- // number, and the rest is similar. The two offsets are also constant and can be folded. So in general:
- // loopCountMinusOne = (left - right + offset) / abs(minMagnitudeChange)
- // Determine the left and right information
- StackSym *leftSym, *rightSym;
- int leftOffset, rightOffset;
- if(minMagnitudeChange >= 0)
- {
- leftSym = boundBaseSym;
- leftOffset = boundOffset;
- rightSym = inductionVariableSymToAdd;
- rightOffset = inductionVariableOffset;
- }
- else
- {
- minMagnitudeChange = -minMagnitudeChange;
- leftSym = inductionVariableSymToAdd;
- leftOffset = inductionVariableOffset;
- rightSym = boundBaseSym;
- rightOffset = boundOffset;
- }
- // Determine the combined offset, and save the info necessary to generate the loop count
- int offset;
- if(Int32Math::Sub(leftOffset, rightOffset, &offset))
- {
- continue;
- }
- void *const loopCountBuffer = JitAnewArray(this->func->GetTopFunc()->m_fg->alloc, byte, sizeof(LoopCount));
- if(!rightSym)
- {
- if(!leftSym)
- {
- loop->loopCount = new(loopCountBuffer) LoopCount(offset / minMagnitudeChange);
- break;
- }
- if(offset == 0 && minMagnitudeChange == 1)
- {
- loop->loopCount = new(loopCountBuffer) LoopCount(leftSym);
- break;
- }
- }
- loop->loopCount = new(loopCountBuffer) LoopCount(leftSym, rightSym, offset, minMagnitudeChange);
- break;
- }
- }
- void GlobOpt::GenerateLoopCount(Loop *const loop, LoopCount *const loopCount)
- {
- Assert(DoLoopCountBasedBoundCheckHoist());
- Assert(loop);
- Assert(loopCount);
- Assert(loopCount == loop->loopCount);
- Assert(!loopCount->HasBeenGenerated());
- // loopCountMinusOne = (left - right + offset) / minMagnitudeChange
- // Prepare the landing pad for bailouts and instruction insertion
- BailOutInfo *const bailOutInfo = loop->bailOutInfo;
- Assert(bailOutInfo);
- const IR::BailOutKind bailOutKind = IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck;
- IR::Instr *const insertBeforeInstr = bailOutInfo->bailOutInstr;
- Assert(insertBeforeInstr);
- Func *const func = bailOutInfo->bailOutFunc;
- // intermediateValue = left - right
- IR::IntConstOpnd *offset =
- loopCount->Offset() == 0 ? nullptr : IR::IntConstOpnd::New(loopCount->Offset(), TyInt32, func, true);
- StackSym *const rightSym = loopCount->RightSym();
- StackSym *intermediateValueSym;
- if(rightSym)
- {
- IR::BailOutInstr *const instr = IR::BailOutInstr::New(Js::OpCode::Sub_I4, bailOutKind, bailOutInfo, func);
- instr->SetSrc2(IR::RegOpnd::New(rightSym, rightSym->GetType(), func));
- instr->GetSrc2()->SetIsJITOptimizedReg(true);
- StackSym *const leftSym = loopCount->LeftSym();
- if(leftSym)
- {
- // intermediateValue = left - right
- instr->SetSrc1(IR::RegOpnd::New(leftSym, leftSym->GetType(), func));
- instr->GetSrc1()->SetIsJITOptimizedReg(true);
- }
- else if(offset)
- {
- // intermediateValue = offset - right
- instr->SetSrc1(offset);
- offset = nullptr;
- }
- else
- {
- // intermediateValue = -right
- instr->m_opcode = Js::OpCode::Neg_I4;
- instr->SetSrc1(instr->UnlinkSrc2());
- }
- intermediateValueSym = StackSym::New(TyInt32, func);
- instr->SetDst(IR::RegOpnd::New(intermediateValueSym, intermediateValueSym->GetType(), func));
- instr->GetDst()->SetIsJITOptimizedReg(true);
- instr->SetByteCodeOffset(insertBeforeInstr);
- insertBeforeInstr->InsertBefore(instr);
- }
- else
- {
- // intermediateValue = left
- Assert(loopCount->LeftSym());
- intermediateValueSym = loopCount->LeftSym();
- }
- // intermediateValue += offset
- if(offset)
- {
- IR::BailOutInstr *const instr = IR::BailOutInstr::New(Js::OpCode::Add_I4, bailOutKind, bailOutInfo, func);
- instr->SetSrc1(IR::RegOpnd::New(intermediateValueSym, intermediateValueSym->GetType(), func));
- instr->GetSrc1()->SetIsJITOptimizedReg(true);
- if(offset->GetValue() < 0 && offset->GetValue() != IntConstMin)
- {
- instr->m_opcode = Js::OpCode::Sub_I4;
- offset->SetValue(-offset->GetValue());
- }
- instr->SetSrc2(offset);
- if(intermediateValueSym == loopCount->LeftSym())
- {
- intermediateValueSym = StackSym::New(TyInt32, func);
- }
- instr->SetDst(IR::RegOpnd::New(intermediateValueSym, intermediateValueSym->GetType(), func));
- instr->GetDst()->SetIsJITOptimizedReg(true);
- instr->SetByteCodeOffset(insertBeforeInstr);
- insertBeforeInstr->InsertBefore(instr);
- }
- // intermediateValue /= minMagnitudeChange
- const int minMagnitudeChange = loopCount->MinMagnitudeChange();
- if(minMagnitudeChange != 1)
- {
- IR::Instr *const instr = IR::Instr::New(Js::OpCode::Div_I4, func);
- instr->SetSrc1(IR::RegOpnd::New(intermediateValueSym, intermediateValueSym->GetType(), func));
- instr->GetSrc1()->SetIsJITOptimizedReg(true);
- Assert(minMagnitudeChange != 0); // bailout is not needed
- instr->SetSrc2(IR::IntConstOpnd::New(minMagnitudeChange, TyInt32, func, true));
- if(intermediateValueSym == loopCount->LeftSym())
- {
- intermediateValueSym = StackSym::New(TyInt32, func);
- }
- instr->SetDst(IR::RegOpnd::New(intermediateValueSym, intermediateValueSym->GetType(), func));
- instr->GetDst()->SetIsJITOptimizedReg(true);
- instr->SetByteCodeOffset(insertBeforeInstr);
- insertBeforeInstr->InsertBefore(instr);
- }
- else
- {
- Assert(intermediateValueSym != loopCount->LeftSym());
- }
- // loopCountMinusOne = intermediateValue
- loopCount->SetLoopCountMinusOneSym(intermediateValueSym);
- }
- void GlobOpt::GenerateLoopCountPlusOne(Loop *const loop, LoopCount *const loopCount)
- {
- Assert(loop);
- Assert(loopCount);
- Assert(loopCount == loop->loopCount);
- if (loopCount->HasGeneratedLoopCountSym())
- {
- return;
- }
- if (!loopCount->HasBeenGenerated())
- {
- GenerateLoopCount(loop, loopCount);
- }
- Assert(loopCount->HasBeenGenerated());
- // If this is null then the loop count is a constant and there is nothing more to do here
- if (loopCount->LoopCountMinusOneSym())
- {
- // Prepare the landing pad for bailouts and instruction insertion
- BailOutInfo *const bailOutInfo = loop->bailOutInfo;
- Assert(bailOutInfo);
- IR::Instr *const insertBeforeInstr = bailOutInfo->bailOutInstr;
- Assert(insertBeforeInstr);
- Func *const func = bailOutInfo->bailOutFunc;
- IRType type = loopCount->LoopCountMinusOneSym()->GetType();
- // loop count is off by one, so add one
- IR::RegOpnd *loopCountOpnd = IR::RegOpnd::New(type, func);
- IR::RegOpnd *minusOneOpnd = IR::RegOpnd::New(loopCount->LoopCountMinusOneSym(), type, func);
- minusOneOpnd->SetIsJITOptimizedReg(true);
- insertBeforeInstr->InsertBefore(IR::Instr::New(Js::OpCode::Add_I4,
- loopCountOpnd,
- minusOneOpnd,
- IR::IntConstOpnd::New(1, type, func, true),
- func));
- loopCount->SetLoopCountSym(loopCountOpnd->GetStackSym());
- }
- }
- void GlobOpt::GenerateSecondaryInductionVariableBound(
- Loop *const loop,
- StackSym *const inductionVariableSym,
- const LoopCount *const loopCount,
- const int maxMagnitudeChange,
- StackSym *const boundSym)
- {
- Assert(loop);
- Assert(inductionVariableSym);
- Assert(inductionVariableSym->GetType() == TyInt32 || inductionVariableSym->GetType() == TyUint32);
- Assert(loopCount);
- Assert(loopCount == loop->loopCount);
- Assert(loopCount->LoopCountMinusOneSym());
- Assert(maxMagnitudeChange != 0);
- Assert(maxMagnitudeChange >= -InductionVariable::ChangeMagnitudeLimitForLoopCountBasedHoisting);
- Assert(maxMagnitudeChange <= InductionVariable::ChangeMagnitudeLimitForLoopCountBasedHoisting);
- Assert(boundSym);
- Assert(boundSym->IsInt32());
- // bound = inductionVariable + loopCountMinusOne * maxMagnitudeChange
- // Prepare the landing pad for bailouts and instruction insertion
- BailOutInfo *const bailOutInfo = loop->bailOutInfo;
- Assert(bailOutInfo);
- const IR::BailOutKind bailOutKind = IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck;
- IR::Instr *const insertBeforeInstr = bailOutInfo->bailOutInstr;
- Assert(insertBeforeInstr);
- Func *const func = bailOutInfo->bailOutFunc;
- // intermediateValue = loopCount * maxMagnitudeChange
- StackSym *intermediateValueSym;
- if(maxMagnitudeChange == 1 || maxMagnitudeChange == -1)
- {
- intermediateValueSym = loopCount->LoopCountMinusOneSym();
- }
- else
- {
- IR::BailOutInstr *const instr = IR::BailOutInstr::New(Js::OpCode::Mul_I4, bailOutKind, bailOutInfo, func);
- instr->SetSrc1(
- IR::RegOpnd::New(loopCount->LoopCountMinusOneSym(), loopCount->LoopCountMinusOneSym()->GetType(), func));
- instr->GetSrc1()->SetIsJITOptimizedReg(true);
- instr->SetSrc2(IR::IntConstOpnd::New(maxMagnitudeChange, TyInt32, func, true));
- intermediateValueSym = boundSym;
- instr->SetDst(IR::RegOpnd::New(intermediateValueSym, intermediateValueSym->GetType(), func));
- instr->GetDst()->SetIsJITOptimizedReg(true);
- instr->SetByteCodeOffset(insertBeforeInstr);
- insertBeforeInstr->InsertBefore(instr);
- }
- // bound = intermediateValue + inductionVariable
- {
- IR::BailOutInstr *const instr = IR::BailOutInstr::New(Js::OpCode::Add_I4, bailOutKind, bailOutInfo, func);
- instr->SetSrc1(IR::RegOpnd::New(intermediateValueSym, intermediateValueSym->GetType(), func));
- instr->GetSrc1()->SetIsJITOptimizedReg(true);
- instr->SetSrc2(IR::RegOpnd::New(inductionVariableSym, inductionVariableSym->GetType(), func));
- instr->GetSrc2()->SetIsJITOptimizedReg(true);
- if(maxMagnitudeChange == -1)
- {
- // bound = inductionVariable - intermediateValue[loopCount]
- instr->m_opcode = Js::OpCode::Sub_I4;
- instr->SwapOpnds();
- }
- instr->SetDst(IR::RegOpnd::New(boundSym, boundSym->GetType(), func));
- instr->GetDst()->SetIsJITOptimizedReg(true);
- instr->SetByteCodeOffset(insertBeforeInstr);
- insertBeforeInstr->InsertBefore(instr);
- }
- }
- void GlobOpt::DetermineArrayBoundCheckHoistability(
- bool needLowerBoundCheck,
- bool needUpperBoundCheck,
- ArrayLowerBoundCheckHoistInfo &lowerHoistInfo,
- ArrayUpperBoundCheckHoistInfo &upperHoistInfo,
- const bool isJsArray,
- StackSym *const indexSym,
- Value *const indexValue,
- const IntConstantBounds &indexConstantBounds,
- StackSym *const headSegmentLengthSym,
- Value *const headSegmentLengthValue,
- const IntConstantBounds &headSegmentLengthConstantBounds,
- Loop *const headSegmentLengthInvariantLoop,
- bool &failedToUpdateCompatibleLowerBoundCheck,
- bool &failedToUpdateCompatibleUpperBoundCheck)
- {
- Assert(DoBoundCheckHoist());
- Assert(needLowerBoundCheck || needUpperBoundCheck);
- Assert(!lowerHoistInfo.HasAnyInfo());
- Assert(!upperHoistInfo.HasAnyInfo());
- Assert(!indexSym == !indexValue);
- Assert(!needUpperBoundCheck || headSegmentLengthSym);
- Assert(!headSegmentLengthSym == !headSegmentLengthValue);
- Assert(!failedToUpdateCompatibleLowerBoundCheck);
- Assert(!failedToUpdateCompatibleUpperBoundCheck);
- Loop *const currentLoop = currentBlock->loop;
- if(!indexValue)
- {
- Assert(!needLowerBoundCheck);
- Assert(needUpperBoundCheck);
- Assert(indexConstantBounds.IsConstant());
- // The index is a constant value, so a bound check on it can be hoisted as far as desired. Just find a compatible bound
- // check that is already available, or the loop in which the head segment length is invariant.
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 2,
- _u("Index is constant, looking for a compatible upper bound check\n"));
- const int indexConstantValue = indexConstantBounds.LowerBound();
- Assert(indexConstantValue != IntConstMax);
- const IntBoundCheck *compatibleBoundCheck;
- if(currentBlock->globOptData.availableIntBoundChecks->TryGetReference(
- IntBoundCheckCompatibilityId(ZeroValueNumber, headSegmentLengthValue->GetValueNumber()),
- &compatibleBoundCheck))
- {
- // We need:
- // index < headSegmentLength
- // Normalize the offset such that:
- // 0 <= headSegmentLength + compatibleBoundCheckOffset
- // Where (compatibleBoundCheckOffset = -1 - index), and -1 is to simulate < instead of <=.
- const int compatibleBoundCheckOffset = -1 - indexConstantValue;
- if(compatibleBoundCheck->SetBoundOffset(compatibleBoundCheckOffset))
- {
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 3,
- _u("Found in block %u\n"),
- compatibleBoundCheck->Block()->GetBlockNum());
- upperHoistInfo.SetCompatibleBoundCheck(compatibleBoundCheck->Block(), indexConstantValue);
- return;
- }
- failedToUpdateCompatibleUpperBoundCheck = true;
- }
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Not found\n"));
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 2, _u("Looking for invariant head segment length\n"));
- Loop *invariantLoop;
- Value *landingPadHeadSegmentLengthValue = nullptr;
- if(headSegmentLengthInvariantLoop)
- {
- invariantLoop = headSegmentLengthInvariantLoop;
- landingPadHeadSegmentLengthValue =
- invariantLoop->landingPad->globOptData.FindValue(headSegmentLengthSym);
- }
- else if(currentLoop)
- {
- invariantLoop = nullptr;
- for(Loop *loop = currentLoop; loop; loop = loop->parent)
- {
- GlobOptBlockData &landingPadBlockData = loop->landingPad->globOptData;
- Value *const value = landingPadBlockData.FindValue(headSegmentLengthSym);
- if(!value)
- {
- break;
- }
- invariantLoop = loop;
- landingPadHeadSegmentLengthValue = value;
- }
- if(!invariantLoop)
- {
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Not found\n"));
- return;
- }
- }
- else
- {
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Not found, block is not in a loop\n"));
- return;
- }
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 3,
- _u("Found in loop %u landing pad block %u\n"),
- invariantLoop->GetLoopNumber(),
- invariantLoop->landingPad->GetBlockNum());
- IntConstantBounds landingPadHeadSegmentLengthConstantBounds;
- AssertVerify(
- landingPadHeadSegmentLengthValue
- ->GetValueInfo()
- ->TryGetIntConstantBounds(&landingPadHeadSegmentLengthConstantBounds));
- if(isJsArray)
- {
- // index >= headSegmentLength is currently not possible for JS arrays (except when index == int32 max, which is
- // covered above).
- Assert(
- !ValueInfo::IsGreaterThanOrEqualTo(
- nullptr,
- indexConstantValue,
- indexConstantValue,
- landingPadHeadSegmentLengthValue,
- landingPadHeadSegmentLengthConstantBounds.LowerBound(),
- landingPadHeadSegmentLengthConstantBounds.UpperBound()));
- }
- else if(
- ValueInfo::IsGreaterThanOrEqualTo(
- nullptr,
- indexConstantValue,
- indexConstantValue,
- landingPadHeadSegmentLengthValue,
- landingPadHeadSegmentLengthConstantBounds.LowerBound(),
- landingPadHeadSegmentLengthConstantBounds.UpperBound()))
- {
- // index >= headSegmentLength in the landing pad, can't use the index sym. This is possible for typed arrays through
- // conditions on array.length in user code.
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 2, _u("Index >= head segment length\n"));
- return;
- }
- upperHoistInfo.SetLoop(
- invariantLoop,
- indexConstantValue,
- landingPadHeadSegmentLengthValue,
- landingPadHeadSegmentLengthConstantBounds);
- return;
- }
- Assert(!indexConstantBounds.IsConstant());
- ValueInfo *const indexValueInfo = indexValue->GetValueInfo();
- const IntBounds *const indexBounds = indexValueInfo->IsIntBounded() ? indexValueInfo->AsIntBounded()->Bounds() : nullptr;
- {
- // See if a compatible bound check is already available
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 2,
- _u("Looking for compatible bound checks for index bounds\n"));
- bool searchingLower = needLowerBoundCheck;
- bool searchingUpper = needUpperBoundCheck;
- Assert(searchingLower || searchingUpper);
- bool foundLowerBoundCheck = false;
- const IntBoundCheck *lowerBoundCheck = nullptr;
- ValueNumber lowerHoistBlockIndexValueNumber = InvalidValueNumber;
- int lowerBoundOffset = 0;
- if(searchingLower &&
- currentBlock->globOptData.availableIntBoundChecks->TryGetReference(
- IntBoundCheckCompatibilityId(ZeroValueNumber, indexValue->GetValueNumber()),
- &lowerBoundCheck))
- {
- if(lowerBoundCheck->SetBoundOffset(0))
- {
- foundLowerBoundCheck = true;
- lowerHoistBlockIndexValueNumber = indexValue->GetValueNumber();
- lowerBoundOffset = 0;
- searchingLower = false;
- }
- else
- {
- failedToUpdateCompatibleLowerBoundCheck = true;
- }
- }
- bool foundUpperBoundCheck = false;
- const IntBoundCheck *upperBoundCheck = nullptr;
- ValueNumber upperHoistBlockIndexValueNumber = InvalidValueNumber;
- int upperBoundOffset = 0;
- if(searchingUpper &&
- currentBlock->globOptData.availableIntBoundChecks->TryGetReference(
- IntBoundCheckCompatibilityId(indexValue->GetValueNumber(), headSegmentLengthValue->GetValueNumber()),
- &upperBoundCheck))
- {
- if(upperBoundCheck->SetBoundOffset(-1)) // -1 is to simulate < instead of <=
- {
- foundUpperBoundCheck = true;
- upperHoistBlockIndexValueNumber = indexValue->GetValueNumber();
- upperBoundOffset = 0;
- searchingUpper = false;
- }
- else
- {
- failedToUpdateCompatibleUpperBoundCheck = true;
- }
- }
- if(indexBounds)
- {
- searchingLower = searchingLower && indexBounds->RelativeLowerBounds().Count() != 0;
- searchingUpper = searchingUpper && indexBounds->RelativeUpperBounds().Count() != 0;
- if(searchingLower || searchingUpper)
- {
- for(auto it = currentBlock->globOptData.availableIntBoundChecks->GetIterator(); it.IsValid(); it.MoveNext())
- {
- const IntBoundCheck &boundCheck = it.CurrentValue();
- if(searchingLower && boundCheck.LeftValueNumber() == ZeroValueNumber)
- {
- lowerHoistBlockIndexValueNumber = boundCheck.RightValueNumber();
- const ValueRelativeOffset *bound;
- if(indexBounds->RelativeLowerBounds().TryGetReference(lowerHoistBlockIndexValueNumber, &bound))
- {
- // We need:
- // 0 <= boundBase + boundOffset
- const int offset = bound->Offset();
- if(boundCheck.SetBoundOffset(offset))
- {
- foundLowerBoundCheck = true;
- lowerBoundCheck = &boundCheck;
- lowerBoundOffset = offset;
- searchingLower = false;
- if(!searchingUpper)
- {
- break;
- }
- }
- else
- {
- failedToUpdateCompatibleLowerBoundCheck = true;
- }
- }
- }
- if(searchingUpper && boundCheck.RightValueNumber() == headSegmentLengthValue->GetValueNumber())
- {
- upperHoistBlockIndexValueNumber = boundCheck.LeftValueNumber();
- const ValueRelativeOffset *bound;
- if(indexBounds->RelativeUpperBounds().TryGetReference(upperHoistBlockIndexValueNumber, &bound))
- {
- // We need:
- // boundBase + boundOffset < headSegmentLength
- // Normalize the offset such that:
- // boundBase <= headSegmentLength + compatibleBoundCheckOffset
- // Where (compatibleBoundCheckOffset = -1 - boundOffset), and -1 is to simulate < instead of <=.
- const int offset = -1 - bound->Offset();
- if(boundCheck.SetBoundOffset(offset))
- {
- foundUpperBoundCheck = true;
- upperBoundCheck = &boundCheck;
- upperBoundOffset = bound->Offset();
- searchingUpper = false;
- if(!searchingLower)
- {
- break;
- }
- }
- else
- {
- failedToUpdateCompatibleUpperBoundCheck = true;
- }
- }
- }
- }
- }
- }
- if(foundLowerBoundCheck)
- {
- // A bound check takes the form src1 <= src2 + dst
- Assert(lowerBoundCheck->Instr()->GetSrc2());
- Assert(
- lowerBoundCheck->Instr()->GetSrc2()->AsRegOpnd()->m_sym->GetType() == TyInt32 ||
- lowerBoundCheck->Instr()->GetSrc2()->AsRegOpnd()->m_sym->GetType() == TyUint32);
- StackSym *boundCheckIndexSym = lowerBoundCheck->Instr()->GetSrc2()->AsRegOpnd()->m_sym;
- if(boundCheckIndexSym->IsTypeSpec())
- {
- boundCheckIndexSym = boundCheckIndexSym->GetVarEquivSym(nullptr);
- Assert(boundCheckIndexSym);
- }
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 3,
- _u("Found lower bound (s%u + %d) in block %u\n"),
- boundCheckIndexSym->m_id,
- lowerBoundOffset,
- lowerBoundCheck->Block()->GetBlockNum());
- lowerHoistInfo.SetCompatibleBoundCheck(
- lowerBoundCheck->Block(),
- boundCheckIndexSym,
- lowerBoundOffset,
- lowerHoistBlockIndexValueNumber);
- Assert(!searchingLower);
- needLowerBoundCheck = false;
- if(!needUpperBoundCheck)
- {
- return;
- }
- }
- if(foundUpperBoundCheck)
- {
- // A bound check takes the form src1 <= src2 + dst
- Assert(upperBoundCheck->Instr()->GetSrc1());
- Assert(
- upperBoundCheck->Instr()->GetSrc1()->AsRegOpnd()->m_sym->GetType() == TyInt32 ||
- upperBoundCheck->Instr()->GetSrc1()->AsRegOpnd()->m_sym->GetType() == TyUint32);
- StackSym *boundCheckIndexSym = upperBoundCheck->Instr()->GetSrc1()->AsRegOpnd()->m_sym;
- if(boundCheckIndexSym->IsTypeSpec())
- {
- boundCheckIndexSym = boundCheckIndexSym->GetVarEquivSym(nullptr);
- Assert(boundCheckIndexSym);
- }
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 3,
- _u("Found upper bound (s%u + %d) in block %u\n"),
- boundCheckIndexSym->m_id,
- upperBoundOffset,
- upperBoundCheck->Block()->GetBlockNum());
- upperHoistInfo.SetCompatibleBoundCheck(
- upperBoundCheck->Block(),
- boundCheckIndexSym,
- -1 - upperBoundOffset,
- upperHoistBlockIndexValueNumber);
- Assert(!searchingUpper);
- needUpperBoundCheck = false;
- if(!needLowerBoundCheck)
- {
- return;
- }
- }
- Assert(needLowerBoundCheck || needUpperBoundCheck);
- Assert(!needLowerBoundCheck || !lowerHoistInfo.CompatibleBoundCheckBlock());
- Assert(!needUpperBoundCheck || !upperHoistInfo.CompatibleBoundCheckBlock());
- }
- if(!currentLoop)
- {
- return;
- }
- // 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
- // index value in the current block
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 2, _u("Looking for invariant index or index bounded by itself\n"));
- bool searchingLower = needLowerBoundCheck, searchingUpper = needUpperBoundCheck;
- for(Loop *loop = currentLoop; loop; loop = loop->parent)
- {
- GlobOptBlockData &landingPadBlockData = loop->landingPad->globOptData;
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 3,
- _u("Trying loop %u landing pad block %u\n"),
- loop->GetLoopNumber(),
- loop->landingPad->GetBlockNum());
- Value *const landingPadIndexValue = landingPadBlockData.FindValue(indexSym);
- if(!landingPadIndexValue)
- {
- break;
- }
- IntConstantBounds landingPadIndexConstantBounds;
- const bool landingPadIndexValueIsLikelyInt =
- landingPadIndexValue->GetValueInfo()->TryGetIntConstantBounds(&landingPadIndexConstantBounds, true);
- int lowerOffset = 0, upperOffset = 0;
- if(indexValue->GetValueNumber() == landingPadIndexValue->GetValueNumber())
- {
- Assert(landingPadIndexValueIsLikelyInt);
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Index is invariant\n"));
- }
- else
- {
- if(!landingPadIndexValueIsLikelyInt)
- {
- break;
- }
- if(searchingLower)
- {
- if(lowerHoistInfo.Loop() && indexValue->GetValueNumber() == lowerHoistInfo.IndexValueNumber())
- {
- // Prefer using the invariant sym
- needLowerBoundCheck = searchingLower = false;
- if(!needUpperBoundCheck)
- {
- return;
- }
- if(!searchingUpper)
- {
- break;
- }
- }
- else
- {
- bool foundBound = false;
- if(indexBounds)
- {
- const ValueRelativeOffset *bound;
- if(indexBounds->RelativeLowerBounds().TryGetReference(landingPadIndexValue->GetValueNumber(), &bound))
- {
- foundBound = true;
- lowerOffset = bound->Offset();
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 4,
- _u("Found lower bound (index + %d)\n"),
- lowerOffset);
- }
- }
- if(!foundBound)
- {
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Lower bound was not found\n"));
- searchingLower = false;
- if(!searchingUpper)
- {
- break;
- }
- }
- }
- }
- if(searchingUpper)
- {
- if(upperHoistInfo.Loop() && indexValue->GetValueNumber() == upperHoistInfo.IndexValueNumber())
- {
- // Prefer using the invariant sym
- needUpperBoundCheck = searchingUpper = false;
- if(!needLowerBoundCheck)
- {
- return;
- }
- if(!searchingLower)
- {
- break;
- }
- }
- else
- {
- bool foundBound = false;
- if(indexBounds)
- {
- const ValueRelativeOffset *bound;
- if(indexBounds->RelativeUpperBounds().TryGetReference(landingPadIndexValue->GetValueNumber(), &bound))
- {
- foundBound = true;
- upperOffset = bound->Offset();
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 4,
- _u("Found upper bound (index + %d)\n"),
- upperOffset);
- }
- }
- if(!foundBound)
- {
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Upper bound was not found\n"));
- searchingUpper = false;
- if(!searchingLower)
- {
- break;
- }
- }
- }
- }
- }
- if(searchingLower)
- {
- if(ValueInfo::IsLessThan(
- landingPadIndexValue,
- landingPadIndexConstantBounds.LowerBound(),
- landingPadIndexConstantBounds.UpperBound(),
- nullptr,
- 0,
- 0))
- {
- // index < 0 in the landing pad; can't use the index sym
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, _u("Index < 0\n"));
- searchingLower = false;
- if(!searchingUpper)
- {
- break;
- }
- }
- else
- {
- lowerHoistInfo.SetLoop(
- loop,
- indexSym,
- lowerOffset,
- landingPadIndexValue,
- landingPadIndexConstantBounds);
- }
- }
- if(!searchingUpper)
- {
- continue;
- }
- // Check if the head segment length sym is available in the landing pad
- Value *const landingPadHeadSegmentLengthValue = landingPadBlockData.FindValue(headSegmentLengthSym);
- if(!landingPadHeadSegmentLengthValue)
- {
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, _u("Head segment length is not invariant\n"));
- searchingUpper = false;
- if(!searchingLower)
- {
- break;
- }
- continue;
- }
- IntConstantBounds landingPadHeadSegmentLengthConstantBounds;
- AssertVerify(
- landingPadHeadSegmentLengthValue
- ->GetValueInfo()
- ->TryGetIntConstantBounds(&landingPadHeadSegmentLengthConstantBounds));
- if(ValueInfo::IsGreaterThanOrEqualTo(
- landingPadIndexValue,
- landingPadIndexConstantBounds.LowerBound(),
- landingPadIndexConstantBounds.UpperBound(),
- landingPadHeadSegmentLengthValue,
- landingPadHeadSegmentLengthConstantBounds.LowerBound(),
- landingPadHeadSegmentLengthConstantBounds.UpperBound()))
- {
- // index >= headSegmentLength in the landing pad; can't use the index sym
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, _u("Index >= head segment length\n"));
- searchingUpper = false;
- if(!searchingLower)
- {
- break;
- }
- continue;
- }
- // We need:
- // boundBase + boundOffset < headSegmentLength
- // Normalize the offset such that:
- // boundBase <= headSegmentLength + offset
- // Where (offset = -1 - boundOffset), and -1 is to simulate < instead of <=.
- upperOffset = -1 - upperOffset;
- upperHoistInfo.SetLoop(
- loop,
- indexSym,
- upperOffset,
- landingPadIndexValue,
- landingPadIndexConstantBounds,
- landingPadHeadSegmentLengthValue,
- landingPadHeadSegmentLengthConstantBounds);
- }
- if(needLowerBoundCheck && lowerHoistInfo.Loop())
- {
- needLowerBoundCheck = false;
- if(!needUpperBoundCheck)
- {
- return;
- }
- }
- if(needUpperBoundCheck && upperHoistInfo.Loop())
- {
- needUpperBoundCheck = false;
- if(!needLowerBoundCheck)
- {
- return;
- }
- }
- // Find an invariant lower/upper bound of the index that can be used for hoisting the bound checks
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 2, _u("Looking for invariant index bounds\n"));
- searchingLower = needLowerBoundCheck;
- searchingUpper = needUpperBoundCheck;
- for(Loop *loop = currentLoop; loop; loop = loop->parent)
- {
- GlobOptBlockData &landingPadBlockData = loop->landingPad->globOptData;
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 3,
- _u("Trying loop %u landing pad block %u\n"),
- loop->GetLoopNumber(),
- loop->landingPad->GetBlockNum());
- Value *landingPadHeadSegmentLengthValue = nullptr;
- IntConstantBounds landingPadHeadSegmentLengthConstantBounds;
- if(searchingUpper)
- {
- // Check if the head segment length sym is available in the landing pad
- landingPadHeadSegmentLengthValue = landingPadBlockData.FindValue(headSegmentLengthSym);
- if(landingPadHeadSegmentLengthValue)
- {
- AssertVerify(
- landingPadHeadSegmentLengthValue
- ->GetValueInfo()
- ->TryGetIntConstantBounds(&landingPadHeadSegmentLengthConstantBounds));
- }
- else
- {
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Head segment length is not invariant\n"));
- searchingUpper = false;
- if(!searchingLower)
- {
- break;
- }
- }
- }
- // Look for a relative bound
- if(indexBounds)
- {
- for(int j = 0; j < 2; ++j)
- {
- const bool searchingRelativeLowerBounds = j == 0;
- if(!(searchingRelativeLowerBounds ? searchingLower : searchingUpper))
- {
- continue;
- }
- for(auto it =
- (
- searchingRelativeLowerBounds
- ? indexBounds->RelativeLowerBounds()
- : indexBounds->RelativeUpperBounds()
- ).GetIterator();
- it.IsValid();
- it.MoveNext())
- {
- const ValueRelativeOffset &indexBound = it.CurrentValue();
- StackSym *const indexBoundBaseSym = indexBound.BaseSym();
- if(!indexBoundBaseSym)
- {
- continue;
- }
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 4,
- _u("Found %S bound (s%u + %d)\n"),
- searchingRelativeLowerBounds ? "lower" : "upper",
- indexBoundBaseSym->m_id,
- indexBound.Offset());
- if(!indexBound.WasEstablishedExplicitly())
- {
- // Don't use a bound that was not established explicitly, as it may be too aggressive. For instance, an
- // index sym used in an array will obtain an upper bound of the array's head segment length - 1. That
- // bound is not established explicitly because the bound assertion is not enforced by the source code.
- // Rather, it is assumed and enforced by the JIT using bailout check. Incrementing the index and using
- // it in a different array may otherwise cause it to use the first array's head segment length as the
- // upper bound on which to do the bound check against the second array, and that bound check would
- // always fail when the arrays are the same size.
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, _u("Bound was established implicitly\n"));
- continue;
- }
- Value *const landingPadIndexBoundBaseValue = landingPadBlockData.FindValue(indexBoundBaseSym);
- if(!landingPadIndexBoundBaseValue ||
- landingPadIndexBoundBaseValue->GetValueNumber() != indexBound.BaseValueNumber())
- {
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, _u("Bound is not invariant\n"));
- continue;
- }
- IntConstantBounds landingPadIndexBoundBaseConstantBounds;
- AssertVerify(
- landingPadIndexBoundBaseValue
- ->GetValueInfo()
- ->TryGetIntConstantBounds(&landingPadIndexBoundBaseConstantBounds, true));
- int offset = indexBound.Offset();
- if(searchingRelativeLowerBounds)
- {
- if(offset == IntConstMin ||
- ValueInfo::IsLessThan(
- landingPadIndexBoundBaseValue,
- landingPadIndexBoundBaseConstantBounds.LowerBound(),
- landingPadIndexBoundBaseConstantBounds.UpperBound(),
- nullptr,
- -offset,
- -offset))
- {
- // indexBoundBase + indexBoundOffset < 0; can't use this bound
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, _u("Bound < 0\n"));
- continue;
- }
- lowerHoistInfo.SetLoop(
- loop,
- indexBoundBaseSym,
- offset,
- landingPadIndexBoundBaseValue,
- landingPadIndexBoundBaseConstantBounds);
- break;
- }
- if(ValueInfo::IsLessThanOrEqualTo(
- landingPadHeadSegmentLengthValue,
- landingPadHeadSegmentLengthConstantBounds.LowerBound(),
- landingPadHeadSegmentLengthConstantBounds.UpperBound(),
- landingPadIndexBoundBaseValue,
- landingPadIndexBoundBaseConstantBounds.LowerBound(),
- landingPadIndexBoundBaseConstantBounds.UpperBound(),
- offset))
- {
- // indexBoundBase + indexBoundOffset >= headSegmentLength; can't use this bound
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, _u("Bound >= head segment length\n"));
- continue;
- }
- // We need:
- // boundBase + boundOffset < headSegmentLength
- // Normalize the offset such that:
- // boundBase <= headSegmentLength + offset
- // Where (offset = -1 - boundOffset), and -1 is to simulate < instead of <=.
- offset = -1 - offset;
- upperHoistInfo.SetLoop(
- loop,
- indexBoundBaseSym,
- offset,
- landingPadIndexBoundBaseValue,
- landingPadIndexBoundBaseConstantBounds,
- landingPadHeadSegmentLengthValue,
- landingPadHeadSegmentLengthConstantBounds);
- break;
- }
- }
- }
- if(searchingLower && lowerHoistInfo.Loop() != loop)
- {
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Lower bound was not found\n"));
- searchingLower = false;
- if(!searchingUpper)
- {
- break;
- }
- }
- if(searchingUpper && upperHoistInfo.Loop() != loop)
- {
- // No useful relative bound found; look for a constant bound if the index is an induction variable. Exclude constant
- // bounds of non-induction variables because those bounds may have been established through means other than a loop
- // exit condition, such as math or bitwise operations. Exclude constant bounds established implicitly by <,
- // <=, >, and >=. For example, for a loop condition (i < n - 1), if 'n' is not invariant and hence can't be used,
- // 'i' will still have a constant upper bound of (int32 max - 2) that should be excluded.
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Relative upper bound was not found\n"));
- const InductionVariable *indexInductionVariable;
- if(!upperHoistInfo.Loop() &&
- currentLoop->inductionVariables &&
- currentLoop->inductionVariables->TryGetReference(indexSym->m_id, &indexInductionVariable) &&
- indexInductionVariable->IsChangeDeterminate())
- {
- if(!(indexBounds && indexBounds->WasConstantUpperBoundEstablishedExplicitly()))
- {
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 4,
- _u("Constant upper bound was established implicitly\n"));
- }
- else
- {
- // See if a compatible bound check is already available
- const int indexConstantBound = indexBounds->ConstantUpperBound();
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 4,
- _u("Found constant upper bound %d, looking for a compatible bound check\n"),
- indexConstantBound);
- const IntBoundCheck *boundCheck;
- if(currentBlock->globOptData.availableIntBoundChecks->TryGetReference(
- IntBoundCheckCompatibilityId(ZeroValueNumber, headSegmentLengthValue->GetValueNumber()),
- &boundCheck))
- {
- // We need:
- // indexConstantBound < headSegmentLength
- // Normalize the offset such that:
- // 0 <= headSegmentLength + compatibleBoundCheckOffset
- // Where (compatibleBoundCheckOffset = -1 - indexConstantBound), and -1 is to simulate < instead of <=.
- const int compatibleBoundCheckOffset = -1 - indexConstantBound;
- if(boundCheck->SetBoundOffset(compatibleBoundCheckOffset))
- {
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 5,
- _u("Found in block %u\n"),
- boundCheck->Block()->GetBlockNum());
- upperHoistInfo.SetCompatibleBoundCheck(boundCheck->Block(), indexConstantBound);
- needUpperBoundCheck = searchingUpper = false;
- if(!needLowerBoundCheck)
- {
- return;
- }
- if(!searchingLower)
- {
- break;
- }
- }
- else
- {
- failedToUpdateCompatibleUpperBoundCheck = true;
- }
- }
- if(searchingUpper)
- {
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 5, _u("Not found\n"));
- upperHoistInfo.SetLoop(
- loop,
- indexConstantBound,
- landingPadHeadSegmentLengthValue,
- landingPadHeadSegmentLengthConstantBounds);
- }
- }
- }
- else if(!upperHoistInfo.Loop())
- {
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 4,
- _u("Index is not an induction variable, not using constant upper bound\n"));
- }
- if(searchingUpper && upperHoistInfo.Loop() != loop)
- {
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Upper bound was not found\n"));
- searchingUpper = false;
- if(!searchingLower)
- {
- break;
- }
- }
- }
- }
- if(needLowerBoundCheck && lowerHoistInfo.Loop())
- {
- needLowerBoundCheck = false;
- if(!needUpperBoundCheck)
- {
- return;
- }
- }
- if(needUpperBoundCheck && upperHoistInfo.Loop())
- {
- needUpperBoundCheck = false;
- if(!needLowerBoundCheck)
- {
- return;
- }
- }
- // Try to use the loop count to calculate a missing lower/upper bound that in turn can be used for hoisting a bound check
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 2,
- _u("Looking for loop count based bound for loop %u landing pad block %u\n"),
- currentLoop->GetLoopNumber(),
- currentLoop->landingPad->GetBlockNum());
- LoopCount *const loopCount = currentLoop->loopCount;
- if(!loopCount)
- {
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Loop was not counted\n"));
- return;
- }
- const InductionVariable *indexInductionVariable;
- if(!currentLoop->inductionVariables ||
- !currentLoop->inductionVariables->TryGetReference(indexSym->m_id, &indexInductionVariable) ||
- !indexInductionVariable->IsChangeDeterminate())
- {
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Index is not an induction variable\n"));
- return;
- }
- // Determine the maximum-magnitude change per iteration, and verify that the change is reasonably finite
- Assert(indexInductionVariable->IsChangeUnidirectional());
- GlobOptBlockData &landingPadBlockData = currentLoop->landingPad->globOptData;
- int maxMagnitudeChange = indexInductionVariable->ChangeBounds().UpperBound();
- Value *landingPadHeadSegmentLengthValue;
- IntConstantBounds landingPadHeadSegmentLengthConstantBounds;
- if(maxMagnitudeChange > 0)
- {
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 3,
- _u("Index's maximum-magnitude change per iteration is %d\n"),
- maxMagnitudeChange);
- if(!needUpperBoundCheck || maxMagnitudeChange > InductionVariable::ChangeMagnitudeLimitForLoopCountBasedHoisting)
- {
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Change magnitude is too large\n"));
- return;
- }
- // Check whether the head segment length is available in the landing pad
- landingPadHeadSegmentLengthValue = landingPadBlockData.FindValue(headSegmentLengthSym);
- Assert(!headSegmentLengthInvariantLoop || landingPadHeadSegmentLengthValue);
- if(!landingPadHeadSegmentLengthValue)
- {
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Head segment length is not invariant\n"));
- return;
- }
- AssertVerify(
- landingPadHeadSegmentLengthValue
- ->GetValueInfo()
- ->TryGetIntConstantBounds(&landingPadHeadSegmentLengthConstantBounds));
- }
- else
- {
- maxMagnitudeChange = indexInductionVariable->ChangeBounds().LowerBound();
- Assert(maxMagnitudeChange < 0);
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 3,
- _u("Index's maximum-magnitude change per iteration is %d\n"),
- maxMagnitudeChange);
- if(!needLowerBoundCheck || maxMagnitudeChange < -InductionVariable::ChangeMagnitudeLimitForLoopCountBasedHoisting)
- {
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Change magnitude is too large\n"));
- return;
- }
- landingPadHeadSegmentLengthValue = nullptr;
- }
- // Determine if the index already changed in the loop, and by how much
- int indexOffset = 0;
- StackSym *indexSymToAdd = nullptr;
- SymBoundType symBoundType = DetermineSymBoundOffsetOrValueRelativeToLandingPad(
- indexSym,
- maxMagnitudeChange >= 0,
- indexValueInfo,
- indexBounds,
- ¤tLoop->landingPad->globOptData,
- &indexOffset);
- if (symBoundType == SymBoundType::VALUE)
- {
- // The bound value is constant
- indexSymToAdd = nullptr;
- }
- else if (symBoundType == SymBoundType::OFFSET)
- {
- // The bound value is not constant, the offset needs to be added to the index sym in the landing pad
- indexSymToAdd = indexSym;
- }
- else
- {
- Assert(symBoundType == SymBoundType::UNKNOWN);
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Unable to determine the sym bound offset or value\n"));
- return;
- }
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Index's offset from landing pad is %d\n"), indexOffset);
- // The secondary induction variable bound is computed as follows:
- // bound = index + indexOffset + loopCountMinusOne * maxMagnitudeChange
- //
- // If the loop count is constant, (inductionVariableOffset + loopCount * maxMagnitudeChange) can be folded into an offset:
- // bound = index + offset
- int offset;
- StackSym *indexLoopCountBasedBoundBaseSym = nullptr;
- Value *indexLoopCountBasedBoundBaseValue = nullptr;
- IntConstantBounds indexLoopCountBasedBoundBaseConstantBounds;
- bool generateLoopCountBasedIndexBound;
- if(!loopCount->HasBeenGenerated() || loopCount->LoopCountMinusOneSym())
- {
- if(loopCount->HasBeenGenerated())
- {
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 3,
- _u("Loop count is assigned to s%u\n"),
- loopCount->LoopCountMinusOneSym()->m_id);
- }
- else
- {
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Loop count has not been generated yet\n"));
- }
- offset = indexOffset;
- // Check if there is already a loop count based bound sym for the index. If not, generate it.
- do
- {
- const SymID indexSymId = indexSym->m_id;
- SymIdToStackSymMap *&loopCountBasedBoundBaseSyms = currentLoop->loopCountBasedBoundBaseSyms;
- if(!loopCountBasedBoundBaseSyms)
- {
- loopCountBasedBoundBaseSyms = JitAnew(alloc, SymIdToStackSymMap, alloc);
- }
- else if(loopCountBasedBoundBaseSyms->TryGetValue(indexSymId, &indexLoopCountBasedBoundBaseSym))
- {
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 3,
- _u("Loop count based bound is assigned to s%u\n"),
- indexLoopCountBasedBoundBaseSym->m_id);
- indexLoopCountBasedBoundBaseValue = landingPadBlockData.FindValue(indexLoopCountBasedBoundBaseSym);
- Assert(indexLoopCountBasedBoundBaseValue);
- AssertVerify(
- indexLoopCountBasedBoundBaseValue
- ->GetValueInfo()
- ->TryGetIntConstantBounds(&indexLoopCountBasedBoundBaseConstantBounds));
- generateLoopCountBasedIndexBound = false;
- break;
- }
- indexLoopCountBasedBoundBaseSym = StackSym::New(TyInt32, func);
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 3,
- _u("Assigning s%u to the loop count based bound\n"),
- indexLoopCountBasedBoundBaseSym->m_id);
- loopCountBasedBoundBaseSyms->Add(indexSymId, indexLoopCountBasedBoundBaseSym);
- indexLoopCountBasedBoundBaseValue = NewValue(ValueInfo::New(alloc, ValueType::GetInt(true)));
- landingPadBlockData.SetValue(indexLoopCountBasedBoundBaseValue, indexLoopCountBasedBoundBaseSym);
- indexLoopCountBasedBoundBaseConstantBounds = IntConstantBounds(IntConstMin, IntConstMax);
- generateLoopCountBasedIndexBound = true;
- } while(false);
- }
- else
- {
- // The loop count is constant, fold (indexOffset + loopCountMinusOne * maxMagnitudeChange)
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Loop count is constant, folding\n"));
- if(Int32Math::Mul(loopCount->LoopCountMinusOneConstantValue(), maxMagnitudeChange, &offset) ||
- Int32Math::Add(offset, indexOffset, &offset))
- {
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Folding failed\n"));
- return;
- }
- if(!indexSymToAdd)
- {
- // The loop count based bound is constant
- const int loopCountBasedConstantBound = offset;
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 3,
- _u("Loop count based bound is constant: %d\n"),
- loopCountBasedConstantBound);
- if(maxMagnitudeChange < 0)
- {
- if(loopCountBasedConstantBound < 0)
- {
- // Can't use this bound
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Bound < 0\n"));
- return;
- }
- lowerHoistInfo.SetLoop(currentLoop, loopCountBasedConstantBound, true);
- return;
- }
- // loopCountBasedConstantBound >= headSegmentLength is currently not possible, except when
- // loopCountBasedConstantBound == int32 max
- Assert(
- loopCountBasedConstantBound == IntConstMax ||
- !ValueInfo::IsGreaterThanOrEqualTo(
- nullptr,
- loopCountBasedConstantBound,
- loopCountBasedConstantBound,
- landingPadHeadSegmentLengthValue,
- landingPadHeadSegmentLengthConstantBounds.LowerBound(),
- landingPadHeadSegmentLengthConstantBounds.UpperBound()));
- // See if a compatible bound check is already available
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Looking for a compatible bound check\n"));
- const IntBoundCheck *boundCheck;
- if(currentBlock->globOptData.availableIntBoundChecks->TryGetReference(
- IntBoundCheckCompatibilityId(ZeroValueNumber, headSegmentLengthValue->GetValueNumber()),
- &boundCheck))
- {
- // We need:
- // loopCountBasedConstantBound < headSegmentLength
- // Normalize the offset such that:
- // 0 <= headSegmentLength + compatibleBoundCheckOffset
- // Where (compatibleBoundCheckOffset = -1 - loopCountBasedConstantBound), and -1 is to simulate < instead of <=.
- const int compatibleBoundCheckOffset = -1 - loopCountBasedConstantBound;
- if(boundCheck->SetBoundOffset(compatibleBoundCheckOffset, true))
- {
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 4,
- _u("Found in block %u\n"),
- boundCheck->Block()->GetBlockNum());
- upperHoistInfo.SetCompatibleBoundCheck(boundCheck->Block(), loopCountBasedConstantBound);
- return;
- }
- failedToUpdateCompatibleUpperBoundCheck = true;
- }
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Not found\n"));
- upperHoistInfo.SetLoop(
- currentLoop,
- loopCountBasedConstantBound,
- landingPadHeadSegmentLengthValue,
- landingPadHeadSegmentLengthConstantBounds,
- true);
- return;
- }
- // The loop count based bound is not constant; we need to add the offset of the index sym in the landing pad. Instead
- // of adding though, we will treat the index sym as the loop count based bound base sym and adjust the offset that will
- // be used in the bound check itself.
- indexLoopCountBasedBoundBaseSym = indexSymToAdd;
- indexLoopCountBasedBoundBaseValue = landingPadBlockData.FindValue(indexSymToAdd);
- Assert(indexLoopCountBasedBoundBaseValue);
- AssertVerify(
- indexLoopCountBasedBoundBaseValue
- ->GetValueInfo()
- ->TryGetIntConstantBounds(&indexLoopCountBasedBoundBaseConstantBounds));
- generateLoopCountBasedIndexBound = false;
- }
- if(maxMagnitudeChange >= 0)
- {
- // We need:
- // indexLoopCountBasedBoundBase + indexOffset < headSegmentLength
- // Normalize the offset such that:
- // indexLoopCountBasedBoundBase <= headSegmentLength + offset
- // Where (offset = -1 - indexOffset), and -1 is to simulate < instead of <=.
- offset = -1 - offset;
- }
- if(!generateLoopCountBasedIndexBound)
- {
- if(maxMagnitudeChange < 0)
- {
- if(offset != IntConstMax &&
- ValueInfo::IsGreaterThanOrEqualTo(
- nullptr,
- 0,
- 0,
- indexLoopCountBasedBoundBaseValue,
- indexLoopCountBasedBoundBaseConstantBounds.LowerBound(),
- indexLoopCountBasedBoundBaseConstantBounds.UpperBound(),
- offset + 1)) // + 1 to simulate > instead of >=
- {
- // loopCountBasedBound < 0, can't use this bound
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Bound < 0\n"));
- return;
- }
- }
- else if(
- ValueInfo::IsGreaterThanOrEqualTo(
- indexLoopCountBasedBoundBaseValue,
- indexLoopCountBasedBoundBaseConstantBounds.LowerBound(),
- indexLoopCountBasedBoundBaseConstantBounds.UpperBound(),
- landingPadHeadSegmentLengthValue,
- landingPadHeadSegmentLengthConstantBounds.LowerBound(),
- landingPadHeadSegmentLengthConstantBounds.UpperBound(),
- offset))
- {
- // loopCountBasedBound >= headSegmentLength, can't use this bound
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Bound >= head segment length\n"));
- return;
- }
- // See if a compatible bound check is already available
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Looking for a compatible bound check\n"));
- const ValueNumber indexLoopCountBasedBoundBaseValueNumber = indexLoopCountBasedBoundBaseValue->GetValueNumber();
- const IntBoundCheck *boundCheck;
- if(currentBlock->globOptData.availableIntBoundChecks->TryGetReference(
- maxMagnitudeChange < 0
- ? IntBoundCheckCompatibilityId(
- ZeroValueNumber,
- indexLoopCountBasedBoundBaseValueNumber)
- : IntBoundCheckCompatibilityId(
- indexLoopCountBasedBoundBaseValueNumber,
- headSegmentLengthValue->GetValueNumber()),
- &boundCheck))
- {
- if(boundCheck->SetBoundOffset(offset, true))
- {
- TRACE_PHASE_VERBOSE(
- Js::Phase::BoundCheckHoistPhase,
- 4,
- _u("Found in block %u\n"),
- boundCheck->Block()->GetBlockNum());
- if(maxMagnitudeChange < 0)
- {
- lowerHoistInfo.SetCompatibleBoundCheck(
- boundCheck->Block(),
- indexLoopCountBasedBoundBaseSym,
- offset,
- indexLoopCountBasedBoundBaseValueNumber);
- }
- else
- {
- upperHoistInfo.SetCompatibleBoundCheck(
- boundCheck->Block(),
- indexLoopCountBasedBoundBaseSym,
- offset,
- indexLoopCountBasedBoundBaseValueNumber);
- }
- return;
- }
- (maxMagnitudeChange < 0 ? failedToUpdateCompatibleLowerBoundCheck : failedToUpdateCompatibleUpperBoundCheck) = true;
- }
- TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Not found\n"));
- }
- if(maxMagnitudeChange < 0)
- {
- lowerHoistInfo.SetLoop(
- currentLoop,
- indexLoopCountBasedBoundBaseSym,
- offset,
- indexLoopCountBasedBoundBaseValue,
- indexLoopCountBasedBoundBaseConstantBounds,
- true);
- if(generateLoopCountBasedIndexBound)
- {
- lowerHoistInfo.SetLoopCount(loopCount, maxMagnitudeChange);
- }
- return;
- }
- upperHoistInfo.SetLoop(
- currentLoop,
- indexLoopCountBasedBoundBaseSym,
- offset,
- indexLoopCountBasedBoundBaseValue,
- indexLoopCountBasedBoundBaseConstantBounds,
- landingPadHeadSegmentLengthValue,
- landingPadHeadSegmentLengthConstantBounds,
- true);
- if(generateLoopCountBasedIndexBound)
- {
- upperHoistInfo.SetLoopCount(loopCount, maxMagnitudeChange);
- }
- }
|