| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386 |
- //-------------------------------------------------------------------------------------------------------
- // 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"
- FlowGraph *
- FlowGraph::New(Func * func, JitArenaAllocator * alloc)
- {
- FlowGraph * graph;
- graph = JitAnew(alloc, FlowGraph, func, alloc);
- return graph;
- }
- ///----------------------------------------------------------------------------
- ///
- /// FlowGraph::Build
- ///
- /// Construct flow graph and loop structures for the current state of the function.
- ///
- ///----------------------------------------------------------------------------
- void
- FlowGraph::Build(void)
- {
- Func * func = this->func;
- BEGIN_CODEGEN_PHASE(func, Js::FGPeepsPhase);
- this->RunPeeps();
- END_CODEGEN_PHASE(func, Js::FGPeepsPhase);
- // We don't optimize fully with SimpleJit. But, when JIT loop body is enabled, we do support
- // bailing out from a simple jitted function to do a full jit of a loop body in the function
- // (BailOnSimpleJitToFullJitLoopBody). For that purpose, we need the flow from try to catch.
- if (this->func->HasTry() &&
- (this->func->DoOptimizeTryCatch() ||
- (this->func->IsSimpleJit() && this->func->GetJITFunctionBody()->DoJITLoopBody())
- )
- )
- {
- this->catchLabelStack = JitAnew(this->alloc, SList<IR::LabelInstr*>, this->alloc);
- }
- IR::Instr * currLastInstr = nullptr;
- BasicBlock * currBlock = nullptr;
- BasicBlock * nextBlock = nullptr;
- bool hasCall = false;
- FOREACH_INSTR_IN_FUNC_BACKWARD_EDITING(instr, instrPrev, func)
- {
- if (currLastInstr == nullptr || instr->EndsBasicBlock())
- {
- // Start working on a new block.
- // If we're currently processing a block, then wrap it up before beginning a new one.
- if (currLastInstr != nullptr)
- {
- nextBlock = currBlock;
- currBlock = this->AddBlock(instr->m_next, currLastInstr, nextBlock);
- currBlock->hasCall = hasCall;
- hasCall = false;
- }
- currLastInstr = instr;
- }
- if (instr->StartsBasicBlock())
- {
- // Insert a BrOnException after the loop top if we are in a try-catch. This is required to
- // model flow from the loop to the catch block for loops that don't have a break condition.
- if (instr->IsLabelInstr() && instr->AsLabelInstr()->m_isLoopTop &&
- this->catchLabelStack && !this->catchLabelStack->Empty() &&
- instr->m_next->m_opcode != Js::OpCode::BrOnException)
- {
- IR::BranchInstr * brOnException = IR::BranchInstr::New(Js::OpCode::BrOnException, this->catchLabelStack->Top(), instr->m_func);
- instr->InsertAfter(brOnException);
- instrPrev = brOnException; // process BrOnException before adding a new block for loop top label.
- continue;
- }
- // Wrap up the current block and get ready to process a new one.
- nextBlock = currBlock;
- currBlock = this->AddBlock(instr, currLastInstr, nextBlock);
- currBlock->hasCall = hasCall;
- hasCall = false;
- currLastInstr = nullptr;
- }
- switch (instr->m_opcode)
- {
- case Js::OpCode::Catch:
- Assert(instr->m_prev->IsLabelInstr());
- if (this->catchLabelStack)
- {
- this->catchLabelStack->Push(instr->m_prev->AsLabelInstr());
- }
- break;
- case Js::OpCode::TryCatch:
- if (this->catchLabelStack)
- {
- this->catchLabelStack->Pop();
- }
- break;
- case Js::OpCode::CloneBlockScope:
- case Js::OpCode::CloneInnerScopeSlots:
- // It would be nice to do this in IRBuilder, but doing so gives us
- // trouble when doing the DoSlotArrayCheck since it assume single def
- // of the sym to do its check properly. So instead we assign the dst
- // here in FlowGraph.
- instr->SetDst(instr->GetSrc1());
- break;
- }
- if (OpCodeAttr::UseAllFields(instr->m_opcode))
- {
- // UseAllFields opcode are call instruction or opcode that would call.
- hasCall = true;
- if (OpCodeAttr::CallInstr(instr->m_opcode))
- {
- if (!instr->isCallInstrProtectedByNoProfileBailout)
- {
- instr->m_func->SetHasCallsOnSelfAndParents();
- }
- // For ARM & X64 because of their register calling convention
- // the ArgOuts need to be moved next to the call.
- #if defined(_M_ARM) || defined(_M_X64)
- IR::Instr* argInsertInstr = instr;
- instr->IterateArgInstrs([&](IR::Instr* argInstr)
- {
- if (argInstr->m_opcode != Js::OpCode::LdSpreadIndices &&
- argInstr->m_opcode != Js::OpCode::ArgOut_A_Dynamic &&
- argInstr->m_opcode != Js::OpCode::ArgOut_A_FromStackArgs &&
- argInstr->m_opcode != Js::OpCode::ArgOut_A_SpreadArg)
- {
- // don't have bailout in asm.js so we don't need BytecodeArgOutCapture
- if (!argInstr->m_func->GetJITFunctionBody()->IsAsmJsMode())
- {
- // Need to always generate byte code arg out capture,
- // because bailout can't restore from the arg out as it is
- // replaced by new sym for register calling convention in lower
- argInstr->GenerateBytecodeArgOutCapture();
- }
- // Check if the instruction is already next
- if (argInstr != argInsertInstr->m_prev)
- {
- // It is not, move it.
- argInstr->Move(argInsertInstr);
- }
- argInsertInstr = argInstr;
- }
- return false;
- });
- #endif
- }
- }
- }
- NEXT_INSTR_IN_FUNC_BACKWARD_EDITING;
- this->func->isFlowGraphValid = true;
- Assert(!this->catchLabelStack || this->catchLabelStack->Empty());
- // We've been walking backward so that edge lists would be in the right order. Now walk the blocks
- // forward to number the blocks in lexical order.
- unsigned int blockNum = 0;
- FOREACH_BLOCK(block, this)
- {
- block->SetBlockNum(blockNum++);
- }NEXT_BLOCK;
- AssertMsg(blockNum == this->blockCount, "Block count is out of whack");
- this->RemoveUnreachableBlocks();
- this->FindLoops();
- bool breakBlocksRelocated = this->CanonicalizeLoops();
- #if DBG
- this->VerifyLoopGraph();
- #endif
- // Renumber the blocks. Break block remove code has likely inserted new basic blocks.
- blockNum = 0;
- // Regions need to be assigned before Globopt because:
- // 1. FullJit: The Backward Pass will set the write-through symbols on the regions and the forward pass will
- // use this information to insert ToVars for those symbols. Also, for a symbol determined as write-through
- // in the try region to be restored correctly by the bailout, it should not be removed from the
- // byteCodeUpwardExposedUsed upon a def in the try region (the def might be preempted by an exception).
- //
- // 2. SimpleJit: Same case of correct restoration as above applies in SimpleJit too. However, the only bailout
- // we have in Simple Jitted code right now is BailOnSimpleJitToFullJitLoopBody, installed in IRBuilder. So,
- // for now, we can just check if the func has a bailout to assign regions pre globopt while running SimpleJit.
- bool assignRegionsBeforeGlobopt = this->func->HasTry() &&
- (this->func->DoOptimizeTryCatch() || (this->func->IsSimpleJit() && this->func->hasBailout));
- Region ** blockToRegion = nullptr;
- if (assignRegionsBeforeGlobopt)
- {
- blockToRegion = JitAnewArrayZ(this->alloc, Region*, this->blockCount);
- }
- FOREACH_BLOCK_ALL(block, this)
- {
- block->SetBlockNum(blockNum++);
- if (assignRegionsBeforeGlobopt)
- {
- if (block->isDeleted && !block->isDead)
- {
- continue;
- }
- this->UpdateRegionForBlock(block, blockToRegion);
- }
- } NEXT_BLOCK_ALL;
- AssertMsg (blockNum == this->blockCount, "Block count is out of whack");
- if (breakBlocksRelocated)
- {
- // Sort loop lists only if there is break block removal.
- SortLoopLists();
- }
- #if DBG_DUMP
- this->Dump(false, nullptr);
- #endif
- }
- void
- FlowGraph::SortLoopLists()
- {
- // Sort the blocks in loopList
- for (Loop *loop = this->loopList; loop; loop = loop->next)
- {
- unsigned int lastBlockNumber = loop->GetHeadBlock()->GetBlockNum();
- // Insertion sort as the blockList is almost sorted in the loop.
- FOREACH_BLOCK_IN_LOOP_EDITING(block, loop, iter)
- {
- if (lastBlockNumber <= block->GetBlockNum())
- {
- lastBlockNumber = block->GetBlockNum();
- }
- else
- {
- iter.UnlinkCurrent();
- FOREACH_BLOCK_IN_LOOP_EDITING(insertBlock,loop,newIter)
- {
- if (insertBlock->GetBlockNum() > block->GetBlockNum())
- {
- break;
- }
- }NEXT_BLOCK_IN_LOOP_EDITING;
- newIter.InsertBefore(block);
- }
- }NEXT_BLOCK_IN_LOOP_EDITING;
- }
- }
- void
- FlowGraph::RunPeeps()
- {
- if (this->func->HasTry())
- {
- return;
- }
- if (PHASE_OFF(Js::FGPeepsPhase, this->func))
- {
- return;
- }
- IR::Instr * instrCm = nullptr;
- bool tryUnsignedCmpPeep = false;
- FOREACH_INSTR_IN_FUNC_EDITING(instr, instrNext, this->func)
- {
- switch(instr->m_opcode)
- {
- case Js::OpCode::Br:
- case Js::OpCode::BrEq_I4:
- case Js::OpCode::BrGe_I4:
- case Js::OpCode::BrGt_I4:
- case Js::OpCode::BrLt_I4:
- case Js::OpCode::BrLe_I4:
- case Js::OpCode::BrUnGe_I4:
- case Js::OpCode::BrUnGt_I4:
- case Js::OpCode::BrUnLt_I4:
- case Js::OpCode::BrUnLe_I4:
- case Js::OpCode::BrNeq_I4:
- case Js::OpCode::BrEq_A:
- case Js::OpCode::BrGe_A:
- case Js::OpCode::BrGt_A:
- case Js::OpCode::BrLt_A:
- case Js::OpCode::BrLe_A:
- case Js::OpCode::BrUnGe_A:
- case Js::OpCode::BrUnGt_A:
- case Js::OpCode::BrUnLt_A:
- case Js::OpCode::BrUnLe_A:
- case Js::OpCode::BrNotEq_A:
- case Js::OpCode::BrNotNeq_A:
- case Js::OpCode::BrSrNotEq_A:
- case Js::OpCode::BrSrNotNeq_A:
- case Js::OpCode::BrNotGe_A:
- case Js::OpCode::BrNotGt_A:
- case Js::OpCode::BrNotLt_A:
- case Js::OpCode::BrNotLe_A:
- case Js::OpCode::BrNeq_A:
- case Js::OpCode::BrNotNull_A:
- case Js::OpCode::BrNotAddr_A:
- case Js::OpCode::BrAddr_A:
- case Js::OpCode::BrSrEq_A:
- case Js::OpCode::BrSrNeq_A:
- case Js::OpCode::BrOnHasProperty:
- case Js::OpCode::BrOnNoProperty:
- case Js::OpCode::BrHasSideEffects:
- case Js::OpCode::BrNotHasSideEffects:
- case Js::OpCode::BrFncEqApply:
- case Js::OpCode::BrFncNeqApply:
- case Js::OpCode::BrOnEmpty:
- case Js::OpCode::BrOnNotEmpty:
- case Js::OpCode::BrFncCachedScopeEq:
- case Js::OpCode::BrFncCachedScopeNeq:
- case Js::OpCode::BrOnObject_A:
- case Js::OpCode::BrOnClassConstructor:
- case Js::OpCode::BrOnBaseConstructorKind:
- if (tryUnsignedCmpPeep)
- {
- this->UnsignedCmpPeep(instr);
- }
- instrNext = Peeps::PeepBranch(instr->AsBranchInstr());
- break;
- case Js::OpCode::MultiBr:
- // TODO: Run peeps on these as well...
- break;
- case Js::OpCode::BrTrue_I4:
- case Js::OpCode::BrFalse_I4:
- case Js::OpCode::BrTrue_A:
- case Js::OpCode::BrFalse_A:
- if (instrCm)
- {
- if (instrCm->GetDst()->IsInt32())
- {
- Assert(instr->m_opcode == Js::OpCode::BrTrue_I4 || instr->m_opcode == Js::OpCode::BrFalse_I4);
- instrNext = this->PeepTypedCm(instrCm);
- }
- else
- {
- instrNext = this->PeepCm(instrCm);
- }
- instrCm = nullptr;
- if (instrNext == nullptr)
- {
- // Set instrNext back to the current instr.
- instrNext = instr;
- }
- }
- else
- {
- instrNext = Peeps::PeepBranch(instr->AsBranchInstr());
- }
- break;
- case Js::OpCode::CmEq_I4:
- case Js::OpCode::CmGe_I4:
- case Js::OpCode::CmGt_I4:
- case Js::OpCode::CmLt_I4:
- case Js::OpCode::CmLe_I4:
- case Js::OpCode::CmNeq_I4:
- case Js::OpCode::CmEq_A:
- case Js::OpCode::CmGe_A:
- case Js::OpCode::CmGt_A:
- case Js::OpCode::CmLt_A:
- case Js::OpCode::CmLe_A:
- case Js::OpCode::CmNeq_A:
- case Js::OpCode::CmSrEq_A:
- case Js::OpCode::CmSrNeq_A:
- if (tryUnsignedCmpPeep)
- {
- this->UnsignedCmpPeep(instr);
- }
- case Js::OpCode::CmUnGe_I4:
- case Js::OpCode::CmUnGt_I4:
- case Js::OpCode::CmUnLt_I4:
- case Js::OpCode::CmUnLe_I4:
- case Js::OpCode::CmUnGe_A:
- case Js::OpCode::CmUnGt_A:
- case Js::OpCode::CmUnLt_A:
- case Js::OpCode::CmUnLe_A:
- // There may be useless branches between the Cm instr and the branch that uses the result.
- // So save the last Cm instr seen, and trigger the peep on the next BrTrue/BrFalse.
- instrCm = instr;
- break;
- case Js::OpCode::Label:
- if (instr->AsLabelInstr()->IsUnreferenced())
- {
- instrNext = Peeps::PeepUnreachableLabel(instr->AsLabelInstr(), false);
- }
- break;
- case Js::OpCode::StatementBoundary:
- instr->ClearByteCodeOffset();
- instr->SetByteCodeOffset(instr->GetNextRealInstrOrLabel());
- break;
- case Js::OpCode::ShrU_I4:
- case Js::OpCode::ShrU_A:
- if (tryUnsignedCmpPeep)
- {
- break;
- }
- if (instr->GetDst()->AsRegOpnd()->m_sym->IsSingleDef()
- && instr->GetSrc2()->IsRegOpnd() && instr->GetSrc2()->AsRegOpnd()->m_sym->IsTaggableIntConst()
- && instr->GetSrc2()->AsRegOpnd()->m_sym->GetIntConstValue() == 0)
- {
- tryUnsignedCmpPeep = true;
- }
- break;
- default:
- Assert(!instr->IsBranchInstr());
- }
- } NEXT_INSTR_IN_FUNC_EDITING;
- }
- void
- Loop::InsertLandingPad(FlowGraph *fg)
- {
- BasicBlock *headBlock = this->GetHeadBlock();
- // Always create a landing pad. This allows globopt to easily hoist instructions
- // and re-optimize the block if needed.
- BasicBlock *landingPad = BasicBlock::New(fg);
- this->landingPad = landingPad;
- IR::Instr * headInstr = headBlock->GetFirstInstr();
- IR::LabelInstr *landingPadLabel = IR::LabelInstr::New(Js::OpCode::Label, headInstr->m_func);
- landingPadLabel->SetByteCodeOffset(headInstr);
- headInstr->InsertBefore(landingPadLabel);
- landingPadLabel->SetBasicBlock(landingPad);
- landingPad->SetBlockNum(fg->blockCount++);
- landingPad->SetFirstInstr(landingPadLabel);
- landingPad->SetLastInstr(landingPadLabel);
- landingPad->prev = headBlock->prev;
- landingPad->prev->next = landingPad;
- landingPad->next = headBlock;
- headBlock->prev = landingPad;
- Loop *parentLoop = this->parent;
- landingPad->loop = parentLoop;
- // We need to add this block to the block list of the parent loops
- while (parentLoop)
- {
- // Find the head block in the block list of the parent loop
- FOREACH_BLOCK_IN_LOOP_EDITING(block, parentLoop, iter)
- {
- if (block == headBlock)
- {
- // Add the landing pad to the block list
- iter.InsertBefore(landingPad);
- break;
- }
- } NEXT_BLOCK_IN_LOOP_EDITING;
- parentLoop = parentLoop->parent;
- }
- // Fix predecessor flow edges
- FOREACH_PREDECESSOR_EDGE_EDITING(edge, headBlock, iter)
- {
- // Make sure it isn't a back-edge
- if (edge->GetPred()->loop != this && !this->IsDescendentOrSelf(edge->GetPred()->loop))
- {
- if (edge->GetPred()->GetLastInstr()->IsBranchInstr() && headBlock->GetFirstInstr()->IsLabelInstr())
- {
- IR::BranchInstr *branch = edge->GetPred()->GetLastInstr()->AsBranchInstr();
- branch->ReplaceTarget(headBlock->GetFirstInstr()->AsLabelInstr(), landingPadLabel);
- }
- headBlock->UnlinkPred(edge->GetPred(), false);
- landingPad->AddPred(edge, fg);
- edge->SetSucc(landingPad);
- }
- } NEXT_PREDECESSOR_EDGE_EDITING;
- fg->AddEdge(landingPad, headBlock);
- }
- bool
- Loop::RemoveBreakBlocks(FlowGraph *fg)
- {
- bool breakBlockRelocated = false;
- if (PHASE_OFF(Js::RemoveBreakBlockPhase, fg->GetFunc()))
- {
- return false;
- }
- BasicBlock *loopTailBlock = nullptr;
- FOREACH_BLOCK_IN_LOOP(block, this)
- {
- loopTailBlock = block;
- }NEXT_BLOCK_IN_LOOP;
- AnalysisAssert(loopTailBlock);
- FOREACH_BLOCK_BACKWARD_IN_RANGE_EDITING(breakBlockEnd, loopTailBlock, this->GetHeadBlock(), blockPrev)
- {
- while (!this->IsDescendentOrSelf(breakBlockEnd->loop))
- {
- // Found at least one break block;
- breakBlockRelocated = true;
- #if DBG
- breakBlockEnd->isBreakBlock = true;
- #endif
- // Find the first block in this break block sequence.
- BasicBlock *breakBlockStart = breakBlockEnd;
- BasicBlock *breakBlockStartPrev = breakBlockEnd->GetPrev();
- // Walk back the blocks until we find a block which belongs to that block.
- // Note: We don't really care if there are break blocks corresponding to different loops. We move the blocks conservatively to the end of the loop.
- // Algorithm works on one loop at a time.
- while((breakBlockStartPrev->loop == breakBlockEnd->loop) || !this->IsDescendentOrSelf(breakBlockStartPrev->loop))
- {
- breakBlockStart = breakBlockStartPrev;
- breakBlockStartPrev = breakBlockStartPrev->GetPrev();
- }
- #if DBG
- breakBlockStart->isBreakBlock = true; // Mark the first block as well.
- #endif
- BasicBlock *exitLoopTail = loopTailBlock;
- // Move these break blocks to the tail of the loop.
- fg->MoveBlocksBefore(breakBlockStart, breakBlockEnd, exitLoopTail->next);
- #if DBG_DUMP
- fg->Dump(true /*needs verbose flag*/, _u("\n After Each iteration of canonicalization \n"));
- #endif
- // Again be conservative, there are edits to the loop graph. Start fresh for this loop.
- breakBlockEnd = loopTailBlock;
- blockPrev = breakBlockEnd->prev;
- }
- } NEXT_BLOCK_BACKWARD_IN_RANGE_EDITING;
- return breakBlockRelocated;
- }
- void
- FlowGraph::MoveBlocksBefore(BasicBlock *blockStart, BasicBlock *blockEnd, BasicBlock *insertBlock)
- {
- BasicBlock *srcPredBlock = blockStart->prev;
- BasicBlock *srcNextBlock = blockEnd->next;
- BasicBlock *dstPredBlock = insertBlock->prev;
- IR::Instr* dstPredBlockLastInstr = dstPredBlock->GetLastInstr();
- IR::Instr* blockEndLastInstr = blockEnd->GetLastInstr();
- // Fix block linkage
- srcPredBlock->next = srcNextBlock;
- srcNextBlock->prev = srcPredBlock;
- dstPredBlock->next = blockStart;
- insertBlock->prev = blockEnd;
- blockStart->prev = dstPredBlock;
- blockEnd->next = insertBlock;
- // Fix instruction linkage
- IR::Instr::MoveRangeAfter(blockStart->GetFirstInstr(), blockEndLastInstr, dstPredBlockLastInstr);
- // Fix instruction flow
- IR::Instr *srcLastInstr = srcPredBlock->GetLastInstr();
- if (srcLastInstr->IsBranchInstr() && srcLastInstr->AsBranchInstr()->HasFallThrough())
- {
- // There was a fallthrough in the break blocks original position.
- IR::BranchInstr *srcBranch = srcLastInstr->AsBranchInstr();
- IR::Instr *srcBranchNextInstr = srcBranch->GetNextRealInstrOrLabel();
- // Save the target and invert the branch.
- IR::LabelInstr *srcBranchTarget = srcBranch->GetTarget();
- srcPredBlock->InvertBranch(srcBranch);
- IR::LabelInstr *srcLabel = blockStart->GetFirstInstr()->AsLabelInstr();
- // Point the inverted branch to break block.
- srcBranch->SetTarget(srcLabel);
- if (srcBranchNextInstr != srcBranchTarget)
- {
- FlowEdge *srcEdge = this->FindEdge(srcPredBlock, srcBranchTarget->GetBasicBlock());
- Assert(srcEdge);
- BasicBlock *compensationBlock = this->InsertCompensationCodeForBlockMove(srcEdge, true /*insert compensation block to loop list*/, false /*At source*/);
- Assert(compensationBlock);
- }
- }
- IR::Instr *dstLastInstr = dstPredBlockLastInstr;
- if (dstLastInstr->IsBranchInstr() && dstLastInstr->AsBranchInstr()->HasFallThrough())
- {
- //There is a fallthrough in the block after which break block is inserted.
- FlowEdge *dstEdge = this->FindEdge(dstPredBlock, blockEnd->GetNext());
- Assert(dstEdge);
- BasicBlock *compensationBlock = this->InsertCompensationCodeForBlockMove(dstEdge, true /*insert compensation block to loop list*/, true /*At sink*/);
- Assert(compensationBlock);
- }
- }
- FlowEdge *
- FlowGraph::FindEdge(BasicBlock *predBlock, BasicBlock *succBlock)
- {
- FlowEdge *srcEdge = nullptr;
- FOREACH_SUCCESSOR_EDGE(edge, predBlock)
- {
- if (edge->GetSucc() == succBlock)
- {
- srcEdge = edge;
- break;
- }
- } NEXT_SUCCESSOR_EDGE;
- return srcEdge;
- }
- void
- BasicBlock::InvertBranch(IR::BranchInstr *branch)
- {
- Assert(this->GetLastInstr() == branch);
- Assert(this->GetSuccList()->HasTwo());
- branch->Invert();
- this->GetSuccList()->Reverse();
- }
- bool
- FlowGraph::CanonicalizeLoops()
- {
- if (this->func->HasProfileInfo())
- {
- this->implicitCallFlags = this->func->GetReadOnlyProfileInfo()->GetImplicitCallFlags();
- for (Loop *loop = this->loopList; loop; loop = loop->next)
- {
- this->implicitCallFlags = (Js::ImplicitCallFlags)(this->implicitCallFlags | loop->GetImplicitCallFlags());
- }
- }
- #if DBG_DUMP
- this->Dump(true, _u("\n Before canonicalizeLoops \n"));
- #endif
- bool breakBlockRelocated = false;
- for (Loop *loop = this->loopList; loop; loop = loop->next)
- {
- loop->InsertLandingPad(this);
- if (!this->func->HasTry() || this->func->DoOptimizeTryCatch())
- {
- bool relocated = loop->RemoveBreakBlocks(this);
- if (!breakBlockRelocated && relocated)
- {
- breakBlockRelocated = true;
- }
- }
- }
- #if DBG_DUMP
- this->Dump(true, _u("\n After canonicalizeLoops \n"));
- #endif
- return breakBlockRelocated;
- }
- // Find the loops in this function, build the loop structure, and build a linked
- // list of the basic blocks in this loop (including blocks of inner loops). The
- // list preserves the reverse post-order of the blocks in the flowgraph block list.
- void
- FlowGraph::FindLoops()
- {
- if (!this->hasLoop)
- {
- return;
- }
- Func * func = this->func;
- FOREACH_BLOCK_BACKWARD_IN_FUNC(block, func)
- {
- if (block->loop != nullptr)
- {
- // Block already visited
- continue;
- }
- FOREACH_SUCCESSOR_BLOCK(succ, block)
- {
- if (succ->isLoopHeader && succ->loop == nullptr)
- {
- // Found a loop back-edge
- BuildLoop(succ, block);
- }
- } NEXT_SUCCESSOR_BLOCK;
- if (block->isLoopHeader && block->loop == nullptr)
- {
- // We would have built a loop for it if it was a loop...
- block->isLoopHeader = false;
- block->GetFirstInstr()->AsLabelInstr()->m_isLoopTop = false;
- }
- } NEXT_BLOCK_BACKWARD_IN_FUNC;
- }
- void
- FlowGraph::BuildLoop(BasicBlock *headBlock, BasicBlock *tailBlock, Loop *parentLoop)
- {
- // This function is recursive, so when jitting in the foreground, probe the stack
- if(!func->IsBackgroundJIT())
- {
- PROBE_STACK(func->GetScriptContext(), Js::Constants::MinStackDefault);
- }
- if (tailBlock->number < headBlock->number)
- {
- // Not a loop. We didn't see any back-edge.
- headBlock->isLoopHeader = false;
- headBlock->GetFirstInstr()->AsLabelInstr()->m_isLoopTop = false;
- return;
- }
- Assert(headBlock->isLoopHeader);
- Loop *loop = JitAnewZ(this->GetFunc()->m_alloc, Loop, this->GetFunc()->m_alloc, this->GetFunc());
- loop->next = this->loopList;
- this->loopList = loop;
- headBlock->loop = loop;
- loop->headBlock = headBlock;
- loop->int32SymsOnEntry = nullptr;
- loop->lossyInt32SymsOnEntry = nullptr;
- // If parentLoop is a parent of loop, it's headBlock better appear first.
- if (parentLoop && loop->headBlock->number > parentLoop->headBlock->number)
- {
- loop->parent = parentLoop;
- parentLoop->isLeaf = false;
- }
- loop->hasDeadStoreCollectionPass = false;
- loop->hasDeadStorePrepass = false;
- loop->memOpInfo = nullptr;
- loop->doMemOp = true;
- NoRecoverMemoryJitArenaAllocator tempAlloc(_u("BE-LoopBuilder"), this->func->m_alloc->GetPageAllocator(), Js::Throw::OutOfMemory);
- WalkLoopBlocks(tailBlock, loop, &tempAlloc);
- Assert(loop->GetHeadBlock() == headBlock);
- IR::LabelInstr * firstInstr = loop->GetLoopTopInstr();
- firstInstr->SetLoop(loop);
- if (firstInstr->IsProfiledLabelInstr())
- {
- loop->SetImplicitCallFlags(firstInstr->AsProfiledLabelInstr()->loopImplicitCallFlags);
- if (this->func->HasProfileInfo() && this->func->GetReadOnlyProfileInfo()->IsLoopImplicitCallInfoDisabled())
- {
- loop->SetImplicitCallFlags(this->func->GetReadOnlyProfileInfo()->GetImplicitCallFlags());
- }
- loop->SetLoopFlags(firstInstr->AsProfiledLabelInstr()->loopFlags);
- }
- else
- {
- // Didn't collect profile information, don't do optimizations
- loop->SetImplicitCallFlags(Js::ImplicitCall_All);
- }
- }
- Loop::MemCopyCandidate* Loop::MemOpCandidate::AsMemCopy()
- {
- Assert(this->IsMemCopy());
- return (Loop::MemCopyCandidate*)this;
- }
- Loop::MemSetCandidate* Loop::MemOpCandidate::AsMemSet()
- {
- Assert(this->IsMemSet());
- return (Loop::MemSetCandidate*)this;
- }
- void
- Loop::EnsureMemOpVariablesInitialized()
- {
- Assert(this->doMemOp);
- if (this->memOpInfo == nullptr)
- {
- JitArenaAllocator *allocator = this->GetFunc()->GetTopFunc()->m_fg->alloc;
- this->memOpInfo = JitAnewStruct(allocator, Loop::MemOpInfo);
- this->memOpInfo->inductionVariablesUsedAfterLoop = nullptr;
- this->memOpInfo->startIndexOpndCache[0] = nullptr;
- this->memOpInfo->startIndexOpndCache[1] = nullptr;
- this->memOpInfo->startIndexOpndCache[2] = nullptr;
- this->memOpInfo->startIndexOpndCache[3] = nullptr;
- this->memOpInfo->inductionVariableChangeInfoMap = JitAnew(allocator, Loop::InductionVariableChangeInfoMap, allocator);
- this->memOpInfo->inductionVariableOpndPerUnrollMap = JitAnew(allocator, Loop::InductionVariableOpndPerUnrollMap, allocator);
- this->memOpInfo->candidates = JitAnew(allocator, Loop::MemOpList, allocator);
- }
- }
- // Walk the basic blocks backwards until we find the loop header.
- // Mark basic blocks in the loop by looking at the predecessors
- // of blocks known to be in the loop.
- // Recurse on inner loops.
- void
- FlowGraph::WalkLoopBlocks(BasicBlock *block, Loop *loop, JitArenaAllocator *tempAlloc)
- {
- AnalysisAssert(loop);
- BVSparse<JitArenaAllocator> *loopBlocksBv = JitAnew(tempAlloc, BVSparse<JitArenaAllocator>, tempAlloc);
- BasicBlock *tailBlock = block;
- BasicBlock *lastBlock;
- loopBlocksBv->Set(block->GetBlockNum());
- this->AddBlockToLoop(block, loop);
- if (block == loop->headBlock)
- {
- // Single block loop, we're done
- return;
- }
- do
- {
- BOOL isInLoop = loopBlocksBv->Test(block->GetBlockNum());
- FOREACH_SUCCESSOR_BLOCK(succ, block)
- {
- if (succ->isLoopHeader)
- {
- // Found a loop back-edge
- if (loop->headBlock == succ)
- {
- isInLoop = true;
- }
- else if (succ->loop == nullptr || succ->loop->headBlock != succ)
- {
- // Recurse on inner loop
- BuildLoop(succ, block, isInLoop ? loop : nullptr);
- }
- }
- } NEXT_SUCCESSOR_BLOCK;
- if (isInLoop)
- {
- // This block is in the loop. All of it's predecessors should be contained in the loop as well.
- FOREACH_PREDECESSOR_BLOCK(pred, block)
- {
- // Fix up loop parent if it isn't set already.
- // If pred->loop != loop, we're looking at an inner loop, which was already visited.
- // If pred->loop->parent == nullptr, this is the first time we see this loop from an outer
- // loop, so this must be an immediate child.
- if (pred->loop && pred->loop != loop && loop->headBlock->number < pred->loop->headBlock->number
- && (pred->loop->parent == nullptr || pred->loop->parent->headBlock->number < loop->headBlock->number))
- {
- pred->loop->parent = loop;
- loop->isLeaf = false;
- if (pred->loop->hasCall)
- {
- loop->SetHasCall();
- }
- loop->SetImplicitCallFlags(pred->loop->GetImplicitCallFlags());
- }
- // Add pred to loop bit vector
- loopBlocksBv->Set(pred->GetBlockNum());
- } NEXT_PREDECESSOR_BLOCK;
- if (block->loop == nullptr || block->loop->IsDescendentOrSelf(loop))
- {
- block->loop = loop;
- }
- if (block != tailBlock)
- {
- this->AddBlockToLoop(block, loop);
- }
- }
- lastBlock = block;
- block = block->GetPrev();
- } while (lastBlock != loop->headBlock);
- }
- // Add block to this loop, and it's parent loops.
- void
- FlowGraph::AddBlockToLoop(BasicBlock *block, Loop *loop)
- {
- loop->blockList.Prepend(block);
- if (block->hasCall)
- {
- loop->SetHasCall();
- }
- }
- ///----------------------------------------------------------------------------
- ///
- /// FlowGraph::AddBlock
- ///
- /// Finish processing of a new block: hook up successor arcs, note loops, etc.
- ///
- ///----------------------------------------------------------------------------
- BasicBlock *
- FlowGraph::AddBlock(
- IR::Instr * firstInstr,
- IR::Instr * lastInstr,
- BasicBlock * nextBlock)
- {
- BasicBlock * block;
- IR::LabelInstr * labelInstr;
- if (firstInstr->IsLabelInstr())
- {
- labelInstr = firstInstr->AsLabelInstr();
- }
- else
- {
- labelInstr = IR::LabelInstr::New(Js::OpCode::Label, firstInstr->m_func);
- labelInstr->SetByteCodeOffset(firstInstr);
- if (firstInstr->IsEntryInstr())
- {
- firstInstr->InsertAfter(labelInstr);
- }
- else
- {
- firstInstr->InsertBefore(labelInstr);
- }
- firstInstr = labelInstr;
- }
- block = labelInstr->GetBasicBlock();
- if (block == nullptr)
- {
- block = BasicBlock::New(this);
- labelInstr->SetBasicBlock(block);
- // Remember last block in function to target successor of RETs.
- if (!this->tailBlock)
- {
- this->tailBlock = block;
- }
- }
- // Hook up the successor edges
- if (lastInstr->EndsBasicBlock())
- {
- BasicBlock * blockTarget = nullptr;
- if (lastInstr->IsBranchInstr())
- {
- // Hook up a successor edge to the branch target.
- IR::BranchInstr * branchInstr = lastInstr->AsBranchInstr();
- if(branchInstr->IsMultiBranch())
- {
- BasicBlock * blockMultiBrTarget;
- IR::MultiBranchInstr * multiBranchInstr = branchInstr->AsMultiBrInstr();
- multiBranchInstr->MapUniqueMultiBrLabels([&](IR::LabelInstr * labelInstr) -> void
- {
- blockMultiBrTarget = SetBlockTargetAndLoopFlag(labelInstr);
- this->AddEdge(block, blockMultiBrTarget);
- });
- }
- else
- {
- IR::LabelInstr * targetLabelInstr = branchInstr->GetTarget();
- blockTarget = SetBlockTargetAndLoopFlag(targetLabelInstr);
- if (branchInstr->IsConditional())
- {
- IR::Instr *instrNext = branchInstr->GetNextRealInstrOrLabel();
- if (instrNext->IsLabelInstr())
- {
- SetBlockTargetAndLoopFlag(instrNext->AsLabelInstr());
- }
- }
- }
- }
- else if (lastInstr->m_opcode == Js::OpCode::Ret && block != this->tailBlock)
- {
- blockTarget = this->tailBlock;
- }
- if (blockTarget)
- {
- this->AddEdge(block, blockTarget);
- }
- }
- if (lastInstr->HasFallThrough())
- {
- // Add a branch to next instruction so that we don't have to update the flow graph
- // when the glob opt tries to insert instructions.
- // We don't run the globopt with try/catch, don't need to insert branch to next for fall through blocks.
- if (!this->func->HasTry() && !lastInstr->IsBranchInstr())
- {
- IR::BranchInstr * instr = IR::BranchInstr::New(Js::OpCode::Br,
- lastInstr->m_next->AsLabelInstr(), lastInstr->m_func);
- instr->SetByteCodeOffset(lastInstr->m_next);
- lastInstr->InsertAfter(instr);
- lastInstr = instr;
- }
- this->AddEdge(block, nextBlock);
- }
- block->SetBlockNum(this->blockCount++);
- block->SetFirstInstr(firstInstr);
- block->SetLastInstr(lastInstr);
- if (this->blockList)
- {
- this->blockList->prev = block;
- }
- block->next = this->blockList;
- this->blockList = block;
- return block;
- }
- BasicBlock *
- FlowGraph::SetBlockTargetAndLoopFlag(IR::LabelInstr * labelInstr)
- {
- BasicBlock * blockTarget = nullptr;
- blockTarget = labelInstr->GetBasicBlock();
- if (blockTarget == nullptr)
- {
- blockTarget = BasicBlock::New(this);
- labelInstr->SetBasicBlock(blockTarget);
- }
- if (labelInstr->m_isLoopTop)
- {
- blockTarget->isLoopHeader = true;
- this->hasLoop = true;
- }
- return blockTarget;
- }
- ///----------------------------------------------------------------------------
- ///
- /// FlowGraph::AddEdge
- ///
- /// Add an edge connecting the two given blocks.
- ///
- ///----------------------------------------------------------------------------
- FlowEdge *
- FlowGraph::AddEdge(BasicBlock * blockPred, BasicBlock * blockSucc)
- {
- FlowEdge * edge = FlowEdge::New(this);
- edge->SetPred(blockPred);
- edge->SetSucc(blockSucc);
- blockPred->AddSucc(edge, this);
- blockSucc->AddPred(edge, this);
- return edge;
- }
- ///----------------------------------------------------------------------------
- ///
- /// FlowGraph::Destroy
- ///
- /// Remove all references to FG structures from the IR in preparation for freeing
- /// the FG.
- ///
- ///----------------------------------------------------------------------------
- void
- FlowGraph::Destroy(void)
- {
- BOOL fHasTry = this->func->HasTry();
- Region ** blockToRegion = nullptr;
- if (fHasTry)
- {
- blockToRegion = JitAnewArrayZ(this->alloc, Region*, this->blockCount);
- // Do unreachable code removal up front to avoid problems
- // with unreachable back edges, etc.
- this->RemoveUnreachableBlocks();
- }
- FOREACH_BLOCK_ALL(block, this)
- {
- IR::Instr * firstInstr = block->GetFirstInstr();
- if (block->isDeleted && !block->isDead)
- {
- if (firstInstr->IsLabelInstr())
- {
- IR::LabelInstr * labelInstr = firstInstr->AsLabelInstr();
- labelInstr->UnlinkBasicBlock();
- // Removing the label for non try blocks as we have a deleted block which has the label instruction
- // still not removed; this prevents the assert for cases where the deleted blocks fall through to a helper block,
- // i.e. helper introduced by polymorphic inlining bailout.
- // Skipping Try blocks as we have dependency on blocks to get the last instr(see below in this function)
- if (!fHasTry)
- {
- if (this->func->GetJITFunctionBody()->IsCoroutine())
- {
- // the label could be a yield resume label, in which case we also need to remove it from the YieldOffsetResumeLabels list
- this->func->MapUntilYieldOffsetResumeLabels([this, &labelInstr](int i, const YieldOffsetResumeLabel& yorl)
- {
- if (labelInstr == yorl.Second())
- {
- labelInstr->m_hasNonBranchRef = false;
- this->func->RemoveYieldOffsetResumeLabel(yorl);
- return true;
- }
- return false;
- });
- }
- Assert(labelInstr->IsUnreferenced());
- labelInstr->Remove();
- }
- }
- continue;
- }
- if (block->isLoopHeader && !block->isDead)
- {
- // Mark the tail block of this loop (the last back-edge). The register allocator
- // uses this to lexically find loops.
- BasicBlock *loopTail = nullptr;
- AssertMsg(firstInstr->IsLabelInstr() && firstInstr->AsLabelInstr()->m_isLoopTop,
- "Label not marked as loop top...");
- FOREACH_BLOCK_IN_LOOP(loopBlock, block->loop)
- {
- FOREACH_SUCCESSOR_BLOCK(succ, loopBlock)
- {
- if (succ == block)
- {
- loopTail = loopBlock;
- break;
- }
- } NEXT_SUCCESSOR_BLOCK;
- } NEXT_BLOCK_IN_LOOP;
- if (loopTail)
- {
- AssertMsg(loopTail->GetLastInstr()->IsBranchInstr(), "LastInstr of loop should always be a branch no?");
- block->loop->SetLoopTopInstr(block->GetFirstInstr()->AsLabelInstr());
- }
- else
- {
- // This loop doesn't have a back-edge: that is, it is not a loop
- // anymore...
- firstInstr->AsLabelInstr()->m_isLoopTop = FALSE;
- }
- }
- if (fHasTry)
- {
- this->UpdateRegionForBlock(block, blockToRegion);
- }
- if (firstInstr->IsLabelInstr())
- {
- IR::LabelInstr * labelInstr = firstInstr->AsLabelInstr();
- labelInstr->UnlinkBasicBlock();
- if (labelInstr->IsUnreferenced() && !fHasTry)
- {
- // This is an unreferenced label, probably added by FG building.
- // Delete it now to make extended basic blocks visible.
- if (firstInstr == block->GetLastInstr())
- {
- labelInstr->Remove();
- continue;
- }
- else
- {
- labelInstr->Remove();
- }
- }
- }
- // We don't run the globopt with try/catch, don't need to remove branch to next for fall through blocks
- IR::Instr * lastInstr = block->GetLastInstr();
- if (!fHasTry && lastInstr->IsBranchInstr())
- {
- IR::BranchInstr * branchInstr = lastInstr->AsBranchInstr();
- if (!branchInstr->IsConditional() && branchInstr->GetTarget() == branchInstr->m_next)
- {
- // Remove branch to next
- branchInstr->Remove();
- }
- }
- }
- NEXT_BLOCK;
- #if DBG
- if (fHasTry)
- {
- // Now that all blocks have regions, we should see consistently propagated regions at all
- // block boundaries.
- FOREACH_BLOCK(block, this)
- {
- Region * region = blockToRegion[block->GetBlockNum()];
- Region * predRegion = nullptr;
- FOREACH_PREDECESSOR_BLOCK(predBlock, block)
- {
- predRegion = blockToRegion[predBlock->GetBlockNum()];
- if (predBlock->GetLastInstr() == nullptr)
- {
- AssertMsg(region == predRegion, "Bad region propagation through empty block");
- }
- else
- {
- switch (predBlock->GetLastInstr()->m_opcode)
- {
- case Js::OpCode::TryCatch:
- case Js::OpCode::TryFinally:
- AssertMsg(region->GetParent() == predRegion, "Bad region prop on entry to try-catch/finally");
- if (block->GetFirstInstr() == predBlock->GetLastInstr()->AsBranchInstr()->GetTarget())
- {
- if (predBlock->GetLastInstr()->m_opcode == Js::OpCode::TryCatch)
- {
- AssertMsg(region->GetType() == RegionTypeCatch, "Bad region type on entry to catch");
- }
- else
- {
- AssertMsg(region->GetType() == RegionTypeFinally, "Bad region type on entry to finally");
- }
- }
- else
- {
- AssertMsg(region->GetType() == RegionTypeTry, "Bad region type on entry to try");
- }
- break;
- case Js::OpCode::Leave:
- case Js::OpCode::LeaveNull:
- AssertMsg(region == predRegion->GetParent() || (region == predRegion && this->func->IsLoopBodyInTry()), "Bad region prop on leaving try-catch/finally");
- break;
- // If the try region has a branch out of the loop,
- // - the branch is moved out of the loop as part of break block removal, and
- // - BrOnException is inverted to BrOnNoException and a Br is inserted after it.
- // Otherwise,
- // - FullJit: BrOnException is removed in the forward pass.
- case Js::OpCode::BrOnException:
- Assert(!this->func->DoGlobOpt());
- case Js::OpCode::BrOnNoException:
- Assert(this->func->HasTry() &&
- ((!this->func->HasFinally() && !this->func->IsLoopBody() && !PHASE_OFF(Js::OptimizeTryCatchPhase, this->func)) ||
- (this->func->IsSimpleJit() && this->func->GetJITFunctionBody()->DoJITLoopBody()))); // should be relaxed as more bailouts are added in Simple Jit
- Assert(region->GetType() == RegionTypeTry || region->GetType() == RegionTypeCatch);
- if (region->GetType() == RegionTypeCatch)
- {
- Assert((predRegion->GetType() == RegionTypeTry) || (predRegion->GetType() == RegionTypeCatch));
- }
- else if (region->GetType() == RegionTypeTry)
- {
- Assert(region == predRegion);
- }
- break;
- case Js::OpCode::Br:
- if (region->GetType() == RegionTypeCatch && region != predRegion)
- {
- AssertMsg(predRegion->GetType() == RegionTypeTry, "Bad region type for the try");
- }
- else
- {
- AssertMsg(region == predRegion, "Bad region propagation through interior block");
- }
- break;
- default:
- AssertMsg(region == predRegion, "Bad region propagation through interior block");
- break;
- }
- }
- }
- NEXT_PREDECESSOR_BLOCK;
- switch (region->GetType())
- {
- case RegionTypeRoot:
- Assert(!region->GetMatchingTryRegion() && !region->GetMatchingCatchRegion() && !region->GetMatchingFinallyRegion());
- break;
- case RegionTypeTry:
- Assert(!(region->GetMatchingCatchRegion() && region->GetMatchingFinallyRegion()));
- break;
- case RegionTypeCatch:
- case RegionTypeFinally:
- Assert(region->GetMatchingTryRegion());
- break;
- }
- }
- NEXT_BLOCK;
- FOREACH_BLOCK_DEAD_OR_ALIVE(block, this)
- {
- if (block->GetFirstInstr()->IsLabelInstr())
- {
- IR::LabelInstr *labelInstr = block->GetFirstInstr()->AsLabelInstr();
- if (labelInstr->IsUnreferenced())
- {
- // This is an unreferenced label, probably added by FG building.
- // Delete it now to make extended basic blocks visible.
- labelInstr->Remove();
- }
- }
- } NEXT_BLOCK_DEAD_OR_ALIVE;
- }
- #endif
- this->func->isFlowGraphValid = false;
- }
- // Propagate the region forward from the block's predecessor(s), tracking the effect
- // of the flow transition. Record the region in the block-to-region map provided
- // and on the label at the entry to the block (if any).
- void
- FlowGraph::UpdateRegionForBlock(BasicBlock * block, Region ** blockToRegion)
- {
- Region *region;
- Region * predRegion = nullptr;
- IR::Instr * tryInstr = nullptr;
- IR::Instr * firstInstr = block->GetFirstInstr();
- if (firstInstr->IsLabelInstr() && firstInstr->AsLabelInstr()->GetRegion())
- {
- Assert(this->func->HasTry() && (this->func->DoOptimizeTryCatch() || (this->func->IsSimpleJit() && this->func->hasBailout)));
- blockToRegion[block->GetBlockNum()] = firstInstr->AsLabelInstr()->GetRegion();
- return;
- }
- if (block == this->blockList)
- {
- // Head of the graph: create the root region.
- region = Region::New(RegionTypeRoot, nullptr, this->func);
- }
- else
- {
- // Propagate the region forward by finding a predecessor we've already processed.
- // We require that there be one, since we've already removed unreachable blocks.
- region = nullptr;
- FOREACH_PREDECESSOR_BLOCK(predBlock, block)
- {
- AssertMsg(predBlock->GetBlockNum() < this->blockCount, "Misnumbered block at teardown time?");
- predRegion = blockToRegion[predBlock->GetBlockNum()];
- if (predRegion != nullptr)
- {
- region = this->PropagateRegionFromPred(block, predBlock, predRegion, tryInstr);
- break;
- }
- }
- NEXT_PREDECESSOR_BLOCK;
- }
- AnalysisAssertMsg(region != nullptr, "Failed to find region for block");
- if (!region->ehBailoutData)
- {
- region->AllocateEHBailoutData(this->func, tryInstr);
- }
- // Record the region in the block-to-region map.
- blockToRegion[block->GetBlockNum()] = region;
- if (firstInstr->IsLabelInstr())
- {
- // Record the region on the label and make sure it stays around as a region
- // marker if we're entering a region at this point.
- IR::LabelInstr * labelInstr = firstInstr->AsLabelInstr();
- labelInstr->SetRegion(region);
- if (region != predRegion)
- {
- labelInstr->m_hasNonBranchRef = true;
- }
- }
- }
- Region *
- FlowGraph::PropagateRegionFromPred(BasicBlock * block, BasicBlock * predBlock, Region * predRegion, IR::Instr * &tryInstr)
- {
- // Propagate predRegion to region, looking at the flow transition for an opcode
- // that affects the region.
- Region * region = nullptr;
- IR::Instr * predLastInstr = predBlock->GetLastInstr();
- IR::Instr * firstInstr = block->GetFirstInstr();
- if (predLastInstr == nullptr)
- {
- // Empty block: trivially propagate the region.
- region = predRegion;
- }
- else
- {
- Region * tryRegion = nullptr;
- IR::LabelInstr * tryInstrNext = nullptr;
- switch (predLastInstr->m_opcode)
- {
- case Js::OpCode::TryCatch:
- // Entry to a try-catch. See whether we're entering the try or the catch
- // by looking for the handler label.
- Assert(predLastInstr->m_next->IsLabelInstr());
- tryInstrNext = predLastInstr->m_next->AsLabelInstr();
- tryRegion = tryInstrNext->GetRegion();
- if (firstInstr == predLastInstr->AsBranchInstr()->GetTarget())
- {
- region = Region::New(RegionTypeCatch, predRegion, this->func);
- Assert(tryRegion);
- region->SetMatchingTryRegion(tryRegion);
- tryRegion->SetMatchingCatchRegion(region);
- }
- else
- {
- region = Region::New(RegionTypeTry, predRegion, this->func);
- tryInstr = predLastInstr;
- }
- break;
- case Js::OpCode::TryFinally:
- // Entry to a try-finally. See whether we're entering the try or the finally
- // by looking for the handler label.
- Assert(predLastInstr->m_next->IsLabelInstr());
- tryInstrNext = predLastInstr->m_next->AsLabelInstr();
- tryRegion = tryInstrNext->GetRegion();
- if (firstInstr == predLastInstr->AsBranchInstr()->GetTarget())
- {
- region = Region::New(RegionTypeFinally, predRegion, this->func);
- Assert(tryRegion);
- region->SetMatchingTryRegion(tryRegion);
- tryRegion->SetMatchingFinallyRegion(region);
- }
- else
- {
- region = Region::New(RegionTypeTry, predRegion, this->func);
- tryInstr = predLastInstr;
- }
- break;
- case Js::OpCode::Leave:
- case Js::OpCode::LeaveNull:
- // Exiting a try or handler. Retrieve the current region's parent.
- region = predRegion->GetParent();
- if (region == nullptr)
- {
- // We found a Leave in the root region- this can only happen when a jitted loop body
- // in a try block has a return statement.
- Assert(this->func->IsLoopBodyInTry());
- predLastInstr->AsBranchInstr()->m_isOrphanedLeave = true;
- region = predRegion;
- }
- break;
- default:
- // Normal (non-EH) transition: just propagate the region.
- region = predRegion;
- break;
- }
- }
- return region;
- }
- void
- FlowGraph::InsertCompBlockToLoopList(Loop *loop, BasicBlock* compBlock, BasicBlock* targetBlock, bool postTarget)
- {
- if (loop)
- {
- bool found = false;
- FOREACH_BLOCK_IN_LOOP_EDITING(loopBlock, loop, iter)
- {
- if (loopBlock == targetBlock)
- {
- found = true;
- break;
- }
- } NEXT_BLOCK_IN_LOOP_EDITING;
- if (found)
- {
- if (postTarget)
- {
- iter.Next();
- }
- iter.InsertBefore(compBlock);
- }
- InsertCompBlockToLoopList(loop->parent, compBlock, targetBlock, postTarget);
- }
- }
- // Insert a block on the given edge
- BasicBlock *
- FlowGraph::InsertAirlockBlock(FlowEdge * edge)
- {
- BasicBlock * airlockBlock = BasicBlock::New(this);
- BasicBlock * sourceBlock = edge->GetPred();
- BasicBlock * sinkBlock = edge->GetSucc();
- BasicBlock * sinkPrevBlock = sinkBlock->prev;
- IR::Instr * sinkPrevBlockLastInstr = sinkPrevBlock->GetLastInstr();
- IR::Instr * sourceLastInstr = sourceBlock->GetLastInstr();
- airlockBlock->loop = sinkBlock->loop;
- airlockBlock->SetBlockNum(this->blockCount++);
- #ifdef DBG
- airlockBlock->isAirLockBlock = true;
- #endif
- //
- // Fixup block linkage
- //
- // airlock block is inserted right before sourceBlock
- airlockBlock->prev = sinkBlock->prev;
- sinkBlock->prev = airlockBlock;
- airlockBlock->next = sinkBlock;
- airlockBlock->prev->next = airlockBlock;
- //
- // Fixup flow edges
- //
- sourceBlock->RemoveSucc(sinkBlock, this, false);
- // Add sourceBlock -> airlockBlock
- this->AddEdge(sourceBlock, airlockBlock);
- // Add airlockBlock -> sinkBlock
- edge->SetPred(airlockBlock);
- airlockBlock->AddSucc(edge, this);
- // Fixup data use count
- airlockBlock->SetDataUseCount(1);
- sourceBlock->DecrementDataUseCount();
- //
- // Fixup IR
- //
- // Maintain the instruction region for inlining
- IR::LabelInstr *sinkLabel = sinkBlock->GetFirstInstr()->AsLabelInstr();
- Func * sinkLabelFunc = sinkLabel->m_func;
- IR::LabelInstr *airlockLabel = IR::LabelInstr::New(Js::OpCode::Label, sinkLabelFunc);
- sinkPrevBlockLastInstr->InsertAfter(airlockLabel);
- airlockBlock->SetFirstInstr(airlockLabel);
- airlockLabel->SetBasicBlock(airlockBlock);
- // Add br to sinkBlock from airlock block
- IR::BranchInstr *airlockBr = IR::BranchInstr::New(Js::OpCode::Br, sinkLabel, sinkLabelFunc);
- airlockBr->SetByteCodeOffset(sinkLabel);
- airlockLabel->InsertAfter(airlockBr);
- airlockBlock->SetLastInstr(airlockBr);
- airlockLabel->SetByteCodeOffset(sinkLabel);
- // Fixup flow out of sourceBlock
- IR::BranchInstr *sourceBr = sourceLastInstr->AsBranchInstr();
- if (sourceBr->IsMultiBranch())
- {
- const bool replaced = sourceBr->AsMultiBrInstr()->ReplaceTarget(sinkLabel, airlockLabel);
- Assert(replaced);
- }
- else if (sourceBr->GetTarget() == sinkLabel)
- {
- sourceBr->SetTarget(airlockLabel);
- }
- if (!sinkPrevBlockLastInstr->IsBranchInstr() || sinkPrevBlockLastInstr->AsBranchInstr()->HasFallThrough())
- {
- if (!sinkPrevBlock->isDeleted)
- {
- FlowEdge *dstEdge = this->FindEdge(sinkPrevBlock, sinkBlock);
- if (dstEdge) // Possibility that sourceblock may be same as sinkPrevBlock
- {
- BasicBlock* compensationBlock = this->InsertCompensationCodeForBlockMove(dstEdge, true /*insert comp block to loop list*/, true);
- compensationBlock->IncrementDataUseCount();
- // We need to skip airlock compensation block in globopt as its inserted while globopt is iteration over the blocks.
- compensationBlock->isAirLockCompensationBlock = true;
- }
- }
- }
- #if DBG_DUMP
- this->Dump(true, _u("\n After insertion of airlock block \n"));
- #endif
- return airlockBlock;
- }
- // Insert a block on the given edge
- BasicBlock *
- FlowGraph::InsertCompensationCodeForBlockMove(FlowEdge * edge, bool insertToLoopList, bool sinkBlockLoop)
- {
- BasicBlock * compBlock = BasicBlock::New(this);
- BasicBlock * sourceBlock = edge->GetPred();
- BasicBlock * sinkBlock = edge->GetSucc();
- BasicBlock * fallthroughBlock = sourceBlock->next;
- IR::Instr * sourceLastInstr = sourceBlock->GetLastInstr();
- compBlock->SetBlockNum(this->blockCount++);
- if (insertToLoopList)
- {
- // For flow graph edits in
- if (sinkBlockLoop)
- {
- if (sinkBlock->loop && sinkBlock->loop->GetHeadBlock() == sinkBlock)
- {
- // BLUE 531255: sinkblock may be the head block of new loop, we shouldn't insert compensation block to that loop
- // Insert it to all the parent loop lists.
- compBlock->loop = sinkBlock->loop->parent;
- InsertCompBlockToLoopList(compBlock->loop, compBlock, sinkBlock, false);
- }
- else
- {
- compBlock->loop = sinkBlock->loop;
- InsertCompBlockToLoopList(compBlock->loop, compBlock, sinkBlock, false); // sinkBlock or fallthroughBlock?
- }
- #ifdef DBG
- compBlock->isBreakCompensationBlockAtSink = true;
- #endif
- }
- else
- {
- compBlock->loop = sourceBlock->loop;
- InsertCompBlockToLoopList(compBlock->loop, compBlock, sourceBlock, true);
- #ifdef DBG
- compBlock->isBreakCompensationBlockAtSource = true;
- #endif
- }
- }
- //
- // Fixup block linkage
- //
- // compensation block is inserted right after sourceBlock
- compBlock->next = fallthroughBlock;
- fallthroughBlock->prev = compBlock;
- compBlock->prev = sourceBlock;
- sourceBlock->next = compBlock;
- //
- // Fixup flow edges
- //
- sourceBlock->RemoveSucc(sinkBlock, this, false);
- // Add sourceBlock -> airlockBlock
- this->AddEdge(sourceBlock, compBlock);
- // Add airlockBlock -> sinkBlock
- edge->SetPred(compBlock);
- compBlock->AddSucc(edge, this);
- //
- // Fixup IR
- //
- // Maintain the instruction region for inlining
- IR::LabelInstr *sinkLabel = sinkBlock->GetFirstInstr()->AsLabelInstr();
- Func * sinkLabelFunc = sinkLabel->m_func;
- IR::LabelInstr *compLabel = IR::LabelInstr::New(Js::OpCode::Label, sinkLabelFunc);
- sourceLastInstr->InsertAfter(compLabel);
- compBlock->SetFirstInstr(compLabel);
- compLabel->SetBasicBlock(compBlock);
- // Add br to sinkBlock from compensation block
- IR::BranchInstr *compBr = IR::BranchInstr::New(Js::OpCode::Br, sinkLabel, sinkLabelFunc);
- compBr->SetByteCodeOffset(sinkLabel);
- compLabel->InsertAfter(compBr);
- compBlock->SetLastInstr(compBr);
- compLabel->SetByteCodeOffset(sinkLabel);
- // Fixup flow out of sourceBlock
- if (sourceLastInstr->IsBranchInstr())
- {
- IR::BranchInstr *sourceBr = sourceLastInstr->AsBranchInstr();
- Assert(sourceBr->IsMultiBranch() || sourceBr->IsConditional());
- if (sourceBr->IsMultiBranch())
- {
- const bool replaced = sourceBr->AsMultiBrInstr()->ReplaceTarget(sinkLabel, compLabel);
- Assert(replaced);
- }
- }
- return compBlock;
- }
- void
- FlowGraph::RemoveUnreachableBlocks()
- {
- AnalysisAssert(this->blockList);
- FOREACH_BLOCK(block, this)
- {
- block->isVisited = false;
- }
- NEXT_BLOCK;
- this->blockList->isVisited = true;
- FOREACH_BLOCK_EDITING(block, this)
- {
- if (block->isVisited)
- {
- FOREACH_SUCCESSOR_BLOCK(succ, block)
- {
- succ->isVisited = true;
- } NEXT_SUCCESSOR_BLOCK;
- }
- else
- {
- this->RemoveBlock(block);
- }
- }
- NEXT_BLOCK_EDITING;
- }
- // If block has no predecessor, remove it.
- bool
- FlowGraph::RemoveUnreachableBlock(BasicBlock *block, GlobOpt * globOpt)
- {
- bool isDead = false;
- if ((block->GetPredList() == nullptr || block->GetPredList()->Empty()) && block != this->func->m_fg->blockList)
- {
- isDead = true;
- }
- else if (block->isLoopHeader)
- {
- // A dead loop still has back-edges pointing to it...
- isDead = true;
- FOREACH_PREDECESSOR_BLOCK(pred, block)
- {
- if (!block->loop->IsDescendentOrSelf(pred->loop))
- {
- isDead = false;
- }
- } NEXT_PREDECESSOR_BLOCK;
- }
- if (isDead)
- {
- this->RemoveBlock(block, globOpt);
- return true;
- }
- return false;
- }
- IR::Instr *
- FlowGraph::PeepTypedCm(IR::Instr *instr)
- {
- // Basic pattern, peep:
- // t1 = CmEq a, b
- // BrTrue_I4 $L1, t1
- // Into:
- // t1 = 1
- // BrEq $L1, a, b
- // t1 = 0
- IR::Instr * instrNext = instr->GetNextRealInstrOrLabel();
- // find intermediate Lds
- IR::Instr * instrLd = nullptr;
- if (instrNext->m_opcode == Js::OpCode::Ld_I4)
- {
- instrLd = instrNext;
- instrNext = instrNext->GetNextRealInstrOrLabel();
- }
- IR::Instr * instrLd2 = nullptr;
- if (instrNext->m_opcode == Js::OpCode::Ld_I4)
- {
- instrLd2 = instrNext;
- instrNext = instrNext->GetNextRealInstrOrLabel();
- }
- // Find BrTrue/BrFalse
- IR::Instr *instrBr;
- bool brIsTrue;
- if (instrNext->m_opcode == Js::OpCode::BrTrue_I4)
- {
- instrBr = instrNext;
- brIsTrue = true;
- }
- else if (instrNext->m_opcode == Js::OpCode::BrFalse_I4)
- {
- instrBr = instrNext;
- brIsTrue = false;
- }
- else
- {
- return nullptr;
- }
- AssertMsg(instrLd || (!instrLd && !instrLd2), "Either instrLd is non-null or both null");
- // if we have intermediate Lds, then make sure pattern is:
- // t1 = CmEq a, b
- // t2 = Ld_A t1
- // BrTrue $L1, t2
- if (instrLd && !instrLd->GetSrc1()->IsEqual(instr->GetDst()))
- {
- return nullptr;
- }
- if (instrLd2 && !instrLd2->GetSrc1()->IsEqual(instrLd->GetDst()))
- {
- return nullptr;
- }
- // Make sure we have:
- // t1 = CmEq a, b
- // BrTrue/BrFalse t1
- if (!(instr->GetDst()->IsEqual(instrBr->GetSrc1()) || (instrLd && instrLd->GetDst()->IsEqual(instrBr->GetSrc1())) || (instrLd2 && instrLd2->GetDst()->IsEqual(instrBr->GetSrc1()))))
- {
- return nullptr;
- }
- IR::Opnd * src1 = instr->UnlinkSrc1();
- IR::Opnd * src2 = instr->UnlinkSrc2();
- IR::Instr * instrNew;
- IR::Opnd * tmpOpnd;
- if (instr->GetDst()->IsEqual(src1) || (instrLd && instrLd->GetDst()->IsEqual(src1)) || (instrLd2 && instrLd2->GetDst()->IsEqual(src1)))
- {
- Assert(src1->IsInt32());
- tmpOpnd = IR::RegOpnd::New(TyInt32, instr->m_func);
- instrNew = IR::Instr::New(Js::OpCode::Ld_I4, tmpOpnd, src1, instr->m_func);
- instrNew->SetByteCodeOffset(instr);
- instr->InsertBefore(instrNew);
- src1 = tmpOpnd;
- }
- if (instr->GetDst()->IsEqual(src2) || (instrLd && instrLd->GetDst()->IsEqual(src2)) || (instrLd2 && instrLd2->GetDst()->IsEqual(src2)))
- {
- Assert(src2->IsInt32());
- tmpOpnd = IR::RegOpnd::New(TyInt32, instr->m_func);
- instrNew = IR::Instr::New(Js::OpCode::Ld_I4, tmpOpnd, src2, instr->m_func);
- instrNew->SetByteCodeOffset(instr);
- instr->InsertBefore(instrNew);
- src2 = tmpOpnd;
- }
- instrBr->ReplaceSrc1(src1);
- instrBr->SetSrc2(src2);
- Js::OpCode newOpcode;
- switch (instr->m_opcode)
- {
- case Js::OpCode::CmEq_I4:
- newOpcode = Js::OpCode::BrEq_I4;
- break;
- case Js::OpCode::CmGe_I4:
- newOpcode = Js::OpCode::BrGe_I4;
- break;
- case Js::OpCode::CmGt_I4:
- newOpcode = Js::OpCode::BrGt_I4;
- break;
- case Js::OpCode::CmLt_I4:
- newOpcode = Js::OpCode::BrLt_I4;
- break;
- case Js::OpCode::CmLe_I4:
- newOpcode = Js::OpCode::BrLe_I4;
- break;
- case Js::OpCode::CmUnGe_I4:
- newOpcode = Js::OpCode::BrUnGe_I4;
- break;
- case Js::OpCode::CmUnGt_I4:
- newOpcode = Js::OpCode::BrUnGt_I4;
- break;
- case Js::OpCode::CmUnLt_I4:
- newOpcode = Js::OpCode::BrUnLt_I4;
- break;
- case Js::OpCode::CmUnLe_I4:
- newOpcode = Js::OpCode::BrUnLe_I4;
- break;
- case Js::OpCode::CmNeq_I4:
- newOpcode = Js::OpCode::BrNeq_I4;
- break;
- case Js::OpCode::CmEq_A:
- newOpcode = Js::OpCode::BrEq_A;
- break;
- case Js::OpCode::CmGe_A:
- newOpcode = Js::OpCode::BrGe_A;
- break;
- case Js::OpCode::CmGt_A:
- newOpcode = Js::OpCode::BrGt_A;
- break;
- case Js::OpCode::CmLt_A:
- newOpcode = Js::OpCode::BrLt_A;
- break;
- case Js::OpCode::CmLe_A:
- newOpcode = Js::OpCode::BrLe_A;
- break;
- case Js::OpCode::CmUnGe_A:
- newOpcode = Js::OpCode::BrUnGe_A;
- break;
- case Js::OpCode::CmUnGt_A:
- newOpcode = Js::OpCode::BrUnGt_A;
- break;
- case Js::OpCode::CmUnLt_A:
- newOpcode = Js::OpCode::BrUnLt_A;
- break;
- case Js::OpCode::CmUnLe_A:
- newOpcode = Js::OpCode::BrUnLe_A;
- break;
- case Js::OpCode::CmNeq_A:
- newOpcode = Js::OpCode::BrNeq_A;
- break;
- case Js::OpCode::CmSrEq_A:
- newOpcode = Js::OpCode::BrSrEq_A;
- break;
- case Js::OpCode::CmSrNeq_A:
- newOpcode = Js::OpCode::BrSrNeq_A;
- break;
- default:
- newOpcode = Js::OpCode::InvalidOpCode;
- Assume(UNREACHED);
- }
- instrBr->m_opcode = newOpcode;
- if (brIsTrue)
- {
- instr->SetSrc1(IR::IntConstOpnd::New(1, TyInt8, instr->m_func));
- instr->m_opcode = Js::OpCode::Ld_I4;
- instrNew = IR::Instr::New(Js::OpCode::Ld_I4, instr->GetDst(), IR::IntConstOpnd::New(0, TyInt8, instr->m_func), instr->m_func);
- instrNew->SetByteCodeOffset(instrBr);
- instrBr->InsertAfter(instrNew);
- if (instrLd)
- {
- instrLd->ReplaceSrc1(IR::IntConstOpnd::New(1, TyInt8, instr->m_func));
- instrNew = IR::Instr::New(Js::OpCode::Ld_I4, instrLd->GetDst(), IR::IntConstOpnd::New(0, TyInt8, instr->m_func), instr->m_func);
- instrNew->SetByteCodeOffset(instrBr);
- instrBr->InsertAfter(instrNew);
- if (instrLd2)
- {
- instrLd2->ReplaceSrc1(IR::IntConstOpnd::New(1, TyInt8, instr->m_func));
- instrNew = IR::Instr::New(Js::OpCode::Ld_I4, instrLd2->GetDst(), IR::IntConstOpnd::New(0, TyInt8, instr->m_func), instr->m_func);
- instrNew->SetByteCodeOffset(instrBr);
- instrBr->InsertAfter(instrNew);
- }
- }
- }
- else
- {
- instrBr->AsBranchInstr()->Invert();
- instr->SetSrc1(IR::IntConstOpnd::New(0, TyInt8, instr->m_func));
- instr->m_opcode = Js::OpCode::Ld_I4;
- instrNew = IR::Instr::New(Js::OpCode::Ld_I4, instr->GetDst(), IR::IntConstOpnd::New(1, TyInt8, instr->m_func), instr->m_func);
- instrNew->SetByteCodeOffset(instrBr);
- instrBr->InsertAfter(instrNew);
- if (instrLd)
- {
- instrLd->ReplaceSrc1(IR::IntConstOpnd::New(0, TyInt8, instr->m_func));
- instrNew = IR::Instr::New(Js::OpCode::Ld_I4, instrLd->GetDst(), IR::IntConstOpnd::New(1, TyInt8, instr->m_func), instr->m_func);
- instrNew->SetByteCodeOffset(instrBr);
- instrBr->InsertAfter(instrNew);
- if (instrLd2)
- {
- instrLd2->ReplaceSrc1(IR::IntConstOpnd::New(0, TyInt8, instr->m_func));
- instrNew = IR::Instr::New(Js::OpCode::Ld_I4, instrLd2->GetDst(), IR::IntConstOpnd::New(1, TyInt8, instr->m_func), instr->m_func);
- instrNew->SetByteCodeOffset(instrBr);
- instrBr->InsertAfter(instrNew);
- }
- }
- }
- return instrBr;
- }
- IR::Instr *
- FlowGraph::PeepCm(IR::Instr *instr)
- {
- // Basic pattern, peep:
- // t1 = CmEq a, b
- // t2 = Ld_A t1
- // BrTrue $L1, t2
- // Into:
- // t1 = True
- // t2 = True
- // BrEq $L1, a, b
- // t1 = False
- // t2 = False
- //
- // The true/false Ld_A's will most likely end up being dead-stores...
- // Alternate Pattern
- // t1= CmEq a, b
- // BrTrue $L1, t1
- // Into:
- // BrEq $L1, a, b
- Func *func = instr->m_func;
- // Find Ld_A
- IR::Instr *instrNext = instr->GetNextRealInstrOrLabel();
- IR::Instr *inlineeEndInstr = nullptr;
- IR::Instr *instrNew;
- IR::Instr *instrLd = nullptr, *instrLd2 = nullptr;
- IR::Instr *instrByteCode = instrNext;
- bool ldFound = false;
- IR::Opnd *brSrc = instr->GetDst();
- if (instrNext->m_opcode == Js::OpCode::Ld_A && instrNext->GetSrc1()->IsEqual(instr->GetDst()))
- {
- ldFound = true;
- instrLd = instrNext;
- brSrc = instrNext->GetDst();
- if (brSrc->IsEqual(instr->GetSrc1()) || brSrc->IsEqual(instr->GetSrc2()))
- {
- return nullptr;
- }
- instrNext = instrLd->GetNextRealInstrOrLabel();
- // Is there a second Ld_A?
- if (instrNext->m_opcode == Js::OpCode::Ld_A && instrNext->GetSrc1()->IsEqual(brSrc))
- {
- // We have:
- // t1 = Cm
- // t2 = t1 // ldSrc = t1
- // t3 = t2 // ldDst = t3
- // BrTrue/BrFalse t3
- instrLd2 = instrNext;
- brSrc = instrLd2->GetDst();
- instrNext = instrLd2->GetNextRealInstrOrLabel();
- if (brSrc->IsEqual(instr->GetSrc1()) || brSrc->IsEqual(instr->GetSrc2()))
- {
- return nullptr;
- }
- }
- }
- // Skip over InlineeEnd
- if (instrNext->m_opcode == Js::OpCode::InlineeEnd)
- {
- inlineeEndInstr = instrNext;
- instrNext = inlineeEndInstr->GetNextRealInstrOrLabel();
- }
- // Find BrTrue/BrFalse
- bool brIsTrue;
- if (instrNext->m_opcode == Js::OpCode::BrTrue_A)
- {
- brIsTrue = true;
- }
- else if (instrNext->m_opcode == Js::OpCode::BrFalse_A)
- {
- brIsTrue = false;
- }
- else
- {
- return nullptr;
- }
- IR::Instr *instrBr = instrNext;
- // Make sure we have:
- // t1 = Ld_A
- // BrTrue/BrFalse t1
- if (!instr->GetDst()->IsEqual(instrBr->GetSrc1()) && !brSrc->IsEqual(instrBr->GetSrc1()))
- {
- return nullptr;
- }
- //
- // We have a match. Generate the new branch
- //
- // BrTrue/BrFalse t1
- // Keep a copy of the inliner func and the bytecode offset of the original BrTrue/BrFalse if we end up inserting a new branch out of the inlinee,
- // and sym id of t1 for proper restoration on a bailout before the branch.
- Func* origBrFunc = instrBr->m_func;
- uint32 origBrByteCodeOffset = instrBr->GetByteCodeOffset();
- uint32 origBranchSrcSymId = instrBr->GetSrc1()->GetStackSym()->m_id;
- bool origBranchSrcOpndIsJITOpt = instrBr->GetSrc1()->GetIsJITOptimizedReg();
- instrBr->Unlink();
- instr->InsertBefore(instrBr);
- instrBr->ClearByteCodeOffset();
- instrBr->SetByteCodeOffset(instr);
- instrBr->FreeSrc1();
- instrBr->SetSrc1(instr->UnlinkSrc1());
- instrBr->SetSrc2(instr->UnlinkSrc2());
- instrBr->m_func = instr->m_func;
- Js::OpCode newOpcode;
- switch(instr->m_opcode)
- {
- case Js::OpCode::CmEq_A:
- newOpcode = Js::OpCode::BrEq_A;
- break;
- case Js::OpCode::CmGe_A:
- newOpcode = Js::OpCode::BrGe_A;
- break;
- case Js::OpCode::CmGt_A:
- newOpcode = Js::OpCode::BrGt_A;
- break;
- case Js::OpCode::CmLt_A:
- newOpcode = Js::OpCode::BrLt_A;
- break;
- case Js::OpCode::CmLe_A:
- newOpcode = Js::OpCode::BrLe_A;
- break;
- case Js::OpCode::CmUnGe_A:
- newOpcode = Js::OpCode::BrUnGe_A;
- break;
- case Js::OpCode::CmUnGt_A:
- newOpcode = Js::OpCode::BrUnGt_A;
- break;
- case Js::OpCode::CmUnLt_A:
- newOpcode = Js::OpCode::BrUnLt_A;
- break;
- case Js::OpCode::CmUnLe_A:
- newOpcode = Js::OpCode::BrUnLe_A;
- break;
- case Js::OpCode::CmNeq_A:
- newOpcode = Js::OpCode::BrNeq_A;
- break;
- case Js::OpCode::CmSrEq_A:
- newOpcode = Js::OpCode::BrSrEq_A;
- break;
- case Js::OpCode::CmSrNeq_A:
- newOpcode = Js::OpCode::BrSrNeq_A;
- break;
- default:
- Assert(UNREACHED);
- __assume(UNREACHED);
- }
- instrBr->m_opcode = newOpcode;
- IR::AddrOpnd* trueOpnd = IR::AddrOpnd::New(func->GetScriptContextInfo()->GetTrueAddr(), IR::AddrOpndKindDynamicVar, func, true);
- IR::AddrOpnd* falseOpnd = IR::AddrOpnd::New(func->GetScriptContextInfo()->GetFalseAddr(), IR::AddrOpndKindDynamicVar, func, true);
- trueOpnd->SetValueType(ValueType::Boolean);
- falseOpnd->SetValueType(ValueType::Boolean);
- if (ldFound)
- {
- // Split Ld_A into "Ld_A TRUE"/"Ld_A FALSE"
- if (brIsTrue)
- {
- instrNew = IR::Instr::New(Js::OpCode::Ld_A, instrLd->GetSrc1(), trueOpnd, instrBr->m_func);
- instrNew->SetByteCodeOffset(instrBr);
- instrNew->GetDst()->AsRegOpnd()->m_fgPeepTmp = true;
- instrBr->InsertBefore(instrNew);
- instrNew = IR::Instr::New(Js::OpCode::Ld_A, instrLd->GetDst(), trueOpnd, instrBr->m_func);
- instrNew->SetByteCodeOffset(instrBr);
- instrNew->GetDst()->AsRegOpnd()->m_fgPeepTmp = true;
- instrBr->InsertBefore(instrNew);
- instrNew = IR::Instr::New(Js::OpCode::Ld_A, instrLd->GetSrc1(), falseOpnd, instrLd->m_func);
- instrLd->InsertBefore(instrNew);
- instrNew->SetByteCodeOffset(instrLd);
- instrNew->GetDst()->AsRegOpnd()->m_fgPeepTmp = true;
- instrLd->ReplaceSrc1(falseOpnd);
- if (instrLd2)
- {
- instrLd2->ReplaceSrc1(falseOpnd);
- instrNew = IR::Instr::New(Js::OpCode::Ld_A, instrLd2->GetDst(), trueOpnd, instrBr->m_func);
- instrBr->InsertBefore(instrNew);
- instrNew->SetByteCodeOffset(instrBr);
- instrNew->GetDst()->AsRegOpnd()->m_fgPeepTmp = true;
- }
- }
- else
- {
- instrBr->AsBranchInstr()->Invert();
- instrNew = IR::Instr::New(Js::OpCode::Ld_A, instrLd->GetSrc1(), falseOpnd, instrBr->m_func);
- instrBr->InsertBefore(instrNew);
- instrNew->SetByteCodeOffset(instrBr);
- instrNew->GetDst()->AsRegOpnd()->m_fgPeepTmp = true;
- instrNew = IR::Instr::New(Js::OpCode::Ld_A, instrLd->GetDst(), falseOpnd, instrBr->m_func);
- instrBr->InsertBefore(instrNew);
- instrNew->SetByteCodeOffset(instrBr);
- instrNew->GetDst()->AsRegOpnd()->m_fgPeepTmp = true;
- instrNew = IR::Instr::New(Js::OpCode::Ld_A, instrLd->GetSrc1(), trueOpnd, instrLd->m_func);
- instrLd->InsertBefore(instrNew);
- instrNew->SetByteCodeOffset(instrLd);
- instrLd->ReplaceSrc1(trueOpnd);
- instrNew->GetDst()->AsRegOpnd()->m_fgPeepTmp = true;
- if (instrLd2)
- {
- instrLd2->ReplaceSrc1(trueOpnd);
- instrNew = IR::Instr::New(Js::OpCode::Ld_A, instrLd->GetSrc1(), trueOpnd, instrBr->m_func);
- instrBr->InsertBefore(instrNew);
- instrNew->SetByteCodeOffset(instrBr);
- instrNew->GetDst()->AsRegOpnd()->m_fgPeepTmp = true;
- }
- }
- }
- // Fix InlineeEnd
- if (inlineeEndInstr)
- {
- this->InsertInlineeOnFLowEdge(instrBr->AsBranchInstr(), inlineeEndInstr, instrByteCode , origBrFunc, origBrByteCodeOffset, origBranchSrcOpndIsJITOpt, origBranchSrcSymId);
- }
- if (instr->GetDst()->AsRegOpnd()->m_sym->HasByteCodeRegSlot())
- {
- Assert(!instrBr->AsBranchInstr()->HasByteCodeReg());
- StackSym *dstSym = instr->GetDst()->AsRegOpnd()->m_sym;
- instrBr->AsBranchInstr()->SetByteCodeReg(dstSym->GetByteCodeRegSlot());
- }
- instr->Remove();
- //
- // Try optimizing through a second branch.
- // Peep:
- //
- // t2 = True;
- // BrTrue $L1
- // ...
- // L1:
- // t1 = Ld_A t2
- // BrTrue $L2
- //
- // Into:
- // t2 = True;
- // t1 = True;
- // BrTrue $L2 <---
- // ...
- // L1:
- // t1 = Ld_A t2
- // BrTrue $L2
- //
- // This cleanup helps expose second level Cm peeps.
- IR::Instr *instrLd3 = instrBr->AsBranchInstr()->GetTarget()->GetNextRealInstrOrLabel();
- // Skip over branch to branch
- while (instrLd3->m_opcode == Js::OpCode::Br)
- {
- instrLd3 = instrLd3->AsBranchInstr()->GetTarget()->GetNextRealInstrOrLabel();
- }
- // Find Ld_A
- if (instrLd3->m_opcode != Js::OpCode::Ld_A)
- {
- return instrBr;
- }
- IR::Instr *instrBr2 = instrLd3->GetNextRealInstrOrLabel();
- IR::Instr *inlineeEndInstr2 = nullptr;
- // InlineeEnd?
- // REVIEW: Can we handle 2 inlineeEnds?
- if (instrBr2->m_opcode == Js::OpCode::InlineeEnd && !inlineeEndInstr)
- {
- inlineeEndInstr2 = instrBr2;
- instrBr2 = instrBr2->GetNextRealInstrOrLabel();
- }
- // Find branch
- bool brIsTrue2;
- if (instrBr2->m_opcode == Js::OpCode::BrTrue_A)
- {
- brIsTrue2 = true;
- }
- else if (instrBr2->m_opcode == Js::OpCode::BrFalse_A)
- {
- brIsTrue2 = false;
- }
- else
- {
- return nullptr;
- }
- // Make sure Ld_A operates on the right tmps.
- if (!instrLd3->GetDst()->IsEqual(instrBr2->GetSrc1()) || !brSrc->IsEqual(instrLd3->GetSrc1()))
- {
- return nullptr;
- }
- if (instrLd3->GetDst()->IsEqual(instrBr->GetSrc1()) || instrLd3->GetDst()->IsEqual(instrBr->GetSrc2()))
- {
- return nullptr;
- }
- // Make sure that the reg we're assigning to is not live in the intervening instructions (if this is a forward branch).
- if (instrLd3->GetByteCodeOffset() > instrBr->GetByteCodeOffset())
- {
- StackSym *symLd3 = instrLd3->GetDst()->AsRegOpnd()->m_sym;
- if (IR::Instr::FindRegUseInRange(symLd3, instrBr->m_next, instrLd3))
- {
- return nullptr;
- }
- }
- //
- // We have a match!
- //
- if(inlineeEndInstr2)
- {
- origBrFunc = instrBr2->m_func;
- origBrByteCodeOffset = instrBr2->GetByteCodeOffset();
- origBranchSrcSymId = instrBr2->GetSrc1()->GetStackSym()->m_id;
- }
- // Fix Ld_A
- if (brIsTrue)
- {
- instrNew = IR::Instr::New(Js::OpCode::Ld_A, instrLd3->GetDst(), trueOpnd, instrBr->m_func);
- instrBr->InsertBefore(instrNew);
- instrNew->SetByteCodeOffset(instrBr);
- instrNew->GetDst()->AsRegOpnd()->m_fgPeepTmp = true;
- }
- else
- {
- instrNew = IR::Instr::New(Js::OpCode::Ld_A, instrLd3->GetDst(), falseOpnd, instrBr->m_func);
- instrBr->InsertBefore(instrNew);
- instrNew->SetByteCodeOffset(instrBr);
- instrNew->GetDst()->AsRegOpnd()->m_fgPeepTmp = true;
- }
- IR::LabelInstr *brTarget2;
- // Retarget branch
- if (brIsTrue2 == brIsTrue)
- {
- brTarget2 = instrBr2->AsBranchInstr()->GetTarget();
- }
- else
- {
- brTarget2 = IR::LabelInstr::New(Js::OpCode::Label, instrBr2->m_func);
- brTarget2->SetByteCodeOffset(instrBr2->m_next);
- instrBr2->InsertAfter(brTarget2);
- }
- instrBr->AsBranchInstr()->SetTarget(brTarget2);
- // InlineeEnd?
- if (inlineeEndInstr2)
- {
- this->InsertInlineeOnFLowEdge(instrBr->AsBranchInstr(), inlineeEndInstr2, instrByteCode, origBrFunc, origBrByteCodeOffset, origBranchSrcOpndIsJITOpt, origBranchSrcSymId);
- }
- return instrBr;
- }
- void
- FlowGraph::InsertInlineeOnFLowEdge(IR::BranchInstr *instrBr, IR::Instr *inlineeEndInstr, IR::Instr *instrBytecode, Func* origBrFunc, uint32 origByteCodeOffset, bool origBranchSrcOpndIsJITOpt, uint32 origBranchSrcSymId)
- {
- // Helper for PeepsCm code.
- //
- // We've skipped some InlineeEnd. Globopt expects to see these
- // on all flow paths out of the inlinee. Insert an InlineeEnd
- // on the new path:
- // BrEq $L1, a, b
- // Becomes:
- // BrNeq $L2, a, b
- // InlineeEnd
- // Br $L1
- // L2:
- instrBr->AsBranchInstr()->Invert();
- IR::BranchInstr *newBr = IR::BranchInstr::New(Js::OpCode::Br, instrBr->AsBranchInstr()->GetTarget(), origBrFunc);
- newBr->SetByteCodeOffset(origByteCodeOffset);
- instrBr->InsertAfter(newBr);
- IR::LabelInstr *newLabel = IR::LabelInstr::New(Js::OpCode::Label, instrBr->m_func);
- newLabel->SetByteCodeOffset(instrBytecode);
- newBr->InsertAfter(newLabel);
- instrBr->AsBranchInstr()->SetTarget(newLabel);
- IR::Instr *newInlineeEnd = IR::Instr::New(Js::OpCode::InlineeEnd, inlineeEndInstr->m_func);
- newInlineeEnd->SetSrc1(inlineeEndInstr->GetSrc1());
- newInlineeEnd->SetSrc2(inlineeEndInstr->GetSrc2());
- newInlineeEnd->SetByteCodeOffset(instrBytecode);
- newInlineeEnd->SetIsCloned(true); // Mark it as cloned - this is used later by the inlinee args optimization
- newBr->InsertBefore(newInlineeEnd);
- IR::ByteCodeUsesInstr * useOrigBranchSrcInstr = IR::ByteCodeUsesInstr::New(origBrFunc, origByteCodeOffset);
- useOrigBranchSrcInstr->SetRemovedOpndSymbol(origBranchSrcOpndIsJITOpt, origBranchSrcSymId);
- newBr->InsertBefore(useOrigBranchSrcInstr);
- uint newBrFnNumber = newBr->m_func->GetFunctionNumber();
- Assert(newBrFnNumber == origBrFunc->GetFunctionNumber());
- // The function numbers of the new branch and the inlineeEnd instruction should be different (ensuring that the new branch is not added in the inlinee but in the inliner).
- // Only case when they can be same is recursive calls - inlinee and inliner are the same function
- Assert(newBrFnNumber != inlineeEndInstr->m_func->GetFunctionNumber() ||
- newBrFnNumber == inlineeEndInstr->m_func->GetParentFunc()->GetFunctionNumber());
- }
- BasicBlock *
- BasicBlock::New(FlowGraph * graph)
- {
- BasicBlock * block;
- block = JitAnew(graph->alloc, BasicBlock, graph->alloc, graph->GetFunc());
- return block;
- }
- void
- BasicBlock::AddPred(FlowEdge * edge, FlowGraph * graph)
- {
- this->predList.Prepend(graph->alloc, edge);
- }
- void
- BasicBlock::AddSucc(FlowEdge * edge, FlowGraph * graph)
- {
- this->succList.Prepend(graph->alloc, edge);
- }
- void
- BasicBlock::RemovePred(BasicBlock *block, FlowGraph * graph)
- {
- this->RemovePred(block, graph, true, false);
- }
- void
- BasicBlock::RemoveSucc(BasicBlock *block, FlowGraph * graph)
- {
- this->RemoveSucc(block, graph, true, false);
- }
- void
- BasicBlock::RemoveDeadPred(BasicBlock *block, FlowGraph * graph)
- {
- this->RemovePred(block, graph, true, true);
- }
- void
- BasicBlock::RemoveDeadSucc(BasicBlock *block, FlowGraph * graph)
- {
- this->RemoveSucc(block, graph, true, true);
- }
- void
- BasicBlock::RemovePred(BasicBlock *block, FlowGraph * graph, bool doCleanSucc, bool moveToDead)
- {
- FOREACH_SLISTBASECOUNTED_ENTRY_EDITING(FlowEdge*, edge, this->GetPredList(), iter)
- {
- if (edge->GetPred() == block)
- {
- BasicBlock *blockSucc = edge->GetSucc();
- if (moveToDead)
- {
- iter.MoveCurrentTo(this->GetDeadPredList());
- }
- else
- {
- iter.RemoveCurrent(graph->alloc);
- }
- if (doCleanSucc)
- {
- block->RemoveSucc(this, graph, false, moveToDead);
- }
- if (blockSucc->isLoopHeader && blockSucc->loop && blockSucc->GetPredList()->HasOne())
- {
- Loop *loop = blockSucc->loop;
- loop->isDead = true;
- }
- return;
- }
- } NEXT_SLISTBASECOUNTED_ENTRY_EDITING;
- AssertMsg(UNREACHED, "Edge not found.");
- }
- void
- BasicBlock::RemoveSucc(BasicBlock *block, FlowGraph * graph, bool doCleanPred, bool moveToDead)
- {
- FOREACH_SLISTBASECOUNTED_ENTRY_EDITING(FlowEdge*, edge, this->GetSuccList(), iter)
- {
- if (edge->GetSucc() == block)
- {
- if (moveToDead)
- {
- iter.MoveCurrentTo(this->GetDeadSuccList());
- }
- else
- {
- iter.RemoveCurrent(graph->alloc);
- }
- if (doCleanPred)
- {
- block->RemovePred(this, graph, false, moveToDead);
- }
- if (block->isLoopHeader && block->loop && block->GetPredList()->HasOne())
- {
- Loop *loop = block->loop;
- loop->isDead = true;
- }
- return;
- }
- } NEXT_SLISTBASECOUNTED_ENTRY_EDITING;
- AssertMsg(UNREACHED, "Edge not found.");
- }
- void
- BasicBlock::UnlinkPred(BasicBlock *block)
- {
- this->UnlinkPred(block, true);
- }
- void
- BasicBlock::UnlinkSucc(BasicBlock *block)
- {
- this->UnlinkSucc(block, true);
- }
- void
- BasicBlock::UnlinkPred(BasicBlock *block, bool doCleanSucc)
- {
- FOREACH_SLISTBASECOUNTED_ENTRY_EDITING(FlowEdge*, edge, this->GetPredList(), iter)
- {
- if (edge->GetPred() == block)
- {
- iter.UnlinkCurrent();
- if (doCleanSucc)
- {
- block->UnlinkSucc(this, false);
- }
- return;
- }
- } NEXT_SLISTBASECOUNTED_ENTRY_EDITING;
- AssertMsg(UNREACHED, "Edge not found.");
- }
- void
- BasicBlock::UnlinkSucc(BasicBlock *block, bool doCleanPred)
- {
- FOREACH_SLISTBASECOUNTED_ENTRY_EDITING(FlowEdge*, edge, this->GetSuccList(), iter)
- {
- if (edge->GetSucc() == block)
- {
- iter.UnlinkCurrent();
- if (doCleanPred)
- {
- block->UnlinkPred(this, false);
- }
- return;
- }
- } NEXT_SLISTBASECOUNTED_ENTRY_EDITING;
- AssertMsg(UNREACHED, "Edge not found.");
- }
- bool
- BasicBlock::IsLandingPad()
- {
- BasicBlock * nextBlock = this->GetNext();
- return nextBlock && nextBlock->loop && nextBlock->isLoopHeader && nextBlock->loop->landingPad == this;
- }
- IR::Instr *
- FlowGraph::RemoveInstr(IR::Instr *instr, GlobOpt * globOpt)
- {
- IR::Instr *instrPrev = instr->m_prev;
- if (globOpt)
- {
- // Removing block during glob opt. Need to maintain the graph so that
- // bailout will record the byte code use in case the dead code is exposed
- // by dyno-pogo optimization (where bailout need the byte code uses from
- // the dead blocks where it may not be dead after bailing out)
- if (instr->IsLabelInstr())
- {
- instr->AsLabelInstr()->m_isLoopTop = false;
- return instr;
- }
- else if (instr->IsByteCodeUsesInstr())
- {
- return instr;
- }
- /*
- * Scope object has to be implicitly live whenever Heap Arguments object is live.
- * - When we restore HeapArguments object in the bail out path, it expects the scope object also to be restored - if one was created.
- */
- Js::OpCode opcode = instr->m_opcode;
- if (opcode == Js::OpCode::LdElemI_A && instr->DoStackArgsOpt(this->func) &&
- globOpt->IsArgumentsOpnd(instr->GetSrc1()) && instr->m_func->GetScopeObjSym())
- {
- IR::ByteCodeUsesInstr * byteCodeUsesInstr = IR::ByteCodeUsesInstr::New(instr);
- byteCodeUsesInstr->SetNonOpndSymbol(instr->m_func->GetScopeObjSym()->m_id);
- instr->InsertAfter(byteCodeUsesInstr);
- }
- IR::ByteCodeUsesInstr * newByteCodeUseInstr = globOpt->ConvertToByteCodeUses(instr);
- if (newByteCodeUseInstr != nullptr)
- {
- // We don't care about property used in these instruction
- // It is only necessary for field copy prop so that we will keep the implicit call
- // up to the copy prop location.
- newByteCodeUseInstr->propertySymUse = nullptr;
- if (opcode == Js::OpCode::Yield)
- {
- IR::Instr *instrLabel = newByteCodeUseInstr->m_next;
- while (instrLabel->m_opcode != Js::OpCode::Label)
- {
- instrLabel = instrLabel->m_next;
- }
- func->RemoveDeadYieldOffsetResumeLabel(instrLabel->AsLabelInstr());
- instrLabel->AsLabelInstr()->m_hasNonBranchRef = false;
- }
- // Save the last instruction to update the block with
- return newByteCodeUseInstr;
- }
- else
- {
- return instrPrev;
- }
- }
- else
- {
- instr->Remove();
- return instrPrev;
- }
- }
- void
- FlowGraph::RemoveBlock(BasicBlock *block, GlobOpt * globOpt, bool tailDuping)
- {
- Assert(!block->isDead && !block->isDeleted);
- IR::Instr * lastInstr = nullptr;
- FOREACH_INSTR_IN_BLOCK_EDITING(instr, instrNext, block)
- {
- if (instr->m_opcode == Js::OpCode::FunctionExit)
- {
- // Removing FunctionExit causes problems downstream...
- // We could change the opcode, or have FunctionEpilog/FunctionExit to get
- // rid of the epilog.
- break;
- }
- if (instr == block->GetFirstInstr())
- {
- Assert(instr->IsLabelInstr());
- instr->AsLabelInstr()->m_isLoopTop = false;
- }
- else
- {
- lastInstr = this->RemoveInstr(instr, globOpt);
- }
- } NEXT_INSTR_IN_BLOCK_EDITING;
- if (lastInstr)
- {
- block->SetLastInstr(lastInstr);
- }
- FOREACH_SLISTBASECOUNTED_ENTRY(FlowEdge*, edge, block->GetPredList())
- {
- edge->GetPred()->RemoveSucc(block, this, false, globOpt != nullptr);
- } NEXT_SLISTBASECOUNTED_ENTRY;
- FOREACH_SLISTBASECOUNTED_ENTRY(FlowEdge*, edge, block->GetSuccList())
- {
- edge->GetSucc()->RemovePred(block, this, false, globOpt != nullptr);
- } NEXT_SLISTBASECOUNTED_ENTRY;
- if (block->isLoopHeader && this->loopList)
- {
- // If loop graph is built, remove loop from loopList
- Loop **pPrevLoop = &this->loopList;
- while (*pPrevLoop != block->loop)
- {
- pPrevLoop = &((*pPrevLoop)->next);
- }
- *pPrevLoop = (*pPrevLoop)->next;
- this->hasLoop = (this->loopList != nullptr);
- }
- if (globOpt != nullptr)
- {
- block->isDead = true;
- block->GetPredList()->MoveTo(block->GetDeadPredList());
- block->GetSuccList()->MoveTo(block->GetDeadSuccList());
- }
- if (tailDuping)
- {
- block->isDead = true;
- }
- block->isDeleted = true;
- block->SetDataUseCount(0);
- }
- void
- BasicBlock::UnlinkInstr(IR::Instr * instr)
- {
- Assert(this->Contains(instr));
- Assert(this->GetFirstInstr() != this->GetLastInstr());
- if (instr == this->GetFirstInstr())
- {
- Assert(!this->GetFirstInstr()->IsLabelInstr());
- this->SetFirstInstr(instr->m_next);
- }
- else if (instr == this->GetLastInstr())
- {
- this->SetLastInstr(instr->m_prev);
- }
- instr->Unlink();
- }
- void
- BasicBlock::RemoveInstr(IR::Instr * instr)
- {
- Assert(this->Contains(instr));
- if (instr == this->GetFirstInstr())
- {
- this->SetFirstInstr(instr->m_next);
- }
- else if (instr == this->GetLastInstr())
- {
- this->SetLastInstr(instr->m_prev);
- }
- instr->Remove();
- }
- void
- BasicBlock::InsertInstrBefore(IR::Instr *newInstr, IR::Instr *beforeThisInstr)
- {
- Assert(this->Contains(beforeThisInstr));
- beforeThisInstr->InsertBefore(newInstr);
- if(this->GetFirstInstr() == beforeThisInstr)
- {
- Assert(!beforeThisInstr->IsLabelInstr());
- this->SetFirstInstr(newInstr);
- }
- }
- void
- BasicBlock::InsertInstrAfter(IR::Instr *newInstr, IR::Instr *afterThisInstr)
- {
- Assert(this->Contains(afterThisInstr));
- afterThisInstr->InsertAfter(newInstr);
- if (this->GetLastInstr() == afterThisInstr)
- {
- Assert(afterThisInstr->HasFallThrough());
- this->SetLastInstr(newInstr);
- }
- }
- void
- BasicBlock::InsertAfter(IR::Instr *newInstr)
- {
- Assert(this->GetLastInstr()->HasFallThrough());
- this->GetLastInstr()->InsertAfter(newInstr);
- this->SetLastInstr(newInstr);
- }
- void
- Loop::SetHasCall()
- {
- Loop * current = this;
- do
- {
- if (current->hasCall)
- {
- #if DBG
- current = current->parent;
- while (current)
- {
- Assert(current->hasCall);
- current = current->parent;
- }
- #endif
- break;
- }
- current->hasCall = true;
- current = current->parent;
- }
- while (current != nullptr);
- }
- void
- Loop::SetImplicitCallFlags(Js::ImplicitCallFlags newFlags)
- {
- Loop * current = this;
- do
- {
- if ((current->implicitCallFlags & newFlags) == newFlags)
- {
- #if DBG
- current = current->parent;
- while (current)
- {
- Assert((current->implicitCallFlags & newFlags) == newFlags);
- current = current->parent;
- }
- #endif
- break;
- }
- newFlags = (Js::ImplicitCallFlags)(implicitCallFlags | newFlags);
- current->implicitCallFlags = newFlags;
- current = current->parent;
- }
- while (current != nullptr);
- }
- Js::ImplicitCallFlags
- Loop::GetImplicitCallFlags()
- {
- if (this->implicitCallFlags == Js::ImplicitCall_HasNoInfo)
- {
- if (this->parent == nullptr)
- {
- // We don't have any information, and we don't have any parent, so just assume that there aren't any implicit calls
- this->implicitCallFlags = Js::ImplicitCall_None;
- }
- else
- {
- // We don't have any information, get it from the parent and hope for the best
- this->implicitCallFlags = this->parent->GetImplicitCallFlags();
- }
- }
- return this->implicitCallFlags;
- }
- bool
- Loop::CanDoFieldCopyProp()
- {
- #if DBG_DUMP
- if (((this->implicitCallFlags & ~(Js::ImplicitCall_External)) == 0) &&
- Js::Configuration::Global.flags.Trace.IsEnabled(Js::HostOptPhase))
- {
- Output::Print(_u("fieldcopyprop disabled because external: loop count: %d"), GetLoopNumber());
- GetFunc()->DumpFullFunctionName();
- Output::Print(_u("\n"));
- Output::Flush();
- }
- #endif
- return GlobOpt::ImplicitCallFlagsAllowOpts(this);
- }
- bool
- Loop::CanDoFieldHoist()
- {
- // We can do field hoist wherever we can do copy prop
- return CanDoFieldCopyProp();
- }
- bool
- Loop::CanHoistInvariants()
- {
- Func * func = this->GetHeadBlock()->firstInstr->m_func->GetTopFunc();
- if (PHASE_OFF(Js::InvariantsPhase, func))
- {
- return false;
- }
- return true;
- }
- IR::LabelInstr *
- Loop::GetLoopTopInstr() const
- {
- IR::LabelInstr * instr = nullptr;
- if (this->topFunc->isFlowGraphValid)
- {
- instr = this->GetHeadBlock()->GetFirstInstr()->AsLabelInstr();
- }
- else
- {
- // Flowgraph gets torn down after the globopt, so can't get the loopTop from the head block.
- instr = this->loopTopLabel;
- }
- if (instr)
- {
- Assert(instr->m_isLoopTop);
- }
- return instr;
- }
- void
- Loop::SetLoopTopInstr(IR::LabelInstr * loopTop)
- {
- this->loopTopLabel = loopTop;
- }
- #if DBG_DUMP
- uint
- Loop::GetLoopNumber() const
- {
- IR::LabelInstr * loopTopInstr = this->GetLoopTopInstr();
- if (loopTopInstr->IsProfiledLabelInstr())
- {
- return loopTopInstr->AsProfiledLabelInstr()->loopNum;
- }
- return Js::LoopHeader::NoLoop;
- }
- bool
- BasicBlock::Contains(IR::Instr * instr)
- {
- FOREACH_INSTR_IN_BLOCK(blockInstr, this)
- {
- if (instr == blockInstr)
- {
- return true;
- }
- }
- NEXT_INSTR_IN_BLOCK;
- return false;
- }
- #endif
- FlowEdge *
- FlowEdge::New(FlowGraph * graph)
- {
- FlowEdge * edge;
- edge = JitAnew(graph->alloc, FlowEdge);
- return edge;
- }
- bool
- Loop::IsDescendentOrSelf(Loop const * loop) const
- {
- Loop const * currentLoop = loop;
- while (currentLoop != nullptr)
- {
- if (currentLoop == this)
- {
- return true;
- }
- currentLoop = currentLoop->parent;
- }
- return false;
- }
- void FlowGraph::SafeRemoveInstr(IR::Instr *instr)
- {
- BasicBlock *block;
- if (instr->m_next->IsLabelInstr())
- {
- block = instr->m_next->AsLabelInstr()->GetBasicBlock()->GetPrev();
- block->RemoveInstr(instr);
- }
- else if (instr->IsLabelInstr())
- {
- block = instr->AsLabelInstr()->GetBasicBlock();
- block->RemoveInstr(instr);
- }
- else
- {
- Assert(!instr->EndsBasicBlock() && !instr->StartsBasicBlock());
- instr->Remove();
- }
- }
- bool FlowGraph::IsUnsignedOpnd(IR::Opnd *src, IR::Opnd **pShrSrc1)
- {
- // Look for an unsigned constant, or the result of an unsigned shift by zero
- if (!src->IsRegOpnd())
- {
- return false;
- }
- if (!src->AsRegOpnd()->m_sym->IsSingleDef())
- {
- return false;
- }
- if (src->AsRegOpnd()->m_sym->IsIntConst())
- {
- int32 intConst = src->AsRegOpnd()->m_sym->GetIntConstValue();
- if (intConst >= 0)
- {
- *pShrSrc1 = src;
- return true;
- }
- else
- {
- return false;
- }
- }
- IR::Instr * shrUInstr = src->AsRegOpnd()->m_sym->GetInstrDef();
- if (shrUInstr->m_opcode != Js::OpCode::ShrU_A)
- {
- return false;
- }
- IR::Opnd *shrCnt = shrUInstr->GetSrc2();
- if (!shrCnt->IsRegOpnd() || !shrCnt->AsRegOpnd()->m_sym->IsTaggableIntConst() || shrCnt->AsRegOpnd()->m_sym->GetIntConstValue() != 0)
- {
- return false;
- }
- *pShrSrc1 = shrUInstr->GetSrc1();
- return true;
- }
- bool FlowGraph::UnsignedCmpPeep(IR::Instr *cmpInstr)
- {
- IR::Opnd *cmpSrc1 = cmpInstr->GetSrc1();
- IR::Opnd *cmpSrc2 = cmpInstr->GetSrc2();
- IR::Opnd *newSrc1;
- IR::Opnd *newSrc2;
- // Look for something like:
- // t1 = ShrU_A x, 0
- // t2 = 10;
- // BrGt t1, t2, L
- //
- // Peep to:
- //
- // t1 = ShrU_A x, 0
- // t2 = 10;
- // BrUnGt x, t2, L
- // ByteCodeUse t1
- //
- // Hopefully dead-store can get rid of the ShrU
- if (!this->func->DoGlobOpt() || !GlobOpt::DoAggressiveIntTypeSpec(this->func) || !GlobOpt::DoLossyIntTypeSpec(this->func))
- {
- return false;
- }
- if (cmpInstr->IsBranchInstr() && !cmpInstr->AsBranchInstr()->IsConditional())
- {
- return false;
- }
- if (!cmpInstr->GetSrc2())
- {
- return false;
- }
- if (!this->IsUnsignedOpnd(cmpSrc1, &newSrc1))
- {
- return false;
- }
- if (!this->IsUnsignedOpnd(cmpSrc2, &newSrc2))
- {
- return false;
- }
- switch(cmpInstr->m_opcode)
- {
- case Js::OpCode::BrEq_A:
- case Js::OpCode::BrNeq_A:
- case Js::OpCode::BrSrEq_A:
- case Js::OpCode::BrSrNeq_A:
- break;
- case Js::OpCode::BrLe_A:
- cmpInstr->m_opcode = Js::OpCode::BrUnLe_A;
- break;
- case Js::OpCode::BrLt_A:
- cmpInstr->m_opcode = Js::OpCode::BrUnLt_A;
- break;
- case Js::OpCode::BrGe_A:
- cmpInstr->m_opcode = Js::OpCode::BrUnGe_A;
- break;
- case Js::OpCode::BrGt_A:
- cmpInstr->m_opcode = Js::OpCode::BrUnGt_A;
- break;
- case Js::OpCode::CmLe_A:
- cmpInstr->m_opcode = Js::OpCode::CmUnLe_A;
- break;
- case Js::OpCode::CmLt_A:
- cmpInstr->m_opcode = Js::OpCode::CmUnLt_A;
- break;
- case Js::OpCode::CmGe_A:
- cmpInstr->m_opcode = Js::OpCode::CmUnGe_A;
- break;
- case Js::OpCode::CmGt_A:
- cmpInstr->m_opcode = Js::OpCode::CmUnGt_A;
- break;
- default:
- return false;
- }
- IR::ByteCodeUsesInstr * bytecodeInstr = IR::ByteCodeUsesInstr::New(cmpInstr);
- cmpInstr->InsertAfter(bytecodeInstr);
- if (cmpSrc1 != newSrc1)
- {
- if (cmpSrc1->IsRegOpnd() && !cmpSrc1->GetIsJITOptimizedReg())
- {
- bytecodeInstr->Set(cmpSrc1);
- }
- cmpInstr->ReplaceSrc1(newSrc1);
- if (newSrc1->IsRegOpnd())
- {
- cmpInstr->GetSrc1()->AsRegOpnd()->SetIsJITOptimizedReg(true);
- }
- }
- if (cmpSrc2 != newSrc2)
- {
- if (cmpSrc2->IsRegOpnd() && !cmpSrc2->GetIsJITOptimizedReg())
- {
- bytecodeInstr->Set(cmpSrc2);
- }
- cmpInstr->ReplaceSrc2(newSrc2);
- if (newSrc2->IsRegOpnd())
- {
- cmpInstr->GetSrc2()->AsRegOpnd()->SetIsJITOptimizedReg(true);
- }
- }
- return true;
- }
- #if DBG
- void
- FlowGraph::VerifyLoopGraph()
- {
- FOREACH_BLOCK(block, this)
- {
- Loop *loop = block->loop;
- FOREACH_SUCCESSOR_BLOCK(succ, block)
- {
- if (loop == succ->loop)
- {
- Assert(succ->isLoopHeader == false || loop->GetHeadBlock() == succ);
- continue;
- }
- if (succ->isLoopHeader)
- {
- Assert(succ->loop->parent == loop
- || (!loop->IsDescendentOrSelf(succ->loop)));
- continue;
- }
- Assert(succ->loop == nullptr || succ->loop->IsDescendentOrSelf(loop));
- } NEXT_SUCCESSOR_BLOCK;
- if (!PHASE_OFF(Js::RemoveBreakBlockPhase, this->GetFunc()))
- {
- // Make sure all break blocks have been removed.
- if (loop && !block->isLoopHeader && !(this->func->HasTry() && !this->func->DoOptimizeTryCatch()))
- {
- Assert(loop->IsDescendentOrSelf(block->GetPrev()->loop));
- }
- }
- } NEXT_BLOCK;
- }
- #endif
- #if DBG_DUMP
- void
- FlowGraph::Dump(bool onlyOnVerboseMode, const char16 *form)
- {
- if(PHASE_DUMP(Js::FGBuildPhase, this->GetFunc()))
- {
- if (!onlyOnVerboseMode || Js::Configuration::Global.flags.Verbose)
- {
- if (form)
- {
- Output::Print(form);
- }
- this->Dump();
- }
- }
- }
- void
- FlowGraph::Dump()
- {
- Output::Print(_u("\nFlowGraph\n"));
- FOREACH_BLOCK(block, this)
- {
- Loop * loop = block->loop;
- while (loop)
- {
- Output::Print(_u(" "));
- loop = loop->parent;
- }
- block->DumpHeader(false);
- } NEXT_BLOCK;
- Output::Print(_u("\nLoopGraph\n"));
- for (Loop *loop = this->loopList; loop; loop = loop->next)
- {
- Output::Print(_u("\nLoop\n"));
- FOREACH_BLOCK_IN_LOOP(block, loop)
- {
- block->DumpHeader(false);
- }NEXT_BLOCK_IN_LOOP;
- Output::Print(_u("Loop Ends\n"));
- }
- }
- void
- BasicBlock::DumpHeader(bool insertCR)
- {
- if (insertCR)
- {
- Output::Print(_u("\n"));
- }
- Output::Print(_u("BLOCK %d:"), this->number);
- if (this->isDead)
- {
- Output::Print(_u(" **** DEAD ****"));
- }
- if (this->isBreakBlock)
- {
- Output::Print(_u(" **** Break Block ****"));
- }
- else if (this->isAirLockBlock)
- {
- Output::Print(_u(" **** Air lock Block ****"));
- }
- else if (this->isBreakCompensationBlockAtSource)
- {
- Output::Print(_u(" **** Break Source Compensation Code ****"));
- }
- else if (this->isBreakCompensationBlockAtSink)
- {
- Output::Print(_u(" **** Break Sink Compensation Code ****"));
- }
- else if (this->isAirLockCompensationBlock)
- {
- Output::Print(_u(" **** Airlock block Compensation Code ****"));
- }
- if (!this->predList.Empty())
- {
- BOOL fFirst = TRUE;
- Output::Print(_u(" In("));
- FOREACH_PREDECESSOR_BLOCK(blockPred, this)
- {
- if (!fFirst)
- {
- Output::Print(_u(", "));
- }
- Output::Print(_u("%d"), blockPred->GetBlockNum());
- fFirst = FALSE;
- }
- NEXT_PREDECESSOR_BLOCK;
- Output::Print(_u(")"));
- }
- if (!this->succList.Empty())
- {
- BOOL fFirst = TRUE;
- Output::Print(_u(" Out("));
- FOREACH_SUCCESSOR_BLOCK(blockSucc, this)
- {
- if (!fFirst)
- {
- Output::Print(_u(", "));
- }
- Output::Print(_u("%d"), blockSucc->GetBlockNum());
- fFirst = FALSE;
- }
- NEXT_SUCCESSOR_BLOCK;
- Output::Print(_u(")"));
- }
- if (!this->deadPredList.Empty())
- {
- BOOL fFirst = TRUE;
- Output::Print(_u(" DeadIn("));
- FOREACH_DEAD_PREDECESSOR_BLOCK(blockPred, this)
- {
- if (!fFirst)
- {
- Output::Print(_u(", "));
- }
- Output::Print(_u("%d"), blockPred->GetBlockNum());
- fFirst = FALSE;
- }
- NEXT_DEAD_PREDECESSOR_BLOCK;
- Output::Print(_u(")"));
- }
- if (!this->deadSuccList.Empty())
- {
- BOOL fFirst = TRUE;
- Output::Print(_u(" DeadOut("));
- FOREACH_DEAD_SUCCESSOR_BLOCK(blockSucc, this)
- {
- if (!fFirst)
- {
- Output::Print(_u(", "));
- }
- Output::Print(_u("%d"), blockSucc->GetBlockNum());
- fFirst = FALSE;
- }
- NEXT_DEAD_SUCCESSOR_BLOCK;
- Output::Print(_u(")"));
- }
- if (this->loop)
- {
- Output::Print(_u(" Loop(%d) header: %d"), this->loop->loopNumber, this->loop->GetHeadBlock()->GetBlockNum());
- if (this->loop->parent)
- {
- Output::Print(_u(" parent(%d): %d"), this->loop->parent->loopNumber, this->loop->parent->GetHeadBlock()->GetBlockNum());
- }
- if (this->loop->GetHeadBlock() == this)
- {
- Output::SkipToColumn(50);
- Output::Print(_u("Call Exp/Imp: "));
- if (this->loop->GetHasCall())
- {
- Output::Print(_u("yes/"));
- }
- else
- {
- Output::Print(_u(" no/"));
- }
- Output::Print(Js::DynamicProfileInfo::GetImplicitCallFlagsString(this->loop->GetImplicitCallFlags()));
- }
- }
- Output::Print(_u("\n"));
- if (insertCR)
- {
- Output::Print(_u("\n"));
- }
- }
- void
- BasicBlock::Dump()
- {
- // Dumping the first instruction (label) will dump the block header as well.
- FOREACH_INSTR_IN_BLOCK(instr, this)
- {
- instr->Dump();
- }
- NEXT_INSTR_IN_BLOCK;
- }
- void
- AddPropertyCacheBucket::Dump() const
- {
- Assert(this->initialType != nullptr);
- Assert(this->finalType != nullptr);
- Output::Print(_u(" initial type: 0x%x, final type: 0x%x "), this->initialType->GetAddr(), this->finalType->GetAddr());
- }
- void
- ObjTypeGuardBucket::Dump() const
- {
- Assert(this->guardedPropertyOps != nullptr);
- this->guardedPropertyOps->Dump();
- }
- void
- ObjWriteGuardBucket::Dump() const
- {
- Assert(this->writeGuards != nullptr);
- this->writeGuards->Dump();
- }
- #endif
|