LowerMDShared.cpp 323 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "BackEnd.h"
  6. #include "Language\JavascriptFunctionArgIndex.h"
  7. #include "Types\DynamicObjectEnumerator.h"
  8. #include "Types\DynamicObjectSnapshotEnumerator.h"
  9. #include "Types\DynamicObjectSnapshotEnumeratorWPCache.h"
  10. #include "Library\ForInObjectEnumerator.h"
  11. const Js::OpCode LowererMD::MDUncondBranchOpcode = Js::OpCode::JMP;
  12. const Js::OpCode LowererMD::MDTestOpcode = Js::OpCode::TEST;
  13. const Js::OpCode LowererMD::MDOrOpcode = Js::OpCode::OR;
  14. const Js::OpCode LowererMD::MDOverflowBranchOpcode = Js::OpCode::JO;
  15. const Js::OpCode LowererMD::MDNotOverflowBranchOpcode = Js::OpCode::JNO;
  16. const Js::OpCode LowererMD::MDConvertFloat32ToFloat64Opcode = Js::OpCode::CVTSS2SD;
  17. const Js::OpCode LowererMD::MDConvertFloat64ToFloat32Opcode = Js::OpCode::CVTSD2SS;
  18. const Js::OpCode LowererMD::MDCallOpcode = Js::OpCode::CALL;
  19. const Js::OpCode LowererMD::MDImulOpcode = Js::OpCode::IMUL2;
  20. //
  21. // Static utility fn()
  22. //
  23. bool
  24. LowererMD::IsAssign(IR::Instr *instr)
  25. {
  26. return instr->GetDst() && instr->m_opcode == LowererMDArch::GetAssignOp(instr->GetDst()->GetType());
  27. }
  28. ///----------------------------------------------------------------------------
  29. ///
  30. /// LowererMD::IsCall
  31. ///
  32. ///----------------------------------------------------------------------------
  33. bool
  34. LowererMD::IsCall(IR::Instr *instr)
  35. {
  36. return instr->m_opcode == Js::OpCode::CALL;
  37. }
  38. ///----------------------------------------------------------------------------
  39. ///
  40. /// LowererMD::IsUnconditionalBranch
  41. ///
  42. ///----------------------------------------------------------------------------
  43. bool
  44. LowererMD::IsUnconditionalBranch(const IR::Instr *instr)
  45. {
  46. return (instr->m_opcode == Js::OpCode::JMP);
  47. }
  48. // GenerateMemRef: Return an opnd that can be used to access the given address.
  49. IR::Opnd *
  50. LowererMD::GenerateMemRef(void *addr, IRType type, IR::Instr *instr, bool dontEncode)
  51. {
  52. return IR::MemRefOpnd::New(addr, type, this->m_func);
  53. }
  54. ///----------------------------------------------------------------------------
  55. ///
  56. /// LowererMD::InvertBranch
  57. ///
  58. ///----------------------------------------------------------------------------
  59. void
  60. LowererMD::InvertBranch(IR::BranchInstr *branchInstr)
  61. {
  62. switch (branchInstr->m_opcode)
  63. {
  64. case Js::OpCode::JA:
  65. branchInstr->m_opcode = Js::OpCode::JBE;
  66. break;
  67. case Js::OpCode::JAE:
  68. branchInstr->m_opcode = Js::OpCode::JB;
  69. break;
  70. case Js::OpCode::JB:
  71. branchInstr->m_opcode = Js::OpCode::JAE;
  72. break;
  73. case Js::OpCode::JBE:
  74. branchInstr->m_opcode = Js::OpCode::JA;
  75. break;
  76. case Js::OpCode::JEQ:
  77. branchInstr->m_opcode = Js::OpCode::JNE;
  78. break;
  79. case Js::OpCode::JNE:
  80. branchInstr->m_opcode = Js::OpCode::JEQ;
  81. break;
  82. case Js::OpCode::JGE:
  83. branchInstr->m_opcode = Js::OpCode::JLT;
  84. break;
  85. case Js::OpCode::JGT:
  86. branchInstr->m_opcode = Js::OpCode::JLE;
  87. break;
  88. case Js::OpCode::JLT:
  89. branchInstr->m_opcode = Js::OpCode::JGE;
  90. break;
  91. case Js::OpCode::JLE:
  92. branchInstr->m_opcode = Js::OpCode::JGT;
  93. break;
  94. case Js::OpCode::JO:
  95. branchInstr->m_opcode = Js::OpCode::JNO;
  96. break;
  97. case Js::OpCode::JNO:
  98. branchInstr->m_opcode = Js::OpCode::JO;
  99. break;
  100. case Js::OpCode::JP:
  101. branchInstr->m_opcode = Js::OpCode::JNP;
  102. break;
  103. case Js::OpCode::JNP:
  104. branchInstr->m_opcode = Js::OpCode::JP;
  105. break;
  106. case Js::OpCode::JSB:
  107. branchInstr->m_opcode = Js::OpCode::JNSB;
  108. break;
  109. case Js::OpCode::JNSB:
  110. branchInstr->m_opcode = Js::OpCode::JSB;
  111. break;
  112. default:
  113. AssertMsg(UNREACHED, "JCC missing in InvertBranch()");
  114. }
  115. }
  116. void
  117. LowererMD::ReverseBranch(IR::BranchInstr *branchInstr)
  118. {
  119. switch (branchInstr->m_opcode)
  120. {
  121. case Js::OpCode::JA:
  122. branchInstr->m_opcode = Js::OpCode::JB;
  123. break;
  124. case Js::OpCode::JAE:
  125. branchInstr->m_opcode = Js::OpCode::JBE;
  126. break;
  127. case Js::OpCode::JB:
  128. branchInstr->m_opcode = Js::OpCode::JA;
  129. break;
  130. case Js::OpCode::JBE:
  131. branchInstr->m_opcode = Js::OpCode::JAE;
  132. break;
  133. case Js::OpCode::JGE:
  134. branchInstr->m_opcode = Js::OpCode::JLE;
  135. break;
  136. case Js::OpCode::JGT:
  137. branchInstr->m_opcode = Js::OpCode::JLT;
  138. break;
  139. case Js::OpCode::JLT:
  140. branchInstr->m_opcode = Js::OpCode::JGT;
  141. break;
  142. case Js::OpCode::JLE:
  143. branchInstr->m_opcode = Js::OpCode::JGE;
  144. break;
  145. case Js::OpCode::JEQ:
  146. case Js::OpCode::JNE:
  147. case Js::OpCode::JO:
  148. case Js::OpCode::JNO:
  149. case Js::OpCode::JP:
  150. case Js::OpCode::JNP:
  151. case Js::OpCode::JSB:
  152. case Js::OpCode::JNSB:
  153. break;
  154. default:
  155. AssertMsg(UNREACHED, "JCC missing in ReverseBranch()");
  156. }
  157. }
  158. IR::Instr *
  159. LowererMD::LowerCallHelper(IR::Instr *instrCall)
  160. {
  161. IR::Opnd *argOpnd = instrCall->UnlinkSrc2();
  162. IR::Instr *prevInstr = nullptr;
  163. IR::JnHelperMethod helperMethod = instrCall->GetSrc1()->AsHelperCallOpnd()->m_fnHelper;
  164. instrCall->FreeSrc1();
  165. #ifndef _M_X64
  166. prevInstr = ChangeToHelperCall(instrCall, helperMethod);
  167. #endif
  168. while (argOpnd)
  169. {
  170. Assert(argOpnd->IsRegOpnd());
  171. IR::RegOpnd *regArg = argOpnd->AsRegOpnd();
  172. Assert(regArg->m_sym->m_isSingleDef);
  173. IR::Instr *instrArg = regArg->m_sym->m_instrDef;
  174. Assert(instrArg->m_opcode == Js::OpCode::ArgOut_A);
  175. prevInstr = LoadHelperArgument(instrArg, instrArg->UnlinkSrc1());
  176. regArg->Free(this->m_func);
  177. argOpnd = instrArg->GetSrc2();
  178. if (argOpnd)
  179. {
  180. instrArg->UnlinkSrc2();
  181. }
  182. if (prevInstr == instrArg)
  183. {
  184. prevInstr = prevInstr->m_prev;
  185. }
  186. instrArg->Remove();
  187. }
  188. prevInstr = m_lowerer->LoadScriptContext(prevInstr);
  189. #ifdef _M_X64
  190. FlipHelperCallArgsOrder();
  191. ChangeToHelperCall(instrCall, helperMethod);
  192. #else
  193. this->lowererMDArch.ResetHelperArgsCount();
  194. #endif
  195. // There might be ToVar in between the ArgOut, need to continue lower from the call still
  196. return instrCall;
  197. }
  198. //
  199. // forwarding functions
  200. //
  201. IR::Instr *
  202. LowererMD::LowerCall(IR::Instr * callInstr, Js::ArgSlot argCount)
  203. {
  204. return this->lowererMDArch.LowerCall(callInstr, argCount);
  205. }
  206. IR::Instr *
  207. LowererMD::LowerCallI(IR::Instr * callInstr, ushort callFlags, bool isHelper, IR::Instr * insertBeforeInstrForCFG)
  208. {
  209. return this->lowererMDArch.LowerCallI(callInstr, callFlags, isHelper, insertBeforeInstrForCFG);
  210. }
  211. IR::Instr *
  212. LowererMD::LowerAsmJsCallI(IR::Instr * callInstr)
  213. {
  214. return this->lowererMDArch.LowerAsmJsCallI(callInstr);
  215. }
  216. IR::Instr *
  217. LowererMD::LowerAsmJsCallE(IR::Instr * callInstr)
  218. {
  219. return this->lowererMDArch.LowerAsmJsCallE(callInstr);
  220. }
  221. IR::Instr *
  222. LowererMD::LowerAsmJsLdElemHelper(IR::Instr * callInstr)
  223. {
  224. return this->lowererMDArch.LowerAsmJsLdElemHelper(callInstr);
  225. }
  226. IR::Instr *
  227. LowererMD::LowerAsmJsStElemHelper(IR::Instr * callInstr)
  228. {
  229. return this->lowererMDArch.LowerAsmJsStElemHelper(callInstr);
  230. }
  231. IR::Instr *
  232. LowererMD::LowerCallPut(IR::Instr * callInstr)
  233. {
  234. int32 argCount = this->lowererMDArch.LowerCallArgs(callInstr, Js::CallFlags_None, 2);
  235. // load native entry point from script function into eax
  236. IR::Opnd * functionWrapOpnd = callInstr->UnlinkSrc1();
  237. AssertMsg(functionWrapOpnd->IsRegOpnd() && functionWrapOpnd->AsRegOpnd()->m_sym->IsStackSym(),
  238. "Expected call src to be stackSym");
  239. this->LoadHelperArgument(callInstr, functionWrapOpnd);
  240. this->m_lowerer->LoadScriptContext(callInstr);
  241. IR::HelperCallOpnd *helperCallOpnd = IR::HelperCallOpnd::New(IR::HelperOp_InvokePut, this->m_func);
  242. callInstr->SetSrc1(helperCallOpnd);
  243. return this->lowererMDArch.LowerCall(callInstr, argCount);
  244. }
  245. IR::Instr *
  246. LowererMD::LoadHelperArgument(IR::Instr * instr, IR::Opnd * opndArg)
  247. {
  248. return this->lowererMDArch.LoadHelperArgument(instr, opndArg);
  249. }
  250. IR::Instr *
  251. LowererMD::LoadDoubleHelperArgument(IR::Instr * instr, IR::Opnd * opndArg)
  252. {
  253. return this->lowererMDArch.LoadDoubleHelperArgument(instr, opndArg);
  254. }
  255. IR::Instr *
  256. LowererMD::LowerEntryInstr(IR::EntryInstr * entryInstr)
  257. {
  258. return this->lowererMDArch.LowerEntryInstr(entryInstr);
  259. }
  260. IR::Instr *
  261. LowererMD::LowerExitInstr(IR::ExitInstr * exitInstr)
  262. {
  263. return this->lowererMDArch.LowerExitInstr(exitInstr);
  264. }
  265. IR::Instr *
  266. LowererMD::LowerEntryInstrAsmJs(IR::EntryInstr * entryInstr)
  267. {
  268. return this->lowererMDArch.LowerEntryInstrAsmJs(entryInstr);
  269. }
  270. IR::Instr *
  271. LowererMD::LowerExitInstrAsmJs(IR::ExitInstr * exitInstr)
  272. {
  273. return this->lowererMDArch.LowerExitInstrAsmJs(exitInstr);
  274. }
  275. IR::Instr *
  276. LowererMD::LoadNewScObjFirstArg(IR::Instr * instr, IR::Opnd * dst, ushort extraArgs)
  277. {
  278. return this->lowererMDArch.LoadNewScObjFirstArg(instr, dst, extraArgs);
  279. }
  280. IR::Instr *
  281. LowererMD::LowerTry(IR::Instr *tryInstr, IR::JnHelperMethod helperMethod)
  282. {
  283. // Mark the entry to the try
  284. IR::Instr *instr = tryInstr->GetNextRealInstrOrLabel();
  285. AssertMsg(instr->IsLabelInstr(), "No label at the entry to a try?");
  286. IR::LabelInstr *tryAddr = instr->AsLabelInstr();
  287. // Arg 5: ScriptContext
  288. this->m_lowerer->LoadScriptContext(tryAddr);
  289. if (tryInstr->m_opcode == Js::OpCode::TryCatch)
  290. {
  291. // Arg 4 : hasBailedOutOffset
  292. IR::Opnd * hasBailedOutOffset = IR::IntConstOpnd::New(this->m_func->m_hasBailedOutSym->m_offset, TyInt32, this->m_func);
  293. this->LoadHelperArgument(tryAddr, hasBailedOutOffset);
  294. }
  295. #ifdef _M_X64
  296. // Arg: args size
  297. IR::RegOpnd *argsSizeOpnd = IR::RegOpnd::New(TyMachReg, m_func);
  298. tryAddr->InsertBefore(IR::Instr::New(Js::OpCode::LdArgSize, argsSizeOpnd, this->m_func));
  299. this->LoadHelperArgument(tryAddr, argsSizeOpnd);
  300. // Arg: spill size
  301. IR::RegOpnd *spillSizeOpnd = IR::RegOpnd::New(TyMachReg, m_func);
  302. tryAddr->InsertBefore(IR::Instr::New(Js::OpCode::LdSpillSize, spillSizeOpnd, this->m_func));
  303. this->LoadHelperArgument(tryAddr, spillSizeOpnd);
  304. #endif
  305. // Arg 3: frame pointer
  306. IR::RegOpnd *ebpOpnd = IR::RegOpnd::New(nullptr, lowererMDArch.GetRegBlockPointer(), TyMachReg, this->m_func);
  307. this->LoadHelperArgument(tryAddr, ebpOpnd);
  308. // Arg 2: handler address
  309. IR::LabelInstr *helperAddr = tryInstr->AsBranchInstr()->GetTarget();
  310. this->LoadHelperArgument(tryAddr, IR::LabelOpnd::New(helperAddr, this->m_func));
  311. // Arg 1: try address
  312. this->LoadHelperArgument(tryAddr, IR::LabelOpnd::New(tryAddr, this->m_func));
  313. // Call the helper
  314. IR::RegOpnd *continuationAddr =
  315. IR::RegOpnd::New(StackSym::New(TyMachReg, this->m_func), lowererMDArch.GetRegReturn(TyMachReg), TyMachReg, this->m_func);
  316. IR::Instr *callInstr = IR::Instr::New(
  317. Js::OpCode::Call, continuationAddr, IR::HelperCallOpnd::New(helperMethod, this->m_func), this->m_func);
  318. tryAddr->InsertBefore(callInstr);
  319. this->LowerCall(callInstr, 0);
  320. #ifdef _M_X64
  321. {
  322. // Emit some instruction to separate the CALL from the JMP following it. The OS stack unwinder
  323. // mistakes the JMP for the start of the epilog otherwise.
  324. IR::Instr *nop = IR::Instr::New(Js::OpCode::NOP, m_func);
  325. tryAddr->InsertBefore(nop);
  326. }
  327. #endif
  328. // Jump to the continuation address supplied by the helper
  329. IR::BranchInstr *branchInstr = IR::MultiBranchInstr::New(Js::OpCode::JMP, continuationAddr, this->m_func);
  330. tryAddr->InsertBefore(branchInstr);
  331. return tryInstr->m_prev;
  332. }
  333. IR::Instr *
  334. LowererMD::LowerLeave(IR::Instr *leaveInstr, IR::LabelInstr *targetInstr, bool fromFinalLower, bool isOrphanedLeave)
  335. {
  336. if (isOrphanedLeave)
  337. {
  338. Assert(this->m_func->IsLoopBodyInTry());
  339. leaveInstr->m_opcode = Js::OpCode::JMP;
  340. return leaveInstr->m_prev;
  341. }
  342. IR::Instr *instrPrev = leaveInstr->m_prev;
  343. IR::LabelOpnd *labelOpnd = IR::LabelOpnd::New(targetInstr, this->m_func);
  344. lowererMDArch.LowerEHRegionReturn(leaveInstr, labelOpnd);
  345. if (fromFinalLower)
  346. {
  347. instrPrev = leaveInstr->m_prev; // Need to lower LdArgSize and LdSpillSize
  348. }
  349. leaveInstr->Remove();
  350. return instrPrev;
  351. }
  352. IR::Instr *
  353. LowererMD::LowerEHRegionReturn(IR::Instr * insertBeforeInstr, IR::Opnd * targetOpnd)
  354. {
  355. return lowererMDArch.LowerEHRegionReturn(insertBeforeInstr, targetOpnd);
  356. }
  357. IR::Instr *
  358. LowererMD::LowerLeaveNull(IR::Instr *finallyEndInstr)
  359. {
  360. IR::Instr *instrPrev = finallyEndInstr->m_prev;
  361. IR::Instr *instr = nullptr;
  362. // Return a null continuation address to the helper: execution will resume at the point determined by the try
  363. // or the exception handler.
  364. IR::RegOpnd *retReg = IR::RegOpnd::New(StackSym::New(TyMachReg,this->m_func), lowererMDArch.GetRegReturn(TyMachReg), TyMachReg, this->m_func);
  365. instr = IR::Instr::New(Js::OpCode::XOR, retReg, this->m_func);
  366. IR::RegOpnd *eaxOpnd = IR::RegOpnd::New(nullptr, lowererMDArch.GetRegReturn(TyMachReg), TyMachReg, this->m_func);
  367. instr->SetSrc1(eaxOpnd);
  368. instr->SetSrc2(eaxOpnd);
  369. finallyEndInstr->InsertBefore(instr);
  370. #if _M_X64
  371. {
  372. // amd64_ReturnFromCallWithFakeFrame expects to find the spill size and args size
  373. // in r8 and r9.
  374. // MOV r8, spillSize
  375. IR::Instr *movR8 = IR::Instr::New(Js::OpCode::LdSpillSize,
  376. IR::RegOpnd::New(nullptr, RegR8, TyMachReg, m_func),
  377. m_func);
  378. finallyEndInstr->InsertBefore(movR8);
  379. // MOV r9, argsSize
  380. IR::Instr *movR9 = IR::Instr::New(Js::OpCode::LdArgSize,
  381. IR::RegOpnd::New(nullptr, RegR9, TyMachReg, m_func),
  382. m_func);
  383. finallyEndInstr->InsertBefore(movR9);
  384. IR::Opnd *targetOpnd = IR::RegOpnd::New(nullptr, RegRCX, TyMachReg, m_func);
  385. IR::Instr *movTarget = IR::Instr::New(Js::OpCode::MOV,
  386. targetOpnd,
  387. IR::HelperCallOpnd::New(IR::HelperOp_ReturnFromCallWithFakeFrame, m_func),
  388. m_func);
  389. finallyEndInstr->InsertBefore(movTarget);
  390. IR::Instr *push = IR::Instr::New(Js::OpCode::PUSH, m_func);
  391. push->SetSrc1(targetOpnd);
  392. finallyEndInstr->InsertBefore(push);
  393. }
  394. #endif
  395. IR::IntConstOpnd *intSrc = IR::IntConstOpnd::New(0, TyInt32, this->m_func);
  396. instr = IR::Instr::New(Js::OpCode::RET, this->m_func);
  397. instr->SetSrc1(intSrc);
  398. instr->SetSrc2(retReg);
  399. finallyEndInstr->InsertBefore(instr);
  400. finallyEndInstr->Remove();
  401. return instrPrev;
  402. }
  403. ///----------------------------------------------------------------------------
  404. ///
  405. /// LowererMD::Init
  406. ///
  407. ///----------------------------------------------------------------------------
  408. void
  409. LowererMD::Init(Lowerer *lowerer)
  410. {
  411. m_lowerer = lowerer;
  412. this->lowererMDArch.Init(this);
  413. Simd128InitOpcodeMap();
  414. }
  415. ///----------------------------------------------------------------------------
  416. ///
  417. /// LowererMD::LoadInputParamCount
  418. ///
  419. /// Load the passed-in parameter count from the appropriate EBP slot.
  420. ///
  421. ///----------------------------------------------------------------------------
  422. IR::Instr *
  423. LowererMD::LoadInputParamCount(IR::Instr * instrInsert, int adjust, bool needFlags)
  424. {
  425. IR::Instr * instr;
  426. IR::RegOpnd * dstOpnd;
  427. IR::SymOpnd * srcOpnd;
  428. srcOpnd = Lowerer::LoadCallInfo(instrInsert);
  429. dstOpnd = IR::RegOpnd::New(StackSym::New(TyMachReg, this->m_func), TyMachReg, this->m_func);
  430. instr = IR::Instr::New(Js::OpCode::MOV, dstOpnd, srcOpnd, this->m_func);
  431. instrInsert->InsertBefore(instr);
  432. // Copy the callinfo before masking off the param count
  433. Assert(Js::CallInfo::ksizeofCount == 24);
  434. // Mask off call flags from callinfo
  435. instr = IR::Instr::New(Js::OpCode::AND, dstOpnd, dstOpnd,
  436. IR::IntConstOpnd::New((Js::CallFlags_ExtraArg << Js::CallInfo::ksizeofCount) | 0x00FFFFFF, TyUint32, this->m_func, true), this->m_func);
  437. instrInsert->InsertBefore(instr);
  438. // Shift and mask the "calling eval" bit and subtract it from the incoming count.
  439. // ("Calling eval" means the last param is the frame display, which only the eval built-in should see.)
  440. instr = IR::Instr::New(Js::OpCode::BTR, dstOpnd, dstOpnd, IR::IntConstOpnd::New(Math::Log2(Js::CallFlags_ExtraArg) + Js::CallInfo::ksizeofCount, TyInt8, this->m_func), this->m_func);
  441. instrInsert->InsertBefore(instr);
  442. instr = IR::Instr::New(Js::OpCode::SBB, dstOpnd, dstOpnd, IR::IntConstOpnd::New(-adjust, TyInt32, this->m_func), this->m_func);
  443. instrInsert->InsertBefore(instr);
  444. return instr;
  445. }
  446. IR::Instr *
  447. LowererMD::LoadStackArgPtr(IR::Instr * instr)
  448. {
  449. if (this->m_func->IsLoopBody())
  450. {
  451. // Get the first user param from the interpreter frame instance that was passed in.
  452. // These args don't include the func object and callinfo; we just need to advance past "this".
  453. // t1 = MOV [prm1 + m_inParams]
  454. // dst = LEA &[t1 + sizeof(var)]
  455. Assert(this->m_func->m_loopParamSym);
  456. IR::RegOpnd *baseOpnd = IR::RegOpnd::New(this->m_func->m_loopParamSym, TyMachReg, this->m_func);
  457. size_t offset = Js::InterpreterStackFrame::GetOffsetOfInParams();
  458. IR::IndirOpnd *indirOpnd = IR::IndirOpnd::New(baseOpnd, (int32)offset, TyMachReg, this->m_func);
  459. IR::RegOpnd *tmpOpnd = IR::RegOpnd::New(TyMachReg, this->m_func);
  460. IR::Instr *instrLdParams = IR::Instr::New(Js::OpCode::MOV, tmpOpnd, indirOpnd, this->m_func);
  461. instr->InsertBefore(instrLdParams);
  462. indirOpnd = IR::IndirOpnd::New(tmpOpnd, sizeof(Js::Var), TyMachReg, this->m_func);
  463. instr->SetSrc1(indirOpnd);
  464. instr->m_opcode = Js::OpCode::LEA;
  465. return instr->m_prev;
  466. }
  467. else
  468. {
  469. return this->lowererMDArch.LoadStackArgPtr(instr);
  470. }
  471. }
  472. IR::Instr *
  473. LowererMD::LoadArgumentsFromFrame(IR::Instr * instr)
  474. {
  475. if (this->m_func->IsLoopBody())
  476. {
  477. // Get the arguments ptr from the interpreter frame instance that was passed in.
  478. Assert(this->m_func->m_loopParamSym);
  479. IR::RegOpnd *baseOpnd = IR::RegOpnd::New(this->m_func->m_loopParamSym, TyMachReg, this->m_func);
  480. int32 offset = (int32)Js::InterpreterStackFrame::GetOffsetOfArguments();
  481. instr->SetSrc1(IR::IndirOpnd::New(baseOpnd, offset, TyMachReg, this->m_func));
  482. }
  483. else
  484. {
  485. instr->SetSrc1(this->CreateStackArgumentsSlotOpnd());
  486. }
  487. instr->m_opcode = Js::OpCode::MOV;
  488. return instr->m_prev;
  489. }
  490. // load argument count as I4
  491. IR::Instr *
  492. LowererMD::LoadArgumentCount(IR::Instr * instr)
  493. {
  494. if (this->m_func->IsLoopBody())
  495. {
  496. // Pull the arg count from the interpreter frame instance that was passed in.
  497. // (The callinfo in the loop body's frame just shows the single parameter, the interpreter frame.)
  498. Assert(this->m_func->m_loopParamSym);
  499. IR::RegOpnd *baseOpnd = IR::RegOpnd::New(this->m_func->m_loopParamSym, TyMachReg, this->m_func);
  500. size_t offset = Js::InterpreterStackFrame::GetOffsetOfInSlotsCount();
  501. instr->SetSrc1(IR::IndirOpnd::New(baseOpnd, (int32)offset, TyInt32, this->m_func));
  502. }
  503. else
  504. {
  505. StackSym *sym = StackSym::New(TyVar, this->m_func);
  506. this->m_func->SetArgOffset(sym, (Js::JavascriptFunctionArgIndex_CallInfo - Js::JavascriptFunctionArgIndex_Frame) * sizeof(Js::Var));
  507. instr->SetSrc1(IR::SymOpnd::New(sym, TyMachReg, this->m_func));
  508. }
  509. instr->m_opcode = Js::OpCode::MOV;
  510. return instr->m_prev;
  511. }
  512. IR::Instr *
  513. LowererMD::LoadHeapArguments(IR::Instr * instrArgs, bool force, IR::Opnd* opndInputParamCount)
  514. {
  515. return this->lowererMDArch.LoadHeapArguments(instrArgs, force, opndInputParamCount);
  516. }
  517. IR::Instr *
  518. LowererMD::LoadHeapArgsCached(IR::Instr * instrArgs)
  519. {
  520. return this->lowererMDArch.LoadHeapArgsCached(instrArgs);
  521. }
  522. IR::Instr *
  523. LowererMD::LoadFuncExpression(IR::Instr * instrFuncExpr)
  524. {
  525. return this->lowererMDArch.LoadFuncExpression(instrFuncExpr);
  526. }
  527. ///----------------------------------------------------------------------------
  528. ///
  529. /// LowererMD::ChangeToHelperCall
  530. ///
  531. /// Change the current instruction to a call to the given helper.
  532. ///
  533. ///----------------------------------------------------------------------------
  534. IR::Instr *
  535. LowererMD::ChangeToHelperCall(IR::Instr * callInstr, IR::JnHelperMethod helperMethod, IR::LabelInstr *labelBailOut,
  536. IR::Opnd *opndBailOutArg, IR::PropertySymOpnd *propSymOpnd, bool isHelperContinuation)
  537. {
  538. IR::Instr * bailOutInstr = callInstr;
  539. if (callInstr->HasBailOutInfo())
  540. {
  541. if (callInstr->GetBailOutKind() == IR::BailOutExpectingObject)
  542. {
  543. callInstr = IR::Instr::New(callInstr->m_opcode, callInstr->m_func);
  544. bailOutInstr->TransferTo(callInstr);
  545. bailOutInstr->InsertBefore(callInstr);
  546. bailOutInstr->m_opcode = Js::OpCode::BailOnNotObject;
  547. bailOutInstr->SetSrc1(opndBailOutArg);
  548. }
  549. else
  550. {
  551. bailOutInstr = this->m_lowerer->SplitBailOnImplicitCall(callInstr);
  552. }
  553. }
  554. callInstr->m_opcode = Js::OpCode::CALL;
  555. IR::HelperCallOpnd *helperCallOpnd = Lowerer::CreateHelperCallOpnd(helperMethod, this->lowererMDArch.GetHelperArgsCount(), m_func);
  556. if (helperCallOpnd->IsDiagHelperCallOpnd())
  557. {
  558. // Load arguments for the wrapper.
  559. this->LoadHelperArgument(callInstr, IR::AddrOpnd::New((Js::Var)IR::GetMethodOriginalAddress(helperMethod), IR::AddrOpndKindDynamicMisc, m_func));
  560. this->m_lowerer->LoadScriptContext(callInstr);
  561. }
  562. callInstr->SetSrc1(helperCallOpnd);
  563. IR::Instr * instrRet = this->lowererMDArch.LowerCall(callInstr, 0);
  564. if (bailOutInstr != callInstr)
  565. {
  566. // The bailout needs to be lowered after we lower the helper call because the helper argument
  567. // has already been loaded. We need to drain them on AMD64 before starting another helper call
  568. if (bailOutInstr->m_opcode == Js::OpCode::BailOnNotObject)
  569. {
  570. this->m_lowerer->LowerBailOnNotObject(bailOutInstr, nullptr, labelBailOut);
  571. }
  572. else if (bailOutInstr->m_opcode == Js::OpCode::BailOut)
  573. {
  574. this->m_lowerer->GenerateBailOut(bailOutInstr, nullptr, labelBailOut);
  575. }
  576. else
  577. {
  578. this->m_lowerer->LowerBailOnEqualOrNotEqual(bailOutInstr, nullptr, labelBailOut, propSymOpnd, isHelperContinuation);
  579. }
  580. }
  581. return instrRet;
  582. }
  583. IR::Instr* LowererMD::ChangeToHelperCallMem(IR::Instr * instr, IR::JnHelperMethod helperMethod)
  584. {
  585. this->m_lowerer->LoadScriptContext(instr);
  586. return this->ChangeToHelperCall(instr, helperMethod);
  587. }
  588. ///----------------------------------------------------------------------------
  589. ///
  590. /// LowererMD::ChangeToAssign
  591. ///
  592. /// Change to a MOV.
  593. ///
  594. ///----------------------------------------------------------------------------
  595. IR::Instr *
  596. LowererMD::ChangeToAssign(IR::Instr * instr)
  597. {
  598. return ChangeToAssign(instr, instr->GetDst()->GetType());
  599. }
  600. IR::Instr *
  601. LowererMD::ChangeToAssign(IR::Instr * instr, IRType type)
  602. {
  603. Assert(!instr->HasBailOutInfo() || instr->GetBailOutKind() == IR::BailOutExpectingString);
  604. instr->m_opcode = LowererMDArch::GetAssignOp(type);
  605. Legalize(instr);
  606. return instr;
  607. }
  608. ///----------------------------------------------------------------------------
  609. ///
  610. /// LowererMD::ChangeToLea
  611. ///
  612. /// Change to an LEA.
  613. ///
  614. ///----------------------------------------------------------------------------
  615. IR::Instr *
  616. LowererMD::ChangeToLea(IR::Instr * instr)
  617. {
  618. Assert(instr);
  619. Assert(instr->GetDst());
  620. Assert(instr->GetDst()->IsRegOpnd());
  621. Assert(instr->GetSrc1());
  622. Assert(instr->GetSrc1()->IsIndirOpnd() || instr->GetSrc1()->IsSymOpnd());
  623. Assert(!instr->GetSrc2());
  624. instr->m_opcode = Js::OpCode::LEA;
  625. return instr;
  626. }
  627. ///----------------------------------------------------------------------------
  628. ///
  629. /// LowererMD::CreateAssign
  630. ///
  631. /// Create a MOV.
  632. ///
  633. ///----------------------------------------------------------------------------
  634. IR::Instr *
  635. LowererMD::CreateAssign(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsertPt)
  636. {
  637. return Lowerer::InsertMove(dst, src, instrInsertPt);
  638. }
  639. ///----------------------------------------------------------------------------
  640. ///
  641. /// LowererMD::LowerRet
  642. ///
  643. /// Lower Ret to "MOV EAX, src"
  644. /// The real RET is inserted at the exit of the function when emitting the
  645. /// epilog.
  646. ///
  647. ///----------------------------------------------------------------------------
  648. IR::Instr *
  649. LowererMD::LowerRet(IR::Instr * retInstr)
  650. {
  651. IR::RegOpnd * retReg;
  652. if (m_func->GetJnFunction()->GetIsAsmjsMode() && !m_func->IsLoopBody()) // for loop body ret is the bytecodeoffset
  653. {
  654. Js::AsmJsRetType asmType = m_func->GetJnFunction()->GetAsmJsFunctionInfo()->GetReturnType();
  655. IRType regType = TyInt32;
  656. if (asmType.which() == Js::AsmJsRetType::Double)
  657. {
  658. regType = TyFloat64;
  659. }
  660. else if (asmType.which() == Js::AsmJsRetType::Float)
  661. {
  662. regType = TyFloat32;
  663. }
  664. else if (asmType.which() == Js::AsmJsRetType::Signed || asmType.which() == Js::AsmJsRetType::Void)
  665. {
  666. regType = TyInt32;
  667. }
  668. else if (asmType.which() == Js::AsmJsRetType::Float32x4)
  669. {
  670. regType = TySimd128F4;
  671. }
  672. else if (asmType.which() == Js::AsmJsRetType::Int32x4)
  673. {
  674. regType = TySimd128I4;
  675. }
  676. else if (asmType.which() == Js::AsmJsRetType::Float64x2)
  677. {
  678. regType = TySimd128D2;
  679. }
  680. else
  681. {
  682. Assert(UNREACHED);
  683. }
  684. retReg = IR::RegOpnd::New(nullptr, lowererMDArch.GetRegReturnAsmJs(regType), regType, m_func);
  685. }
  686. else
  687. {
  688. retReg = IR::RegOpnd::New(nullptr, lowererMDArch.GetRegReturn(TyMachReg), TyMachReg, m_func);
  689. }
  690. retInstr->SetDst(retReg);
  691. return this->ChangeToAssign(retInstr);
  692. }
  693. ///----------------------------------------------------------------------------
  694. ///
  695. /// LowererMD::LowerUncondBranch
  696. ///
  697. ///----------------------------------------------------------------------------
  698. IR::Instr *
  699. LowererMD::LowerUncondBranch(IR::Instr * instr)
  700. {
  701. instr->m_opcode = Js::OpCode::JMP;
  702. return instr;
  703. }
  704. ///----------------------------------------------------------------------------
  705. ///
  706. /// LowererMD::LowerMultiBranch
  707. ///
  708. ///----------------------------------------------------------------------------
  709. IR::Instr *
  710. LowererMD::LowerMultiBranch(IR::Instr * instr)
  711. {
  712. return LowerUncondBranch(instr);
  713. }
  714. ///----------------------------------------------------------------------------
  715. ///
  716. /// LowererMD::LowerUncondBranch
  717. ///
  718. ///----------------------------------------------------------------------------
  719. IR::Instr *
  720. LowererMD::LowerCondBranch(IR::Instr * instr)
  721. {
  722. AssertMsg(instr->GetSrc1() != nullptr, "Expected src opnds on conditional branch");
  723. Assert(!instr->HasBailOutInfo());
  724. IR::Opnd * opndSrc1 = instr->UnlinkSrc1();
  725. IR::Instr * instrPrev = nullptr;
  726. switch (instr->m_opcode)
  727. {
  728. case Js::OpCode::BrTrue_A:
  729. case Js::OpCode::BrFalse_A:
  730. case Js::OpCode::BrNotNull_A:
  731. case Js::OpCode::BrOnObject_A:
  732. case Js::OpCode::BrOnClassConstructor:
  733. Assert(!opndSrc1->IsFloat64());
  734. AssertMsg(instr->GetSrc2() == nullptr, "Expected 1 src on boolean branch");
  735. instrPrev = IR::Instr::New(Js::OpCode::TEST, this->m_func);
  736. instrPrev->SetSrc1(opndSrc1);
  737. instrPrev->SetSrc2(opndSrc1);
  738. instr->InsertBefore(instrPrev);
  739. if (instr->m_opcode != Js::OpCode::BrFalse_A)
  740. {
  741. instr->m_opcode = Js::OpCode::JNE;
  742. }
  743. else
  744. {
  745. instr->m_opcode = Js::OpCode::JEQ;
  746. }
  747. break;
  748. case Js::OpCode::BrOnEmpty:
  749. case Js::OpCode::BrOnNotEmpty:
  750. AssertMsg(0, "BrOnEmpty opcodes should not be passed to MD lowerer");
  751. break;
  752. default:
  753. IR::Opnd * opndSrc2 = instr->UnlinkSrc2();
  754. AssertMsg(opndSrc2 != nullptr, "Expected 2 src's on non-boolean branch");
  755. if (opndSrc1->IsFloat())
  756. {
  757. Assert(opndSrc1->GetType() == opndSrc2->GetType());
  758. instrPrev = IR::Instr::New(opndSrc1->IsFloat64() ? Js::OpCode::COMISD : Js::OpCode::COMISS, m_func);
  759. instrPrev->SetSrc1(opndSrc1);
  760. instrPrev->SetSrc2(opndSrc2);
  761. instr->InsertBefore(instrPrev);
  762. }
  763. else
  764. {
  765. // This check assumes src1 is a variable.
  766. if (opndSrc2->IsIntConstOpnd() && opndSrc2->AsIntConstOpnd()->GetValue() == 0)
  767. {
  768. instrPrev = IR::Instr::New(Js::OpCode::TEST, this->m_func);
  769. instrPrev->SetSrc1(opndSrc1);
  770. instrPrev->SetSrc2(opndSrc1);
  771. instr->InsertBefore(instrPrev);
  772. opndSrc2->Free(this->m_func);
  773. }
  774. else
  775. {
  776. instrPrev = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  777. //
  778. // For 32 bit arithmetic we copy them and set the size of operands to be 32 bits. This is
  779. // relevant only on AMD64.
  780. //
  781. opndSrc1 = instrPrev->SetSrc1(opndSrc1);
  782. opndSrc2 = instrPrev->SetSrc2(opndSrc2);
  783. instr->InsertBefore(instrPrev);
  784. LowererMD::Legalize(instrPrev);
  785. }
  786. }
  787. instr->m_opcode = LowererMD::MDBranchOpcode(instr->m_opcode);
  788. break;
  789. }
  790. return instrPrev;
  791. }
  792. ///----------------------------------------------------------------------------
  793. ///
  794. /// LowererMD::MDBranchOpcode
  795. ///
  796. /// Map HIR branch opcode to machine-dependent equivalent.
  797. ///
  798. ///----------------------------------------------------------------------------
  799. Js::OpCode
  800. LowererMD::MDBranchOpcode(Js::OpCode opcode)
  801. {
  802. switch (opcode)
  803. {
  804. case Js::OpCode::BrSrEq_A:
  805. case Js::OpCode::BrEq_A:
  806. case Js::OpCode::BrSrNotNeq_A:
  807. case Js::OpCode::BrNotNeq_A:
  808. case Js::OpCode::BrAddr_A:
  809. return Js::OpCode::JEQ;
  810. case Js::OpCode::BrSrNeq_A:
  811. case Js::OpCode::BrNeq_A:
  812. case Js::OpCode::BrSrNotEq_A:
  813. case Js::OpCode::BrNotEq_A:
  814. case Js::OpCode::BrNotAddr_A:
  815. return Js::OpCode::JNE;
  816. case Js::OpCode::BrLt_A:
  817. case Js::OpCode::BrNotGe_A:
  818. return Js::OpCode::JLT;
  819. case Js::OpCode::BrLe_A:
  820. case Js::OpCode::BrNotGt_A:
  821. return Js::OpCode::JLE;
  822. case Js::OpCode::BrGt_A:
  823. case Js::OpCode::BrNotLe_A:
  824. return Js::OpCode::JGT;
  825. case Js::OpCode::BrGe_A:
  826. case Js::OpCode::BrNotLt_A:
  827. return Js::OpCode::JGE;
  828. default:
  829. AssertMsg(0, "Branch opcode has no MD mapping");
  830. return opcode;
  831. }
  832. }
  833. Js::OpCode
  834. LowererMD::MDConvertFloat64ToInt32Opcode(const RoundMode roundMode)
  835. {
  836. switch (roundMode)
  837. {
  838. case RoundModeTowardZero:
  839. return Js::OpCode::CVTTSD2SI;
  840. case RoundModeTowardInteger:
  841. return Js::OpCode::Nop;
  842. case RoundModeHalfToEven:
  843. return Js::OpCode::CVTSD2SI;
  844. default:
  845. AssertMsg(0, "RoundMode has no MD mapping.");
  846. return Js::OpCode::Nop;
  847. }
  848. }
  849. Js::OpCode
  850. LowererMD::MDUnsignedBranchOpcode(Js::OpCode opcode)
  851. {
  852. switch (opcode)
  853. {
  854. case Js::OpCode::BrEq_A:
  855. case Js::OpCode::BrSrEq_A:
  856. case Js::OpCode::BrSrNotNeq_A:
  857. case Js::OpCode::BrNotNeq_A:
  858. case Js::OpCode::BrAddr_A:
  859. return Js::OpCode::JEQ;
  860. case Js::OpCode::BrNeq_A:
  861. case Js::OpCode::BrSrNeq_A:
  862. case Js::OpCode::BrSrNotEq_A:
  863. case Js::OpCode::BrNotEq_A:
  864. case Js::OpCode::BrNotAddr_A:
  865. return Js::OpCode::JNE;
  866. case Js::OpCode::BrLt_A:
  867. case Js::OpCode::BrNotGe_A:
  868. return Js::OpCode::JB;
  869. case Js::OpCode::BrLe_A:
  870. case Js::OpCode::BrNotGt_A:
  871. return Js::OpCode::JBE;
  872. case Js::OpCode::BrGt_A:
  873. case Js::OpCode::BrNotLe_A:
  874. return Js::OpCode::JA;
  875. case Js::OpCode::BrGe_A:
  876. case Js::OpCode::BrNotLt_A:
  877. return Js::OpCode::JAE;
  878. default:
  879. AssertMsg(0, "Branch opcode has no MD mapping");
  880. return opcode;
  881. }
  882. }
  883. Js::OpCode LowererMD::MDCompareWithZeroBranchOpcode(Js::OpCode opcode)
  884. {
  885. Assert(opcode == Js::OpCode::BrLt_A || opcode == Js::OpCode::BrGe_A);
  886. return opcode == Js::OpCode::BrLt_A ? Js::OpCode::JSB : Js::OpCode::JNSB;
  887. }
  888. void LowererMD::ChangeToAdd(IR::Instr *const instr, const bool needFlags)
  889. {
  890. Assert(instr);
  891. Assert(instr->GetDst());
  892. Assert(instr->GetSrc1());
  893. Assert(instr->GetSrc2());
  894. if(instr->GetDst()->IsFloat64())
  895. {
  896. Assert(instr->GetSrc1()->IsFloat64());
  897. Assert(instr->GetSrc2()->IsFloat64());
  898. Assert(!needFlags);
  899. instr->m_opcode = Js::OpCode::ADDSD;
  900. return;
  901. }
  902. else if (instr->GetDst()->IsFloat32())
  903. {
  904. Assert(instr->GetSrc1()->IsFloat32());
  905. Assert(instr->GetSrc2()->IsFloat32());
  906. Assert(!needFlags);
  907. instr->m_opcode = Js::OpCode::ADDSS;
  908. return;
  909. }
  910. instr->m_opcode = Js::OpCode::ADD;
  911. MakeDstEquSrc1(instr);
  912. // Prefer INC for add by one
  913. if(instr->GetDst()->IsEqual(instr->GetSrc1()) &&
  914. instr->GetSrc2()->IsIntConstOpnd() &&
  915. instr->GetSrc2()->AsIntConstOpnd()->GetValue() == 1 ||
  916. instr->GetDst()->IsEqual(instr->GetSrc2()) &&
  917. instr->GetSrc1()->IsIntConstOpnd() &&
  918. instr->GetSrc1()->AsIntConstOpnd()->GetValue() == 1)
  919. {
  920. if(instr->GetSrc1()->IsIntConstOpnd())
  921. {
  922. // Swap the operands, such that we would create (dst = INC src2)
  923. instr->SwapOpnds();
  924. }
  925. instr->FreeSrc2();
  926. instr->m_opcode = Js::OpCode::INC;
  927. }
  928. }
  929. void LowererMD::ChangeToSub(IR::Instr *const instr, const bool needFlags)
  930. {
  931. Assert(instr);
  932. Assert(instr->GetDst());
  933. Assert(instr->GetSrc1());
  934. Assert(instr->GetSrc2());
  935. if(instr->GetDst()->IsFloat64())
  936. {
  937. Assert(instr->GetSrc1()->IsFloat64());
  938. Assert(instr->GetSrc2()->IsFloat64());
  939. Assert(!needFlags);
  940. instr->m_opcode = Js::OpCode::SUBSD;
  941. return;
  942. }
  943. // Prefer DEC for sub by one
  944. if(instr->GetDst()->IsEqual(instr->GetSrc1()) &&
  945. instr->GetSrc2()->IsIntConstOpnd() &&
  946. instr->GetSrc2()->AsIntConstOpnd()->GetValue() == 1)
  947. {
  948. instr->FreeSrc2();
  949. instr->m_opcode = Js::OpCode::DEC;
  950. return;
  951. }
  952. instr->m_opcode = Js::OpCode::SUB;
  953. }
  954. void LowererMD::ChangeToShift(IR::Instr *const instr, const bool needFlags)
  955. {
  956. Assert(instr);
  957. Assert(instr->GetDst());
  958. Assert(instr->GetSrc1());
  959. Assert(instr->GetSrc2());
  960. switch(instr->m_opcode)
  961. {
  962. case Js::OpCode::Shl_A:
  963. case Js::OpCode::Shl_I4:
  964. instr->m_opcode = Js::OpCode::SHL;
  965. break;
  966. case Js::OpCode::Shr_A:
  967. case Js::OpCode::Shr_I4:
  968. instr->m_opcode = Js::OpCode::SAR;
  969. break;
  970. case Js::OpCode::ShrU_A:
  971. case Js::OpCode::ShrU_I4:
  972. instr->m_opcode = Js::OpCode::SHR;
  973. break;
  974. default:
  975. Assert(false);
  976. __assume(false);
  977. }
  978. if(instr->GetSrc2()->IsIntConstOpnd())
  979. {
  980. // Only values between 0-31 mean anything
  981. IntConstType value = instr->GetSrc2()->AsIntConstOpnd()->GetValue();
  982. value &= 0x1f;
  983. instr->GetSrc2()->AsIntConstOpnd()->SetValue(value);
  984. }
  985. }
  986. void LowererMD::ChangeToMul(IR::Instr *const instr, bool hasOverflowCheck)
  987. {
  988. // If non-32 bit overflow check is needed, we have to use the IMUL form.
  989. if (hasOverflowCheck && !instr->ShouldCheckFor32BitOverflow() && instr->ShouldCheckForNon32BitOverflow())
  990. {
  991. IR::RegOpnd *regEAX = IR::RegOpnd::New(TyInt32, instr->m_func);
  992. IR::Opnd *temp2 = nullptr;
  993. // MOV eax, src1
  994. regEAX->SetReg(LowererMDArch::GetRegIMulDestLower());
  995. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, regEAX, instr->GetSrc1(), instr->m_func));
  996. if (instr->GetSrc2()->IsImmediateOpnd())
  997. {
  998. // MOV reg, imm
  999. temp2 = IR::RegOpnd::New(TyInt32, instr->m_func);
  1000. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, temp2,
  1001. IR::IntConstOpnd::New((IntConstType)instr->GetSrc2()->GetImmediateValue(), TyInt32, instr->m_func, true),
  1002. instr->m_func));
  1003. }
  1004. // eax = IMUL eax, reg
  1005. instr->m_opcode = Js::OpCode::IMUL;
  1006. instr->ReplaceSrc1(regEAX);
  1007. if (temp2 != nullptr)
  1008. instr->ReplaceSrc2(temp2);
  1009. auto *dst = instr->GetDst()->Copy(instr->m_func);
  1010. instr->ReplaceDst(regEAX);
  1011. // MOV dst, eax
  1012. instr->InsertAfter(IR::Instr::New(Js::OpCode::MOV, dst, regEAX, instr->m_func));
  1013. }
  1014. else
  1015. EmitInt4Instr(instr); // IMUL2
  1016. }
  1017. const uint16
  1018. LowererMD::GetFormalParamOffset()
  1019. {
  1020. //In x86\x64 formal params were offset from EBP by the EBP chain, return address, and the 2 non-user params
  1021. return 4;
  1022. }
  1023. IR::Instr *
  1024. LowererMD::LowerCatch(IR::Instr * instr)
  1025. {
  1026. // t1 = catch => t2(eax) = catch
  1027. // => t1 = t2(eax)
  1028. IR::Opnd *catchObj = instr->UnlinkDst();
  1029. IR::RegOpnd *catchParamReg = IR::RegOpnd::New(TyMachPtr, this->m_func);
  1030. catchParamReg->SetReg(this->lowererMDArch.GetRegReturn(TyMachReg));
  1031. instr->SetDst(catchParamReg);
  1032. instr->InsertAfter(IR::Instr::New(Js::OpCode::MOV, catchObj, catchParamReg, this->m_func));
  1033. return instr->m_prev;
  1034. }
  1035. ///----------------------------------------------------------------------------
  1036. ///
  1037. /// LowererMD::ForceDstToReg
  1038. ///
  1039. ///----------------------------------------------------------------------------
  1040. void
  1041. LowererMD::ForceDstToReg(IR::Instr *instr)
  1042. {
  1043. IR::Opnd * dst = instr->GetDst();
  1044. if (dst->IsRegOpnd())
  1045. {
  1046. return;
  1047. }
  1048. if(dst->IsFloat64())
  1049. {
  1050. instr->SinkDst(Js::OpCode::MOVSD);
  1051. return;
  1052. }
  1053. instr->SinkDst(Js::OpCode::MOV);
  1054. }
  1055. template <bool verify>
  1056. void
  1057. LowererMD::Legalize(IR::Instr *const instr, bool fPostRegAlloc)
  1058. {
  1059. Assert(instr);
  1060. Assert(!instr->isInlineeEntryInstr
  1061. || (instr->m_opcode == Js::OpCode::MOV && instr->GetSrc1()->IsAddrOpnd()));
  1062. switch(instr->m_opcode)
  1063. {
  1064. case Js::OpCode::MOV:
  1065. {
  1066. Assert(instr->GetSrc2() == nullptr);
  1067. IR::Opnd *const dst = instr->GetDst();
  1068. const IRType dstType = dst->GetType();
  1069. IR::Opnd *const src = instr->GetSrc1();
  1070. const IRType srcType = src->GetType();
  1071. if(TySize[dstType] > TySize[srcType])
  1072. {
  1073. if (verify)
  1074. {
  1075. return;
  1076. }
  1077. #if DBG
  1078. switch(dstType)
  1079. {
  1080. case TyInt32:
  1081. case TyUint32:
  1082. #ifdef _M_X64
  1083. case TyInt64:
  1084. case TyUint64:
  1085. #endif
  1086. case TyVar:
  1087. break;
  1088. default:
  1089. Assert(false);
  1090. }
  1091. #endif
  1092. IR::IntConstOpnd *const intConstantSrc = src->IsIntConstOpnd() ? src->AsIntConstOpnd() : nullptr;
  1093. const auto UpdateIntConstantSrc = [&](const size_t extendedValue)
  1094. {
  1095. Assert(intConstantSrc);
  1096. #ifdef _M_X64
  1097. if(TySize[dstType] > sizeof(IntConstType))
  1098. {
  1099. instr->ReplaceSrc1(
  1100. IR::AddrOpnd::New(
  1101. reinterpret_cast<void *>(extendedValue),
  1102. IR::AddrOpndKindConstantVar,
  1103. instr->m_func,
  1104. intConstantSrc->m_dontEncode));
  1105. }
  1106. else
  1107. #endif
  1108. {
  1109. intConstantSrc->SetType(dstType);
  1110. intConstantSrc->SetValue(static_cast<IntConstType>(extendedValue));
  1111. }
  1112. };
  1113. switch(srcType)
  1114. {
  1115. case TyInt8:
  1116. if(intConstantSrc)
  1117. {
  1118. UpdateIntConstantSrc(static_cast<int8>(intConstantSrc->GetValue())); // sign-extend
  1119. break;
  1120. }
  1121. instr->m_opcode = Js::OpCode::MOVSX;
  1122. break;
  1123. case TyUint8:
  1124. if(intConstantSrc)
  1125. {
  1126. UpdateIntConstantSrc(static_cast<uint8>(intConstantSrc->GetValue())); // zero-extend
  1127. break;
  1128. }
  1129. instr->m_opcode = Js::OpCode::MOVZX;
  1130. break;
  1131. case TyInt16:
  1132. if(intConstantSrc)
  1133. {
  1134. UpdateIntConstantSrc(static_cast<int16>(intConstantSrc->GetValue())); // sign-extend
  1135. break;
  1136. }
  1137. instr->m_opcode = Js::OpCode::MOVSXW;
  1138. break;
  1139. case TyUint16:
  1140. if(intConstantSrc)
  1141. {
  1142. UpdateIntConstantSrc(static_cast<uint16>(intConstantSrc->GetValue())); // zero-extend
  1143. break;
  1144. }
  1145. instr->m_opcode = Js::OpCode::MOVZXW;
  1146. break;
  1147. #ifdef _M_X64
  1148. case TyInt32:
  1149. if(intConstantSrc)
  1150. {
  1151. UpdateIntConstantSrc(static_cast<int32>(intConstantSrc->GetValue())); // sign-extend
  1152. break;
  1153. }
  1154. instr->m_opcode = Js::OpCode::MOVSXD;
  1155. break;
  1156. case TyUint32:
  1157. if(intConstantSrc)
  1158. {
  1159. UpdateIntConstantSrc(static_cast<uint32>(intConstantSrc->GetValue())); // zero-extend
  1160. break;
  1161. }
  1162. switch(dst->GetKind())
  1163. {
  1164. case IR::OpndKindReg:
  1165. // (mov r0.u32, r1.u32) clears the upper 32 bits of r0
  1166. dst->SetType(TyUint32);
  1167. instr->m_opcode = Js::OpCode::MOV_TRUNC;
  1168. break;
  1169. case IR::OpndKindSym:
  1170. case IR::OpndKindIndir:
  1171. case IR::OpndKindMemRef:
  1172. // Even if the src is a reg, we don't know if the upper 32 bits are zero. Copy the value to a
  1173. // reg first to zero-extend it to 64 bits, and then copy the 64-bit value to the original dst.
  1174. instr->HoistSrc1(Js::OpCode::MOV_TRUNC);
  1175. instr->GetSrc1()->SetType(dstType);
  1176. break;
  1177. default:
  1178. Assert(false);
  1179. __assume(false);
  1180. }
  1181. break;
  1182. #endif
  1183. default:
  1184. Assert(false);
  1185. __assume(false);
  1186. }
  1187. }
  1188. else if (TySize[dstType] < TySize[srcType])
  1189. {
  1190. instr->GetSrc1()->SetType(dst->GetType());
  1191. }
  1192. if(instr->m_opcode == Js::OpCode::MOV)
  1193. {
  1194. uint src1Forms = L_Reg | L_Mem | L_Ptr; // Allow 64 bit values in x64 as well
  1195. #if _M_X64
  1196. if (dst->IsMemoryOpnd())
  1197. {
  1198. // Only allow <= 32 bit values
  1199. src1Forms = L_Reg | L_Imm32;
  1200. }
  1201. #endif
  1202. LegalizeOpnds<verify>(
  1203. instr,
  1204. L_Reg | L_Mem,
  1205. src1Forms,
  1206. L_None);
  1207. }
  1208. else
  1209. {
  1210. LegalizeOpnds<verify>(
  1211. instr,
  1212. L_Reg,
  1213. L_Reg | L_Mem,
  1214. L_None);
  1215. }
  1216. break;
  1217. }
  1218. case Js::OpCode::MOVSD:
  1219. case Js::OpCode::MOVSS:
  1220. {
  1221. Assert(instr->GetDst()->GetType() == (instr->m_opcode == Js::OpCode::MOVSD? TyFloat64 : TyFloat32) || instr->GetDst()->IsSimd128());
  1222. Assert(instr->GetSrc1()->GetType() == (instr->m_opcode == Js::OpCode::MOVSD ? TyFloat64 : TyFloat32) || instr->GetSrc1()->IsSimd128());
  1223. LegalizeOpnds<verify>(
  1224. instr,
  1225. L_Reg | L_Mem,
  1226. instr->GetDst()->IsMemoryOpnd()?
  1227. L_Reg : L_Reg | L_Mem, // LegalizeOpnds doesn't check if dst/src1 are both memopnd, check it here.
  1228. L_None);
  1229. break;
  1230. }
  1231. case Js::OpCode::MOVUPS:
  1232. case Js::OpCode::MOVAPS:
  1233. {
  1234. LegalizeOpnds<verify>(
  1235. instr,
  1236. L_Reg | L_Mem,
  1237. instr->GetDst()->IsMemoryOpnd()?
  1238. L_Reg : L_Reg | L_Mem, // LegalizeOpnds doesn't check if dst/src1 are both memopnd, check it here.
  1239. L_None);
  1240. break;
  1241. }
  1242. case Js::OpCode::CMP:
  1243. LegalizeOpnds<verify>(
  1244. instr,
  1245. L_None,
  1246. L_Reg | L_Mem,
  1247. L_Reg | L_Mem | L_Imm32);
  1248. break;
  1249. case Js::OpCode::TEST:
  1250. if(instr->GetSrc1()->IsImmediateOpnd() && !instr->GetSrc2()->IsImmediateOpnd() ||
  1251. instr->GetSrc2()->IsMemoryOpnd() && !instr->GetSrc1()->IsMemoryOpnd())
  1252. {
  1253. if (verify)
  1254. {
  1255. AssertMsg(false, "Missing legalization");
  1256. return;
  1257. }
  1258. instr->SwapOpnds();
  1259. }
  1260. LegalizeOpnds<verify>(
  1261. instr,
  1262. L_None,
  1263. L_Reg | L_Mem,
  1264. L_Reg | L_Imm32);
  1265. break;
  1266. case Js::OpCode::COMISD:
  1267. case Js::OpCode::COMISS:
  1268. case Js::OpCode::UCOMISD:
  1269. case Js::OpCode::UCOMISS:
  1270. LegalizeOpnds<verify>(
  1271. instr,
  1272. L_None,
  1273. L_Reg,
  1274. L_Reg | L_Mem);
  1275. break;
  1276. case Js::OpCode::INC:
  1277. case Js::OpCode::DEC:
  1278. case Js::OpCode::NEG:
  1279. MakeDstEquSrc1<verify>(instr);
  1280. LegalizeOpnds<verify>(
  1281. instr,
  1282. L_Reg | L_Mem,
  1283. L_Reg | L_Mem,
  1284. L_None);
  1285. break;
  1286. case Js::OpCode::ADD:
  1287. case Js::OpCode::SUB:
  1288. case Js::OpCode::AND:
  1289. case Js::OpCode::OR:
  1290. case Js::OpCode::XOR:
  1291. MakeDstEquSrc1<verify>(instr);
  1292. LegalizeOpnds<verify>(
  1293. instr,
  1294. L_Reg | L_Mem,
  1295. L_Reg | L_Mem,
  1296. L_Reg | L_Mem | L_Imm32);
  1297. break;
  1298. case Js::OpCode::ADDSD:
  1299. case Js::OpCode::ADDPS:
  1300. case Js::OpCode::ADDPD:
  1301. case Js::OpCode::SUBSD:
  1302. case Js::OpCode::ADDSS:
  1303. case Js::OpCode::SUBSS:
  1304. case Js::OpCode::ANDPS:
  1305. case Js::OpCode::ANDPD:
  1306. case Js::OpCode::ANDNPS:
  1307. case Js::OpCode::ANDNPD:
  1308. case Js::OpCode::DIVPS:
  1309. case Js::OpCode::DIVPD:
  1310. case Js::OpCode::MAXPD:
  1311. case Js::OpCode::MAXPS:
  1312. case Js::OpCode::MINPD:
  1313. case Js::OpCode::MINPS:
  1314. case Js::OpCode::MULPD:
  1315. case Js::OpCode::MULPS:
  1316. case Js::OpCode::ORPS:
  1317. case Js::OpCode::PADDD:
  1318. case Js::OpCode::PAND:
  1319. case Js::OpCode::PCMPEQD:
  1320. case Js::OpCode::PCMPGTD:
  1321. case Js::OpCode::PMULUDQ:
  1322. case Js::OpCode::POR:
  1323. case Js::OpCode::PSUBD:
  1324. case Js::OpCode::PXOR:
  1325. case Js::OpCode::SUBPD:
  1326. case Js::OpCode::SUBPS:
  1327. case Js::OpCode::XORPS:
  1328. case Js::OpCode::CMPLTPS:
  1329. case Js::OpCode::CMPLEPS:
  1330. case Js::OpCode::CMPEQPS:
  1331. case Js::OpCode::CMPNEQPS:
  1332. case Js::OpCode::CMPLTPD:
  1333. case Js::OpCode::CMPLEPD:
  1334. case Js::OpCode::CMPEQPD:
  1335. case Js::OpCode::CMPNEQPD:
  1336. case Js::OpCode::PUNPCKLDQ:
  1337. MakeDstEquSrc1<verify>(instr);
  1338. LegalizeOpnds<verify>(
  1339. instr,
  1340. L_Reg,
  1341. L_Reg,
  1342. L_Reg | L_Mem);
  1343. break;
  1344. case Js::OpCode::SHL:
  1345. case Js::OpCode::SHR:
  1346. case Js::OpCode::SAR:
  1347. if (verify)
  1348. {
  1349. Assert(instr->GetSrc2()->IsIntConstOpnd()
  1350. || instr->GetSrc2()->AsRegOpnd()->GetReg() == LowererMDArch::GetRegShiftCount());
  1351. }
  1352. else
  1353. {
  1354. if(!instr->GetSrc2()->IsIntConstOpnd())
  1355. {
  1356. IR::Instr *const newInstr = instr->HoistSrc2(Js::OpCode::MOV);
  1357. newInstr->GetDst()->AsRegOpnd()->SetReg(LowererMDArch::GetRegShiftCount());
  1358. instr->GetSrc2()->AsRegOpnd()->SetReg(LowererMDArch::GetRegShiftCount());
  1359. }
  1360. instr->GetSrc2()->SetType(TyUint8);
  1361. }
  1362. MakeDstEquSrc1<verify>(instr);
  1363. LegalizeOpnds<verify>(
  1364. instr,
  1365. L_Reg | L_Mem,
  1366. L_Reg | L_Mem,
  1367. L_Reg | L_Imm32);
  1368. break;
  1369. case Js::OpCode::IMUL2:
  1370. MakeDstEquSrc1<verify>(instr); // the encoder does not support IMUL3 r, r/m, imm
  1371. LegalizeOpnds<verify>(
  1372. instr,
  1373. L_Reg,
  1374. L_Reg,
  1375. L_Reg | L_Mem | L_Imm32); // for L_Imm32, the encoder converts it into an IMUL3
  1376. break;
  1377. case Js::OpCode::LZCNT:
  1378. case Js::OpCode::BSR:
  1379. LegalizeOpnds<verify>(
  1380. instr,
  1381. L_Reg,
  1382. L_Reg | L_Mem,
  1383. L_None);
  1384. break;
  1385. case Js::OpCode::LEA:
  1386. Assert(instr->GetDst()->IsRegOpnd());
  1387. Assert(instr->GetSrc1()->IsIndirOpnd() || instr->GetSrc1()->IsSymOpnd());
  1388. Assert(!instr->GetSrc2());
  1389. break;
  1390. case Js::OpCode::PSRLDQ:
  1391. case Js::OpCode::PSLLDQ:
  1392. MakeDstEquSrc1<verify>(instr);
  1393. LegalizeOpnds<verify>(
  1394. instr,
  1395. L_Reg,
  1396. L_Reg,
  1397. L_Imm32);
  1398. break;
  1399. }
  1400. #if DBG
  1401. // Asserting general rules
  1402. // There should be at most 1 memory opnd in an instruction
  1403. if (instr->GetDst() && instr->GetDst()->IsMemoryOpnd())
  1404. {
  1405. // All memref address need to fit in a dword
  1406. Assert(!instr->GetDst()->IsMemRefOpnd() || Math::FitsInDWord((size_t)instr->GetDst()->AsMemRefOpnd()->GetMemLoc()));
  1407. if (instr->GetSrc1())
  1408. {
  1409. Assert(instr->GetSrc1()->IsEqual(instr->GetDst()) || !instr->GetSrc1()->IsMemoryOpnd());
  1410. if (instr->GetSrc2())
  1411. {
  1412. Assert(!instr->GetSrc2()->IsMemoryOpnd());
  1413. }
  1414. }
  1415. }
  1416. else if (instr->GetSrc1() && instr->GetSrc1()->IsMemoryOpnd())
  1417. {
  1418. // All memref address need to fit in a dword
  1419. Assert(!instr->GetSrc1()->IsMemRefOpnd() || Math::FitsInDWord((size_t)instr->GetSrc1()->AsMemRefOpnd()->GetMemLoc()));
  1420. Assert(!instr->GetSrc2() || !instr->GetSrc2()->IsMemoryOpnd());
  1421. }
  1422. else if (instr->GetSrc2() && instr->GetSrc2()->IsMemRefOpnd())
  1423. {
  1424. // All memref address need to fit in a dword
  1425. Assert(Math::FitsInDWord((size_t)instr->GetSrc2()->AsMemRefOpnd()->GetMemLoc()));
  1426. }
  1427. // Non-MOV (second operand) immediate need to fit in DWORD for AMD64
  1428. Assert(!instr->GetSrc2() || !instr->GetSrc2()->IsImmediateOpnd()
  1429. || (TySize[instr->GetSrc2()->GetType()] != 8) || Math::FitsInDWord(instr->GetSrc2()->GetImmediateValue()));
  1430. #endif
  1431. }
  1432. template <bool verify>
  1433. void LowererMD::LegalizeOpnds(IR::Instr *const instr, const uint dstForms, const uint src1Forms, uint src2Forms)
  1434. {
  1435. Assert(instr);
  1436. Assert(!instr->GetDst() == !dstForms);
  1437. Assert(!instr->GetSrc1() == !src1Forms);
  1438. Assert(!instr->GetSrc2() == !src2Forms);
  1439. Assert(src1Forms || !src2Forms);
  1440. const auto NormalizeForms = [](uint forms) -> uint
  1441. {
  1442. #ifdef _M_X64
  1443. if(forms & L_Ptr)
  1444. {
  1445. forms |= L_Imm32;
  1446. }
  1447. #else
  1448. if(forms & (L_Imm32 | L_Ptr))
  1449. {
  1450. forms |= L_Imm32 | L_Ptr;
  1451. }
  1452. #endif
  1453. return forms;
  1454. };
  1455. if(dstForms)
  1456. {
  1457. LegalizeDst<verify>(instr, NormalizeForms(dstForms));
  1458. }
  1459. if(!src1Forms)
  1460. {
  1461. return;
  1462. }
  1463. LegalizeSrc<verify>(instr, instr->GetSrc1(), NormalizeForms(src1Forms));
  1464. if(src2Forms & L_Mem && instr->GetSrc1()->IsMemoryOpnd())
  1465. {
  1466. src2Forms ^= L_Mem;
  1467. }
  1468. if(src2Forms)
  1469. {
  1470. LegalizeSrc<verify>(instr, instr->GetSrc2(), NormalizeForms(src2Forms));
  1471. }
  1472. }
  1473. template <bool verify>
  1474. void LowererMD::LegalizeDst(IR::Instr *const instr, const uint forms)
  1475. {
  1476. Assert(instr);
  1477. Assert(forms);
  1478. IR::Opnd *dst = instr->GetDst();
  1479. Assert(dst);
  1480. switch(dst->GetKind())
  1481. {
  1482. case IR::OpndKindReg:
  1483. Assert(forms & L_Reg);
  1484. return;
  1485. case IR::OpndKindMemRef:
  1486. {
  1487. IR::MemRefOpnd *const memRefOpnd = dst->AsMemRefOpnd();
  1488. if(!LowererMDArch::IsLegalMemLoc(memRefOpnd))
  1489. {
  1490. if (verify)
  1491. {
  1492. AssertMsg(false, "Missing legalization");
  1493. return;
  1494. }
  1495. dst = instr->HoistMemRefAddress(memRefOpnd, Js::OpCode::MOV);
  1496. }
  1497. // fall through
  1498. }
  1499. case IR::OpndKindSym:
  1500. case IR::OpndKindIndir:
  1501. if(forms & L_Mem)
  1502. {
  1503. return;
  1504. }
  1505. break;
  1506. default:
  1507. Assert(false);
  1508. __assume(false);
  1509. }
  1510. if (verify)
  1511. {
  1512. AssertMsg(false, "Missing legalization");
  1513. return;
  1514. }
  1515. // Use a reg dst, then store that reg into the original dst
  1516. Assert(forms & L_Reg);
  1517. const IRType irType = dst->GetType();
  1518. IR::RegOpnd *const regOpnd = IR::RegOpnd::New(irType, instr->m_func);
  1519. regOpnd->SetValueType(dst->GetValueType());
  1520. instr->UnlinkDst();
  1521. instr->SetDst(regOpnd);
  1522. instr->InsertAfter(IR::Instr::New(GetStoreOp(irType), dst, regOpnd, instr->m_func));
  1523. // If the original dst is the same as one of the srcs, hoist a src into the same reg and replace the same srcs with the reg
  1524. const bool equalsSrc1 = instr->GetSrc1() && dst->IsEqual(instr->GetSrc1());
  1525. const bool equalsSrc2 = instr->GetSrc2() && dst->IsEqual(instr->GetSrc2());
  1526. if(!(equalsSrc1 || equalsSrc2))
  1527. {
  1528. return;
  1529. }
  1530. const Js::OpCode loadOpCode = GetLoadOp(irType);
  1531. if(equalsSrc1)
  1532. {
  1533. instr->HoistSrc1(loadOpCode, RegNOREG, regOpnd->m_sym);
  1534. if(equalsSrc2)
  1535. {
  1536. instr->ReplaceSrc2(regOpnd);
  1537. }
  1538. }
  1539. else
  1540. {
  1541. instr->HoistSrc2(loadOpCode, RegNOREG, regOpnd->m_sym);
  1542. }
  1543. }
  1544. template <bool verify>
  1545. void LowererMD::LegalizeSrc(IR::Instr *const instr, IR::Opnd *src, const uint forms)
  1546. {
  1547. Assert(instr);
  1548. Assert(src);
  1549. Assert(src == instr->GetSrc1() || src == instr->GetSrc2());
  1550. Assert(forms);
  1551. switch(src->GetKind())
  1552. {
  1553. case IR::OpndKindReg:
  1554. Assert(forms & L_Reg);
  1555. return;
  1556. case IR::OpndKindIntConst:
  1557. Assert(!instr->isInlineeEntryInstr);
  1558. if(forms & L_Imm32)
  1559. {
  1560. return;
  1561. }
  1562. break;
  1563. case IR::OpndKindFloatConst:
  1564. break; // assume for now that it always needs to be hoisted
  1565. case IR::OpndKindAddr:
  1566. if (forms & L_Ptr)
  1567. {
  1568. return;
  1569. }
  1570. #ifdef _M_X64
  1571. {
  1572. IR::AddrOpnd * addrOpnd = src->AsAddrOpnd();
  1573. if ((forms & L_Imm32) && ((TySize[addrOpnd->GetType()] != 8) ||
  1574. (!instr->isInlineeEntryInstr && Math::FitsInDWord((size_t)addrOpnd->m_address))))
  1575. {
  1576. // the address fits in 32-bit, no need to hoist
  1577. return;
  1578. }
  1579. if (verify)
  1580. {
  1581. AssertMsg(false, "Missing legalization");
  1582. return;
  1583. }
  1584. // The actual value for inlinee entry instr isn't determined until encoder
  1585. // So it need to be hoisted conventionally.
  1586. if (!instr->isInlineeEntryInstr)
  1587. {
  1588. Assert(forms & L_Reg);
  1589. IR::IndirOpnd * indirOpnd = instr->m_func->GetTopFunc()->GetConstantAddressIndirOpnd(addrOpnd->m_address, addrOpnd->GetAddrOpndKind(), TyMachPtr, Js::OpCode::MOV);
  1590. if (indirOpnd != nullptr)
  1591. {
  1592. if (indirOpnd->GetOffset() == 0)
  1593. {
  1594. instr->ReplaceSrc(src, indirOpnd->GetBaseOpnd());
  1595. }
  1596. else
  1597. {
  1598. // Hoist the address load as LEA [reg + offset]
  1599. // with the reg = MOV <some address within 32-bit range at the start of the function
  1600. IR::RegOpnd * regOpnd = IR::RegOpnd::New(TyMachPtr, instr->m_func);
  1601. Lowerer::InsertLea(regOpnd, indirOpnd, instr);
  1602. instr->ReplaceSrc(src, regOpnd);
  1603. }
  1604. return;
  1605. }
  1606. }
  1607. }
  1608. #endif
  1609. break;
  1610. case IR::OpndKindMemRef:
  1611. {
  1612. IR::MemRefOpnd *const memRefOpnd = src->AsMemRefOpnd();
  1613. if(!LowererMDArch::IsLegalMemLoc(memRefOpnd))
  1614. {
  1615. if (verify)
  1616. {
  1617. AssertMsg(false, "Missing legalization");
  1618. return;
  1619. }
  1620. src = instr->HoistMemRefAddress(memRefOpnd, Js::OpCode::MOV);
  1621. }
  1622. // fall through
  1623. }
  1624. case IR::OpndKindSym:
  1625. case IR::OpndKindIndir:
  1626. if(forms & L_Mem)
  1627. {
  1628. return;
  1629. }
  1630. break;
  1631. case IR::OpndKindHelperCall:
  1632. case IR::OpndKindLabel:
  1633. Assert(!instr->isInlineeEntryInstr);
  1634. Assert(forms & L_Ptr);
  1635. return;
  1636. default:
  1637. Assert(false);
  1638. __assume(false);
  1639. }
  1640. if (verify)
  1641. {
  1642. AssertMsg(false, "Missing legalization");
  1643. return;
  1644. }
  1645. // Hoist the src into a reg
  1646. Assert(forms & L_Reg);
  1647. Assert(!(instr->GetDst() && instr->GetDst()->IsEqual(src)));
  1648. const Js::OpCode loadOpCode = GetLoadOp(src->GetType());
  1649. if(src == instr->GetSrc2())
  1650. {
  1651. instr->HoistSrc2(loadOpCode);
  1652. return;
  1653. }
  1654. const bool equalsSrc2 = instr->GetSrc2() && src->IsEqual(instr->GetSrc2());
  1655. IR::Instr * hoistInstr = instr->HoistSrc1(loadOpCode);
  1656. if(equalsSrc2)
  1657. {
  1658. instr->ReplaceSrc2(hoistInstr->GetDst());
  1659. }
  1660. hoistInstr->isInlineeEntryInstr = instr->isInlineeEntryInstr;
  1661. instr->isInlineeEntryInstr = false;
  1662. }
  1663. template void LowererMD::Legalize<false>(IR::Instr *const instr, bool fPostRegAlloc);
  1664. template void LowererMD::LegalizeOpnds<false>(IR::Instr *const instr, const uint dstForms, const uint src1Forms, uint src2Forms);
  1665. template void LowererMD::LegalizeDst<false>(IR::Instr *const instr, const uint forms);
  1666. template void LowererMD::LegalizeSrc<false>(IR::Instr *const instr, IR::Opnd *src, const uint forms);
  1667. template void LowererMD::MakeDstEquSrc1<false>(IR::Instr *const instr);
  1668. #if DBG
  1669. template void LowererMD::Legalize<true>(IR::Instr *const instr, bool fPostRegAlloc);
  1670. template void LowererMD::LegalizeOpnds<true>(IR::Instr *const instr, const uint dstForms, const uint src1Forms, uint src2Forms);
  1671. template void LowererMD::LegalizeDst<true>(IR::Instr *const instr, const uint forms);
  1672. template void LowererMD::LegalizeSrc<true>(IR::Instr *const instr, IR::Opnd *src, const uint forms);
  1673. template void LowererMD::MakeDstEquSrc1<true>(IR::Instr *const instr);
  1674. #endif
  1675. IR::Instr *
  1676. LowererMD::LoadFunctionObjectOpnd(IR::Instr *instr, IR::Opnd *&functionObjOpnd)
  1677. {
  1678. IR::Opnd * src1 = instr->GetSrc1();
  1679. IR::Instr * instrPrev = instr->m_prev;
  1680. if (src1 == nullptr)
  1681. {
  1682. IR::RegOpnd * regOpnd = IR::RegOpnd::New(TyMachPtr, m_func);
  1683. StackSym *paramSym = StackSym::New(TyMachPtr, m_func);
  1684. IR::SymOpnd *paramOpnd = IR::SymOpnd::New(paramSym, TyMachPtr, m_func);
  1685. this->m_func->SetArgOffset(paramSym, 2 * MachPtr);
  1686. IR::Instr * mov1 = IR::Instr::New(Js::OpCode::MOV, regOpnd, paramOpnd, m_func);
  1687. instr->InsertBefore(mov1);
  1688. functionObjOpnd = mov1->GetDst()->AsRegOpnd();
  1689. instrPrev = mov1;
  1690. }
  1691. else
  1692. {
  1693. // Inlinee, use the function object opnd on the instruction
  1694. functionObjOpnd = instr->UnlinkSrc1();
  1695. if (!functionObjOpnd->IsRegOpnd())
  1696. {
  1697. Assert(functionObjOpnd->IsAddrOpnd());
  1698. }
  1699. }
  1700. return instrPrev;
  1701. }
  1702. IR::Instr *
  1703. LowererMD::LowerLdSuper(IR::Instr *instr, IR::JnHelperMethod helperOpCode)
  1704. {
  1705. IR::Opnd * functionObjOpnd;
  1706. IR::Instr * instrPrev = LoadFunctionObjectOpnd(instr, functionObjOpnd);
  1707. m_lowerer->LoadScriptContext(instr);
  1708. LoadHelperArgument(instr, functionObjOpnd);
  1709. ChangeToHelperCall(instr, helperOpCode);
  1710. return instrPrev;
  1711. }
  1712. void
  1713. LowererMD::GenerateFastDivByPow2(IR::Instr *instr)
  1714. {
  1715. //
  1716. // Given:
  1717. // dst = Div_A src1, src2
  1718. // where src2 == power of 2
  1719. //
  1720. // Generate:
  1721. // MOV s1, src1
  1722. // AND s1, 0xFFFF000000000000 | (src2Value-1) ----- test for tagged int and divisibility by src2Value [int32]
  1723. // AND s1, 0x00000001 | ((src2Value-1)<<1) [int31]
  1724. // CMP s1, AtomTag_IntPtr
  1725. // JNE $divbyhalf
  1726. // MOV s1, src1
  1727. // SAR s1, log2(src2Value) ------ perform the divide
  1728. // OR s1, 1
  1729. // MOV dst, s1
  1730. // JMP $done
  1731. // $divbyhalf:
  1732. // AND s1, 0xFFFF000000000000 | (src2Value-1>>1) ----- test for tagged int and divisibility by src2Value /2 [int32]
  1733. // AND s1, 0x00000001 | ((src2Value-1)) [int31]
  1734. // CMP s1, AtomTag_IntPtr
  1735. // JNE $helper
  1736. // MOV s1, src1
  1737. // SAR s1, log2(src2Value) [int32]
  1738. // SAR s1, log2(src2Value) + 1 ------ removes the tag and divides [int31]
  1739. // PUSH s1
  1740. // PUSH 0xXXXXXXXX (ScriptContext)
  1741. // CALL Op_FinishOddDivByPow2
  1742. // MOV dst, eax
  1743. // JMP $done
  1744. // $helper:
  1745. // ...
  1746. // $done:
  1747. //
  1748. if (instr->GetSrc1()->IsRegOpnd() && instr->GetSrc1()->AsRegOpnd()->IsNotInt())
  1749. return;
  1750. IR::Opnd *dst = instr->GetDst();
  1751. IR::Opnd *src1 = instr->GetSrc1();
  1752. IR::AddrOpnd *src2 = instr->GetSrc2()->IsAddrOpnd() ? instr->GetSrc2()->AsAddrOpnd() : nullptr;
  1753. IR::LabelInstr *divbyhalf = IR::LabelInstr::New(Js::OpCode::Label, m_func);
  1754. IR::LabelInstr *helper = IR::LabelInstr::New(Js::OpCode::Label, m_func, true);
  1755. IR::LabelInstr *done = IR::LabelInstr::New(Js::OpCode::Label, m_func);
  1756. IR::RegOpnd *s1 = IR::RegOpnd::New(TyVar, m_func);
  1757. AnalysisAssert(src2);
  1758. Assert(src2->IsVar() && Js::TaggedInt::Is(src2->m_address) && (Math::IsPow2(Js::TaggedInt::ToInt32(src2->m_address))));
  1759. int32 src2Value = Js::TaggedInt::ToInt32(src2->m_address);
  1760. // MOV s1, src1
  1761. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, s1, src1, m_func));
  1762. #if INT32VAR
  1763. // dontEncode as src2 is a power of 2.
  1764. IR::Opnd *constant = IR::AddrOpnd::New((Js::Var)(0xFFFF000000000000 | (src2Value - 1)), IR::AddrOpndKindConstantVar, m_func, /* dontEncode = */ true);
  1765. #else
  1766. IR::Opnd *constant = IR::IntConstOpnd::New((0x00000001 | ((src2Value - 1) << 1)), TyInt32, m_func);
  1767. #endif
  1768. // AND s1, constant
  1769. {
  1770. IR::Instr * andInstr = IR::Instr::New(Js::OpCode::AND, s1, s1, constant, m_func);
  1771. instr->InsertBefore(andInstr);
  1772. Legalize(andInstr);
  1773. }
  1774. // CMP s1, AtomTag_IntPtr
  1775. {
  1776. IR::Instr *cmp = IR::Instr::New(Js::OpCode::CMP, m_func);
  1777. cmp->SetSrc1(s1);
  1778. cmp->SetSrc2(IR::AddrOpnd::New((Js::Var)(Js::AtomTag_IntPtr), IR::AddrOpndKindConstantVar, m_func, /* dontEncode = */ true));
  1779. instr->InsertBefore(cmp);
  1780. Legalize(cmp);
  1781. }
  1782. // JNE $divbyhalf
  1783. instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JNE, divbyhalf, m_func));
  1784. // MOV s1, src1
  1785. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, s1, src1, m_func));
  1786. s1 = s1->UseWithNewType(TyInt32, m_func)->AsRegOpnd();
  1787. // SAR s1, log2(src2Value)
  1788. instr->InsertBefore(IR::Instr::New(Js::OpCode::SAR, s1, s1, IR::IntConstOpnd::New(Math::Log2(src2Value), TyInt32, m_func), m_func));
  1789. if(s1->GetSize() != MachPtr)
  1790. {
  1791. s1 = s1->UseWithNewType(TyMachPtr, m_func)->AsRegOpnd();
  1792. }
  1793. #if INT32VAR
  1794. GenerateInt32ToVarConversion(s1, instr);
  1795. #else
  1796. // OR s1, 1
  1797. instr->InsertBefore(IR::Instr::New(Js::OpCode::OR, s1, s1, IR::IntConstOpnd::New(1, TyInt32, m_func), m_func));
  1798. #endif
  1799. // MOV dst, s1
  1800. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, dst, s1, m_func));
  1801. // JMP $done
  1802. instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JMP, done, m_func));
  1803. // $divbyhalf:
  1804. instr->InsertBefore(divbyhalf);
  1805. #if INT32VAR
  1806. constant = IR::AddrOpnd::New((Js::Var)(0xFFFF000000000000 | ((src2Value-1) >> 1)), IR::AddrOpndKindConstantVar, m_func, /* dontEncode = */ true);
  1807. #else
  1808. constant = IR::IntConstOpnd::New((0x00000001 | (src2Value-1)), TyInt32, m_func);
  1809. #endif
  1810. // AND s1, constant
  1811. {
  1812. IR::Instr * andInstr = IR::Instr::New(Js::OpCode::AND, s1, s1, constant, m_func);
  1813. instr->InsertBefore(andInstr);
  1814. Legalize(andInstr);
  1815. }
  1816. // CMP s1, AtomTag_IntPtr
  1817. {
  1818. IR::Instr *cmp = IR::Instr::New(Js::OpCode::CMP, m_func);
  1819. cmp->SetSrc1(s1);
  1820. cmp->SetSrc2(IR::AddrOpnd::New((Js::Var)(Js::AtomTag_IntPtr), IR::AddrOpndKindConstantVar, m_func, /* dontEncode = */ true));
  1821. instr->InsertBefore(cmp);
  1822. Legalize(cmp);
  1823. }
  1824. // JNE $helper
  1825. instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JNE, helper, m_func));
  1826. // MOV s1, src1
  1827. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, s1, src1, m_func));
  1828. s1 = s1->UseWithNewType(TyInt32, this->m_func)->AsRegOpnd();
  1829. #if INT32VAR
  1830. IR::Opnd* shiftOpnd = IR::IntConstOpnd::New(Math::Log2(src2Value), TyInt32, m_func);
  1831. #else
  1832. IR::Opnd* shiftOpnd = IR::IntConstOpnd::New(Math::Log2(src2Value) + 1, TyInt32, m_func);
  1833. #endif
  1834. // SAR s1, shiftOpnd
  1835. instr->InsertBefore(IR::Instr::New(Js::OpCode::SAR, s1, s1, shiftOpnd, m_func));
  1836. // PUSH s1
  1837. // PUSH ScriptContext
  1838. // CALL Op_FinishOddDivByPow2
  1839. {
  1840. IR::JnHelperMethod helperMethod;
  1841. if (instr->dstIsTempNumber)
  1842. {
  1843. IR::Opnd *tempOpnd;
  1844. helperMethod = IR::HelperOp_FinishOddDivByPow2InPlace;
  1845. Assert(dst->IsRegOpnd());
  1846. StackSym * tempNumberSym = this->m_lowerer->GetTempNumberSym(dst, instr->dstIsTempNumberTransferred);
  1847. IR::Instr *load = this->LoadStackAddress(tempNumberSym);
  1848. instr->InsertBefore(load);
  1849. tempOpnd = load->GetDst();
  1850. this->lowererMDArch.LoadHelperArgument(instr, tempOpnd);
  1851. }
  1852. else
  1853. {
  1854. helperMethod = IR::HelperOp_FinishOddDivByPow2;
  1855. }
  1856. m_lowerer->LoadScriptContext(instr);
  1857. lowererMDArch.LoadHelperArgument(instr, s1);
  1858. IR::Instr *call = IR::Instr::New(Js::OpCode::Call, dst, IR::HelperCallOpnd::New(helperMethod, m_func), m_func);
  1859. instr->InsertBefore(call);
  1860. lowererMDArch.LowerCall(call, 0);
  1861. }
  1862. // JMP $done
  1863. instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JMP, done, m_func));
  1864. // $helper:
  1865. instr->InsertBefore(helper);
  1866. // $done:
  1867. instr->InsertAfter(done);
  1868. }
  1869. bool
  1870. LowererMD::GenerateFastBrString(IR::BranchInstr *branchInstr)
  1871. {
  1872. Assert(branchInstr->m_opcode == Js::OpCode::BrSrEq_A ||
  1873. branchInstr->m_opcode == Js::OpCode::BrSrNeq_A ||
  1874. branchInstr->m_opcode == Js::OpCode::BrEq_A ||
  1875. branchInstr->m_opcode == Js::OpCode::BrNeq_A ||
  1876. branchInstr->m_opcode == Js::OpCode::BrSrNotEq_A ||
  1877. branchInstr->m_opcode == Js::OpCode::BrSrNotNeq_A ||
  1878. branchInstr->m_opcode == Js::OpCode::BrNotEq_A ||
  1879. branchInstr->m_opcode == Js::OpCode::BrNotNeq_A
  1880. );
  1881. IR::Instr* instrInsert = branchInstr;
  1882. IR::RegOpnd *srcReg1 = branchInstr->GetSrc1()->IsRegOpnd() ? branchInstr->GetSrc1()->AsRegOpnd() : nullptr;
  1883. IR::RegOpnd *srcReg2 = branchInstr->GetSrc2()->IsRegOpnd() ? branchInstr->GetSrc2()->AsRegOpnd() : nullptr;
  1884. if (srcReg1 && srcReg2)
  1885. {
  1886. if (srcReg1->IsTaggedInt() || srcReg2->IsTaggedInt())
  1887. {
  1888. return false;
  1889. }
  1890. bool isSrc1String = srcReg1->GetValueType().IsLikelyString();
  1891. bool isSrc2String = srcReg2->GetValueType().IsLikelyString();
  1892. //Left and right hand are both LikelyString
  1893. if (!isSrc1String || !isSrc2String)
  1894. {
  1895. return false;
  1896. }
  1897. }
  1898. else
  1899. {
  1900. return false;
  1901. }
  1902. // Generates:
  1903. // GenerateObjectTest(src1);
  1904. // MOV s1, [srcReg1 + offset(Type)]
  1905. // CMP type, static_string_type
  1906. // JNE $helper
  1907. // GenerateObjectTest(src2);
  1908. // MOV s2, [srcReg2 + offset(Type)]
  1909. // CMP type, static_string_type
  1910. // JNE $fail ; if src1 is string but not src2, src1 !== src2 if isStrict
  1911. // MOV s3, [srcReg1,offset(m_charLength)]
  1912. // CMP [srcReg2,offset(m_charLength)], s3
  1913. // JNE $fail <--- length check done
  1914. // MOV s4, [srcReg1,offset(m_pszValue)]
  1915. // CMP srcReg1, srcReg2
  1916. // JEQ $success
  1917. // CMP s4, 0
  1918. // JEQ $helper
  1919. // MOV s5, [srcReg2,offset(m_pszValue)]
  1920. // CMP s5, 0
  1921. // JEQ $helper
  1922. // MOV s6,[s4]
  1923. // CMP [s5], s6 -First character comparison
  1924. // JNE $fail
  1925. // SHL length, 1
  1926. // eax = memcmp(src1String, src2String, length*2)
  1927. // TEST eax, eax
  1928. // JEQ $success
  1929. // JMP $fail
  1930. IR::LabelInstr *labelHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
  1931. IR::LabelInstr *labelTarget = branchInstr->GetTarget();
  1932. IR::LabelInstr *labelBranchFail = nullptr;
  1933. IR::LabelInstr *labelBranchSuccess = nullptr;
  1934. bool isEqual = false;
  1935. bool isStrict = false;
  1936. switch (branchInstr->m_opcode)
  1937. {
  1938. case Js::OpCode::BrSrEq_A:
  1939. case Js::OpCode::BrSrNotNeq_A:
  1940. isStrict = true;
  1941. case Js::OpCode::BrEq_A:
  1942. case Js::OpCode::BrNotNeq_A:
  1943. labelBranchFail = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  1944. labelBranchSuccess = labelTarget;
  1945. branchInstr->InsertAfter(labelBranchFail);
  1946. isEqual = true;
  1947. break;
  1948. case Js::OpCode::BrSrNeq_A:
  1949. case Js::OpCode::BrSrNotEq_A:
  1950. isStrict = true;
  1951. case Js::OpCode::BrNeq_A:
  1952. case Js::OpCode::BrNotEq_A:
  1953. labelBranchSuccess = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  1954. labelBranchFail = labelTarget;
  1955. branchInstr->InsertAfter(labelBranchSuccess);
  1956. isEqual = false;
  1957. break;
  1958. default:
  1959. Assert(UNREACHED);
  1960. __assume(0);
  1961. }
  1962. this->m_lowerer->GenerateStringTest(srcReg1, instrInsert, labelHelper);
  1963. if (isStrict)
  1964. {
  1965. this->m_lowerer->GenerateStringTest(srcReg2, instrInsert, labelBranchFail);
  1966. }
  1967. else
  1968. {
  1969. this->m_lowerer->GenerateStringTest(srcReg2, instrInsert, labelHelper);
  1970. }
  1971. // MOV s3, [srcReg1,offset(m_charLength)]
  1972. // CMP [srcReg2,offset(m_charLength)], s3
  1973. // JNE $branchfail
  1974. IR::RegOpnd * src1LengthOpnd = IR::RegOpnd::New(TyUint32, this->m_func);
  1975. IR::Instr * loadSrc1LengthInstr = IR::Instr::New(Js::OpCode::MOV, src1LengthOpnd,
  1976. IR::IndirOpnd::New(srcReg1, Js::JavascriptString::GetOffsetOfcharLength(), TyUint32,
  1977. this->m_func), this->m_func);
  1978. instrInsert->InsertBefore(loadSrc1LengthInstr);
  1979. IR::Instr * checkLengthInstr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  1980. checkLengthInstr->SetSrc1(IR::IndirOpnd::New(srcReg2, Js::JavascriptString::GetOffsetOfcharLength(), TyUint32, this->m_func));
  1981. checkLengthInstr->SetSrc2(src1LengthOpnd);
  1982. instrInsert->InsertBefore(checkLengthInstr);
  1983. instrInsert->InsertBefore(IR::BranchInstr::New(Js::OpCode::JNE, labelBranchFail, this->m_func));
  1984. // MOV s4, [src1,offset(m_pszValue)]
  1985. // CMP s4, 0
  1986. // JEQ $helper
  1987. // MOV s5, [src2,offset(m_pszValue)]
  1988. // CMP s5, 0
  1989. // JEQ $helper
  1990. IR::RegOpnd * src1FlatString = IR::RegOpnd::New(TyMachPtr, this->m_func);
  1991. IR::Instr * loadSrc1StringInstr = IR::Instr::New(Js::OpCode::MOV, src1FlatString,
  1992. IR::IndirOpnd::New(srcReg1, Js::JavascriptString::GetOffsetOfpszValue(), TyMachPtr,
  1993. this->m_func), this->m_func);
  1994. instrInsert->InsertBefore(loadSrc1StringInstr);
  1995. IR::Instr * checkFlatString1Instr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  1996. checkFlatString1Instr->SetSrc1(src1FlatString);
  1997. checkFlatString1Instr->SetSrc2(IR::IntConstOpnd::New(0, TyUint32, this->m_func));
  1998. instrInsert->InsertBefore(checkFlatString1Instr);
  1999. instrInsert->InsertBefore(IR::BranchInstr::New(Js::OpCode::JEQ, labelHelper, this->m_func));
  2000. IR::RegOpnd * src2FlatString = IR::RegOpnd::New(TyMachPtr, this->m_func);
  2001. IR::Instr * loadSrc2StringInstr = IR::Instr::New(Js::OpCode::MOV, src2FlatString,
  2002. IR::IndirOpnd::New(srcReg2, Js::JavascriptString::GetOffsetOfpszValue(), TyMachPtr,
  2003. this->m_func), this->m_func);
  2004. instrInsert->InsertBefore(loadSrc2StringInstr);
  2005. // CMP srcReg1, srcReg2 - Ptr comparison
  2006. // JEQ $branchSuccess
  2007. IR::Instr * comparePtrInstr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  2008. comparePtrInstr->SetSrc1(srcReg1);
  2009. comparePtrInstr->SetSrc2(srcReg2);
  2010. instrInsert->InsertBefore(comparePtrInstr);
  2011. instrInsert->InsertBefore(IR::BranchInstr::New(Js::OpCode::JEQ, labelBranchSuccess, this->m_func));
  2012. IR::Instr * checkFlatString2Instr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  2013. checkFlatString2Instr->SetSrc1(src2FlatString);
  2014. checkFlatString2Instr->SetSrc2(IR::IntConstOpnd::New(0, TyUint32, this->m_func));
  2015. instrInsert->InsertBefore(checkFlatString2Instr);
  2016. instrInsert->InsertBefore(IR::BranchInstr::New(Js::OpCode::JEQ, labelHelper, this->m_func));
  2017. // MOV s6,[s4]
  2018. // CMP [s5], s6 -First character comparison
  2019. // JNE $branchfail
  2020. IR::RegOpnd * src1FirstChar = IR::RegOpnd::New(TyUint16, this->m_func);
  2021. IR::Instr * loadSrc1CharInstr = IR::Instr::New(Js::OpCode::MOV, src1FirstChar,
  2022. IR::IndirOpnd::New(src1FlatString, 0, TyUint16,
  2023. this->m_func), this->m_func);
  2024. instrInsert->InsertBefore(loadSrc1CharInstr);
  2025. IR::Instr * compareFirstCharInstr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  2026. compareFirstCharInstr->SetSrc1(IR::IndirOpnd::New(src2FlatString, 0, TyUint16, this->m_func));
  2027. compareFirstCharInstr->SetSrc2(src1FirstChar);
  2028. instrInsert->InsertBefore(compareFirstCharInstr);
  2029. instrInsert->InsertBefore(IR::BranchInstr::New(Js::OpCode::JNE, labelBranchFail, this->m_func));
  2030. // SHL length, 1
  2031. instrInsert->InsertBefore(IR::Instr::New(Js::OpCode::SHL, src1LengthOpnd, src1LengthOpnd, IR::IntConstOpnd::New(1, TyUint8, this->m_func), this->m_func));
  2032. // eax = memcmp(src1String, src2String, length*2)
  2033. this->LoadHelperArgument(branchInstr, src1LengthOpnd);
  2034. this->LoadHelperArgument(branchInstr, src1FlatString);
  2035. this->LoadHelperArgument(branchInstr, src2FlatString);
  2036. IR::RegOpnd *dstOpnd = IR::RegOpnd::New(TyInt32, this->m_func);
  2037. IR::Instr *instrCall = IR::Instr::New(Js::OpCode::CALL, dstOpnd, IR::HelperCallOpnd::New(IR::HelperMemCmp, this->m_func), this->m_func);
  2038. branchInstr->InsertBefore(instrCall);
  2039. this->LowerCall(instrCall, 3);
  2040. // TEST eax, eax
  2041. IR::Instr *instrTest = IR::Instr::New(Js::OpCode::TEST, this->m_func);
  2042. instrTest->SetSrc1(instrCall->GetDst());
  2043. instrTest->SetSrc2(instrCall->GetDst());
  2044. instrInsert->InsertBefore(instrTest);
  2045. // JEQ success
  2046. instrInsert->InsertBefore(IR::BranchInstr::New(Js::OpCode::JEQ, labelBranchSuccess, this->m_func));
  2047. // JMP fail
  2048. instrInsert->InsertBefore(IR::BranchInstr::New(Js::OpCode::JMP, labelBranchFail, this->m_func));
  2049. branchInstr->InsertBefore(labelHelper);
  2050. IR::LabelInstr *labelFallthrough = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  2051. branchInstr->InsertAfter(labelFallthrough);
  2052. #if DBG
  2053. // The fast-path for strings assumes the case where 2 strings are equal is rare, and marks that path as 'helper'.
  2054. // This breaks the helper label dbchecks as it can result in non-helper blocks be reachable only from helper blocks.
  2055. // Use m_isHelperToNonHelperBranch and m_noHelperAssert to fix this.
  2056. IR::Instr *blockEndInstr;
  2057. if (isEqual)
  2058. {
  2059. blockEndInstr = labelHelper->GetNextBranchOrLabel();
  2060. }
  2061. else
  2062. {
  2063. blockEndInstr = branchInstr->GetNextBranchOrLabel();
  2064. }
  2065. if (blockEndInstr->IsBranchInstr())
  2066. {
  2067. blockEndInstr->AsBranchInstr()->m_isHelperToNonHelperBranch = true;
  2068. }
  2069. labelFallthrough->m_noHelperAssert = true;
  2070. #endif
  2071. return true;
  2072. }
  2073. ///----------------------------------------------------------------------------
  2074. ///
  2075. /// LowererMD::GenerateFastCmSrEqConst
  2076. ///
  2077. ///----------------------------------------------------------------------------
  2078. bool
  2079. LowererMD::GenerateFastCmSrEqConst(IR::Instr *instr)
  2080. {
  2081. //
  2082. // Given:
  2083. // s1 = CmSrEq_A s2, s3
  2084. // where either s2 or s3 is 'null', 'true' or 'false'
  2085. //
  2086. // Generate:
  2087. //
  2088. // CMP s2, s3
  2089. // JEQ $mov_true
  2090. // MOV s1, Library.GetFalse()
  2091. // JMP $done
  2092. // $mov_true:
  2093. // MOV s1, Library.GetTrue()
  2094. // $done:
  2095. //
  2096. Assert(m_lowerer->IsConstRegOpnd(instr->GetSrc2()->AsRegOpnd()));
  2097. IR::Opnd *opnd = instr->GetSrc1();
  2098. IR::RegOpnd *opndReg = instr->GetSrc2()->AsRegOpnd();
  2099. IR::LabelInstr *labelMovTrue = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  2100. IR::LabelInstr *labelDone = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  2101. if (!opnd->IsRegOpnd())
  2102. {
  2103. IR::RegOpnd *lhsReg = IR::RegOpnd::New(TyVar, m_func);
  2104. IR::Instr *mov = IR::Instr::New(Js::OpCode::MOV, lhsReg, opnd, m_func);
  2105. instr->InsertBefore(mov);
  2106. opnd = lhsReg;
  2107. }
  2108. Assert(opnd->IsRegOpnd());
  2109. // CMP s2, s3
  2110. // JEQ $mov_true
  2111. this->m_lowerer->InsertCompareBranch(opnd, opndReg->m_sym->GetConstOpnd(), Js::OpCode::BrEq_A, labelMovTrue, instr);
  2112. // MOV s1, 'false'
  2113. IR::Instr *instrMov = IR::Instr::New(Js::OpCode::MOV,
  2114. instr->GetDst(),
  2115. m_lowerer->LoadLibraryValueOpnd(instr, LibraryValue::ValueFalse),
  2116. m_func);
  2117. instr->InsertBefore(instrMov);
  2118. // JMP $done
  2119. IR::BranchInstr *jmp = IR::BranchInstr::New(Js::OpCode::JMP, labelDone, this->m_func);
  2120. instr->InsertBefore(jmp);
  2121. // $mov_true:
  2122. instr->InsertBefore(labelMovTrue);
  2123. // MOV s1, 'true'
  2124. instr->m_opcode = Js::OpCode::MOV;
  2125. instr->UnlinkSrc1();
  2126. instr->UnlinkSrc2();
  2127. instr->SetSrc1(m_lowerer->LoadLibraryValueOpnd(instr, LibraryValue::ValueTrue));
  2128. instr->ClearBailOutInfo();
  2129. Legalize(instr);
  2130. // $done:
  2131. instr->InsertAfter(labelDone);
  2132. return true;
  2133. }
  2134. ///----------------------------------------------------------------------------
  2135. ///
  2136. /// LowererMD::GenerateFastCmXxTaggedInt
  2137. ///
  2138. ///----------------------------------------------------------------------------
  2139. bool LowererMD::GenerateFastCmXxTaggedInt(IR::Instr *instr)
  2140. {
  2141. // The idea is to do an inline compare if we can prove that both sources
  2142. // are tagged ints (i.e., are vars with the low bit set).
  2143. //
  2144. // Given:
  2145. //
  2146. // Cmxx_A dst, src1, src2
  2147. //
  2148. // Generate:
  2149. //
  2150. // (If not Int31's, goto $helper)
  2151. // MOV r1, src1
  2152. // if (==, !=, !== or ===)
  2153. // SUB r1, src2
  2154. // NEG r1 // Sets CF if r1 != 0
  2155. // SBB r1, r1 // CF == 1 ? r1 = -1 : r1 = 0
  2156. // else
  2157. // MOV r2, 0
  2158. // CMP r1, src2
  2159. // SETcc r2
  2160. // DEC r2
  2161. // set r1 to r2
  2162. // AND r1, (notEqualResult - equalResult)
  2163. // ADD r1, equalResult
  2164. // MOV dst, r1
  2165. // JMP $fallthru
  2166. // $helper:
  2167. // (caller will generate normal helper call sequence)
  2168. // $fallthru:
  2169. IR::Opnd * src1 = instr->GetSrc1();
  2170. IR::Opnd * src2 = instr->GetSrc2();
  2171. IR::Opnd * dst = instr->GetDst();
  2172. IR::RegOpnd * r1 = IR::RegOpnd::New(TyMachReg, m_func);
  2173. IR::LabelInstr * helper = IR::LabelInstr::New(Js::OpCode::Label, m_func, true);
  2174. IR::LabelInstr * fallthru = IR::LabelInstr::New(Js::OpCode::Label, m_func);
  2175. Assert(src1 && src2 && dst);
  2176. // Not tagged ints?
  2177. if (src1->IsRegOpnd() && src1->AsRegOpnd()->IsNotInt())
  2178. {
  2179. return false;
  2180. }
  2181. if (src2->IsRegOpnd() && src2->AsRegOpnd()->IsNotInt())
  2182. {
  2183. return false;
  2184. }
  2185. bool isNeqOp = instr->m_opcode == Js::OpCode::CmSrNeq_A || instr->m_opcode == Js::OpCode::CmNeq_A;
  2186. Js::Var notEqualResult = m_func->GetScriptContext()->GetLibrary()->GetTrueOrFalse(isNeqOp);
  2187. Js::Var equalResult = m_func->GetScriptContext()->GetLibrary()->GetTrueOrFalse(!isNeqOp);
  2188. // Tagged ints?
  2189. bool isTaggedInts = false;
  2190. if (src1->IsTaggedInt())
  2191. {
  2192. if (src2->IsTaggedInt())
  2193. {
  2194. isTaggedInts = true;
  2195. }
  2196. }
  2197. if (!isTaggedInts)
  2198. {
  2199. this->GenerateSmIntPairTest(instr, src1, src2, helper);
  2200. }
  2201. // MOV r1, src1
  2202. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, r1, src1, m_func));
  2203. Js::OpCode setCC_Opcode = Js::OpCode::Nop;
  2204. switch(instr->m_opcode)
  2205. {
  2206. case Js::OpCode::CmSrEq_A:
  2207. case Js::OpCode::CmEq_A:
  2208. break;
  2209. case Js::OpCode::CmSrNeq_A:
  2210. case Js::OpCode::CmNeq_A:
  2211. break;
  2212. case Js::OpCode::CmGe_A:
  2213. setCC_Opcode = Js::OpCode::SETGE;
  2214. break;
  2215. case Js::OpCode::CmGt_A:
  2216. setCC_Opcode = Js::OpCode::SETG;
  2217. break;
  2218. case Js::OpCode::CmLe_A:
  2219. setCC_Opcode = Js::OpCode::SETLE;
  2220. break;
  2221. case Js::OpCode::CmLt_A:
  2222. setCC_Opcode = Js::OpCode::SETL;
  2223. break;
  2224. default:
  2225. Assume(UNREACHED);
  2226. }
  2227. if (setCC_Opcode == Js::OpCode::Nop)
  2228. {
  2229. // SUB r1, src2
  2230. IR::Instr * subInstr = IR::Instr::New(Js::OpCode::SUB, r1, r1, src2, m_func);
  2231. instr->InsertBefore(subInstr);
  2232. Legalize(subInstr); // src2 may need legalizing
  2233. // NEG r1
  2234. instr->InsertBefore(IR::Instr::New(Js::OpCode::NEG, r1, r1, m_func));
  2235. // SBB r1, r1
  2236. instr->InsertBefore(IR::Instr::New(Js::OpCode::SBB, r1, r1, r1, m_func));
  2237. }
  2238. else
  2239. {
  2240. IR::Instr *instrNew;
  2241. IR::RegOpnd *r2 = IR::RegOpnd::New(TyMachPtr, this->m_func);
  2242. // MOV r2, 0
  2243. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, r2, IR::IntConstOpnd::New(0, TyInt32, this->m_func), m_func));
  2244. // CMP r1, src2
  2245. IR::Opnd *r1_32 = r1->UseWithNewType(TyInt32, this->m_func);
  2246. IR::Opnd *src2_32 =src2->UseWithNewType(TyInt32, this->m_func);
  2247. instrNew = IR::Instr::New(Js::OpCode::CMP, m_func);
  2248. instrNew->SetSrc1(r1_32);
  2249. instrNew->SetSrc2(src2_32);
  2250. instr->InsertBefore(instrNew);
  2251. // SETcc r2
  2252. IR::RegOpnd *r2_i8 = (IR::RegOpnd*) r2->UseWithNewType(TyInt8, this->m_func);
  2253. instrNew = IR::Instr::New(setCC_Opcode, r2_i8, r2_i8, m_func);
  2254. instr->InsertBefore(instrNew);
  2255. // DEC r2
  2256. instr->InsertBefore(IR::Instr::New(Js::OpCode::DEC, r2, r2, m_func));
  2257. // r1 <- r2
  2258. r1 = r2;
  2259. }
  2260. // AND r1, (notEqualResult - equalResult)
  2261. {
  2262. IR::Instr * and = IR::Instr::New(Js::OpCode::AND, r1, r1, m_func);
  2263. and->SetSrc2(IR::AddrOpnd::New((void*)((size_t)notEqualResult - (size_t)equalResult), IR::AddrOpndKind::AddrOpndKindDynamicMisc, this->m_func));
  2264. instr->InsertBefore(and);
  2265. Legalize(and);
  2266. }
  2267. // ADD r1, equalResult
  2268. {
  2269. IR::Instr * add = IR::Instr::New(Js::OpCode::ADD, r1, r1, m_func);
  2270. add->SetSrc2(IR::AddrOpnd::New(equalResult, IR::AddrOpndKind::AddrOpndKindDynamicVar, this->m_func));
  2271. instr->InsertBefore(add);
  2272. Legalize(add);
  2273. }
  2274. // MOV dst, r1
  2275. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, dst, r1, m_func));
  2276. if (isTaggedInts)
  2277. {
  2278. instr->Remove();
  2279. return true;
  2280. }
  2281. // JMP $fallthru
  2282. instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JMP, fallthru, m_func));
  2283. instr->InsertBefore(helper);
  2284. instr->InsertAfter(fallthru);
  2285. return false;
  2286. }
  2287. void LowererMD::GenerateFastCmXxR8(IR::Instr *instr)
  2288. {
  2289. GenerateFastCmXx(instr);
  2290. }
  2291. void LowererMD::GenerateFastCmXxI4(IR::Instr *instr)
  2292. {
  2293. GenerateFastCmXx(instr);
  2294. }
  2295. void LowererMD::GenerateFastCmXx(IR::Instr *instr)
  2296. {
  2297. // For float src:
  2298. // dst = MOV 0/1
  2299. // (U)COMISD src1, src2
  2300. // JP $done
  2301. // dst.i8 = SetCC dst.i8
  2302. // $done:
  2303. // for int src:
  2304. // CMP src1, src2
  2305. // dst = MOV 0 / false
  2306. // dst.i8 = SetCC dst.i8 / CMOCcc true
  2307. IR::Opnd * src1 = instr->UnlinkSrc1();
  2308. IR::Opnd * src2 = instr->UnlinkSrc2();
  2309. IR::Opnd * dst = instr->UnlinkDst();
  2310. IR::Opnd * tmp = dst;
  2311. bool isIntDst = dst->AsRegOpnd()->m_sym->IsInt32();
  2312. bool isFloatSrc = src1->IsFloat();
  2313. Assert(!isFloatSrc || src2->IsFloat());
  2314. Assert(!isFloatSrc || isIntDst);
  2315. Assert(!isFloatSrc || AutoSystemInfo::Data.SSE2Available());
  2316. IR::Opnd *opnd;
  2317. IR::Instr *newInstr;
  2318. Assert(src1->IsRegOpnd());
  2319. IR::Instr * done;
  2320. if (isFloatSrc)
  2321. {
  2322. done = IR::LabelInstr::New(Js::OpCode::Label, m_func);
  2323. instr->InsertBefore(done);
  2324. }
  2325. else
  2326. {
  2327. done = instr;
  2328. }
  2329. if (isIntDst)
  2330. {
  2331. // reg = MOV 0 will get peeped to XOR reg, reg which sets the flags.
  2332. // Put the MOV before the CMP, but use a tmp if dst == src1/src2
  2333. if (dst->IsEqual(src1) || dst->IsEqual(src2))
  2334. {
  2335. tmp = IR::RegOpnd::New(dst->GetType(), this->m_func);
  2336. }
  2337. // dst = MOV 0
  2338. if (isFloatSrc && instr->m_opcode == Js::OpCode::CmNeq_A)
  2339. {
  2340. opnd = IR::IntConstOpnd::New(1, TyInt32, this->m_func);
  2341. }
  2342. else
  2343. {
  2344. opnd = IR::IntConstOpnd::New(0, TyInt32, this->m_func);
  2345. }
  2346. newInstr = IR::Instr::New(Js::OpCode::MOV, tmp, opnd, this->m_func);
  2347. done->InsertBefore(newInstr);
  2348. }
  2349. Js::OpCode cmpOp;
  2350. if (isFloatSrc)
  2351. {
  2352. if (instr->m_opcode == Js::OpCode::CmEq_A || instr->m_opcode == Js::OpCode::CmNeq_A)
  2353. {
  2354. cmpOp = src1->IsFloat64() ? Js::OpCode::UCOMISD : Js::OpCode::UCOMISS;
  2355. }
  2356. else
  2357. {
  2358. cmpOp = src1->IsFloat64() ? Js::OpCode::COMISD : Js::OpCode::COMISS;
  2359. }
  2360. }
  2361. else
  2362. {
  2363. cmpOp = Js::OpCode::CMP;
  2364. }
  2365. // CMP src1, src2
  2366. newInstr = IR::Instr::New(cmpOp, this->m_func);
  2367. newInstr->SetSrc1(src1);
  2368. newInstr->SetSrc2(src2);
  2369. done->InsertBefore(newInstr);
  2370. if (isFloatSrc)
  2371. {
  2372. newInstr = IR::BranchInstr::New(Js::OpCode::JP, done->AsLabelInstr(), this->m_func);
  2373. done->InsertBefore(newInstr);
  2374. }
  2375. if (!isIntDst)
  2376. {
  2377. opnd = this->m_lowerer->LoadLibraryValueOpnd(instr, LibraryValue::ValueFalse);
  2378. LowererMD::CreateAssign(tmp, opnd, done);
  2379. }
  2380. Js::OpCode useCC;
  2381. switch(instr->m_opcode)
  2382. {
  2383. case Js::OpCode::CmEq_I4:
  2384. case Js::OpCode::CmEq_A:
  2385. useCC = isIntDst ? Js::OpCode::SETE : Js::OpCode::CMOVE;
  2386. break;
  2387. case Js::OpCode::CmNeq_I4:
  2388. case Js::OpCode::CmNeq_A:
  2389. useCC = isIntDst ? Js::OpCode::SETNE : Js::OpCode::CMOVNE;
  2390. break;
  2391. case Js::OpCode::CmGe_I4:
  2392. useCC = isIntDst ? Js::OpCode::SETGE : Js::OpCode::CMOVGE;
  2393. break;
  2394. case Js::OpCode::CmGt_I4:
  2395. useCC = isIntDst ? Js::OpCode::SETG : Js::OpCode::CMOVG;
  2396. break;
  2397. case Js::OpCode::CmLe_I4:
  2398. useCC = isIntDst ? Js::OpCode::SETLE : Js::OpCode::CMOVLE;
  2399. break;
  2400. case Js::OpCode::CmLt_I4:
  2401. useCC = isIntDst ? Js::OpCode::SETL : Js::OpCode::CMOVL;
  2402. break;
  2403. case Js::OpCode::CmUnGe_I4:
  2404. case Js::OpCode::CmGe_A:
  2405. useCC = isIntDst ? Js::OpCode::SETAE : Js::OpCode::CMOVAE;
  2406. break;
  2407. case Js::OpCode::CmUnGt_I4:
  2408. case Js::OpCode::CmGt_A:
  2409. useCC = isIntDst ? Js::OpCode::SETA : Js::OpCode::CMOVA;
  2410. break;
  2411. case Js::OpCode::CmUnLe_I4:
  2412. case Js::OpCode::CmLe_A:
  2413. useCC = isIntDst ? Js::OpCode::SETBE : Js::OpCode::CMOVBE;
  2414. break;
  2415. case Js::OpCode::CmUnLt_I4:
  2416. case Js::OpCode::CmLt_A:
  2417. useCC = isIntDst ? Js::OpCode::SETB : Js::OpCode::CMOVB;
  2418. break;
  2419. default:
  2420. useCC = Js::OpCode::InvalidOpCode;
  2421. Assume(UNREACHED);
  2422. }
  2423. if (isIntDst)
  2424. {
  2425. // tmp.i8 = SetCC tmp.i8
  2426. IR::Opnd *tmp_i8 = tmp->UseWithNewType(TyInt8, this->m_func);
  2427. newInstr = IR::Instr::New(useCC, tmp_i8, tmp_i8, this->m_func);
  2428. }
  2429. else
  2430. {
  2431. // regTrue = MOV true
  2432. IR::Opnd *regTrue = IR::RegOpnd::New(TyMachPtr, this->m_func);
  2433. Lowerer::InsertMove(regTrue, this->m_lowerer->LoadLibraryValueOpnd(instr, LibraryValue::ValueTrue), done);
  2434. // tmp = CMOVcc tmp, regTrue
  2435. newInstr = IR::Instr::New(useCC, tmp, tmp, regTrue, this->m_func);
  2436. }
  2437. done->InsertBefore(newInstr);
  2438. if (tmp != dst)
  2439. {
  2440. newInstr = IR::Instr::New(Js::OpCode::MOV, dst, tmp, this->m_func);
  2441. instr->InsertBefore(newInstr);
  2442. }
  2443. instr->Remove();
  2444. }
  2445. IR::Instr * LowererMD::GenerateConvBool(IR::Instr *instr)
  2446. {
  2447. // TEST src1, src1
  2448. // dst = MOV true
  2449. // rf = MOV false
  2450. // dst = CMOV dst, rf
  2451. IR::Instr *instrNew, *instrFirst;
  2452. IR::RegOpnd *dst = instr->GetDst()->AsRegOpnd();
  2453. IR::RegOpnd *regFalse;
  2454. // TEST src1, src2
  2455. instrFirst = instrNew = IR::Instr::New(Js::OpCode::TEST, this->m_func);
  2456. instrNew->SetSrc1(instr->GetSrc1());
  2457. instrNew->SetSrc2(instr->GetSrc1());
  2458. instr->InsertBefore(instrNew);
  2459. // dst = MOV true
  2460. Lowerer::InsertMove(dst, this->m_lowerer->LoadLibraryValueOpnd(instr, LibraryValue::ValueTrue), instr);
  2461. // rf = MOV false
  2462. regFalse = IR::RegOpnd::New(TyMachPtr, this->m_func);
  2463. Lowerer::InsertMove(regFalse, this->m_lowerer->LoadLibraryValueOpnd(instr, LibraryValue::ValueFalse), instr);
  2464. // Add dst as src1 of CMOV to create a pseudo use of dst. Otherwise, the register allocator
  2465. // won't know the previous dst is needed. and needed in the same register as the dst of the CMOV.
  2466. // dst = CMOV dst, rf
  2467. instrNew = IR::Instr::New(Js::OpCode::CMOVE, dst, dst, regFalse, this->m_func);
  2468. instr->InsertBefore(instrNew);
  2469. instr->Remove();
  2470. return instrFirst;
  2471. }
  2472. ///----------------------------------------------------------------------------
  2473. ///
  2474. /// LowererMD::GenerateFastAdd
  2475. ///
  2476. /// NOTE: We assume that only the sum of two Int31's will have 0x2 set. This
  2477. /// is only true until we have an var type with tag == 0x2.
  2478. ///
  2479. ///----------------------------------------------------------------------------
  2480. bool
  2481. LowererMD::GenerateFastAdd(IR::Instr * instrAdd)
  2482. {
  2483. // Given:
  2484. //
  2485. // dst = Add src1, src2
  2486. //
  2487. // Generate:
  2488. //
  2489. // (If not 2 Int31's, jump to $helper.)
  2490. // s1 = MOV src1
  2491. // s1 = DEC s1 -- Get rid of one of the tag [Int31 only]
  2492. // s1 = ADD s1, src2 -- try an inline add
  2493. // JO $helper -- bail if the add overflowed
  2494. // s1 = OR s1, AtomTag_IntPtr [Int32 only]
  2495. // dst = MOV s1
  2496. // JMP $fallthru
  2497. // $helper:
  2498. // (caller generates helper call)
  2499. // $fallthru:
  2500. IR::Instr * instr;
  2501. IR::LabelInstr * labelHelper;
  2502. IR::LabelInstr * labelFallThru;
  2503. IR::Opnd * opndReg;
  2504. IR::Opnd * opndSrc1;
  2505. IR::Opnd * opndSrc2;
  2506. opndSrc1 = instrAdd->GetSrc1();
  2507. opndSrc2 = instrAdd->GetSrc2();
  2508. AssertMsg(opndSrc1 && opndSrc2, "Expected 2 src opnd's on Add instruction");
  2509. // Generate fastpath for Incr_A anyway -
  2510. // Incrementing strings representing integers can be inter-mixed with integers e.g. "1"++ -> converts 1 to an int and thereafter, integer increment is expected.
  2511. if (opndSrc1->IsRegOpnd() && (opndSrc1->AsRegOpnd()->IsNotInt() || opndSrc1->GetValueType().IsString()
  2512. || (instrAdd->m_opcode != Js::OpCode::Incr_A && opndSrc1->GetValueType().IsLikelyString())))
  2513. {
  2514. return false;
  2515. }
  2516. if (opndSrc2->IsRegOpnd() && (opndSrc2->AsRegOpnd()->IsNotInt() ||
  2517. opndSrc2->GetValueType().IsLikelyString()))
  2518. {
  2519. return false;
  2520. }
  2521. // Tagged ints?
  2522. bool isTaggedInts = false;
  2523. if (opndSrc1->IsTaggedInt())
  2524. {
  2525. if (opndSrc2->IsTaggedInt())
  2526. {
  2527. isTaggedInts = true;
  2528. }
  2529. }
  2530. labelHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
  2531. if (!isTaggedInts)
  2532. {
  2533. // (If not 2 Int31's, jump to $helper.)
  2534. this->GenerateSmIntPairTest(instrAdd, opndSrc1, opndSrc2, labelHelper);
  2535. }
  2536. if (opndSrc1->IsAddrOpnd())
  2537. {
  2538. // If opnd1 is a constant, just swap them.
  2539. IR::Opnd *opndTmp = opndSrc1;
  2540. opndSrc1 = opndSrc2;
  2541. opndSrc2 = opndTmp;
  2542. }
  2543. //
  2544. // For 32 bit arithmetic we copy them and set the size of operands to be 32 bits. This is
  2545. // relevant only on AMD64.
  2546. //
  2547. opndSrc1 = opndSrc1->UseWithNewType(TyInt32, this->m_func);
  2548. // s1 = MOV src1
  2549. opndReg = IR::RegOpnd::New(TyInt32, this->m_func);
  2550. instr = IR::Instr::New(Js::OpCode::MOV, opndReg, opndSrc1, this->m_func);
  2551. instrAdd->InsertBefore(instr);
  2552. #if !INT32VAR
  2553. // Do the DEC in place
  2554. if (opndSrc2->IsAddrOpnd())
  2555. {
  2556. Assert(opndSrc2->AsAddrOpnd()->GetAddrOpndKind() == IR::AddrOpndKindConstantVar);
  2557. opndSrc2 = IR::IntConstOpnd::New(*((int *)&(opndSrc2->AsAddrOpnd()->m_address)) - 1, TyInt32, this->m_func, opndSrc2->AsAddrOpnd()->m_dontEncode);
  2558. opndSrc2 = opndSrc2->Use(this->m_func);
  2559. }
  2560. else if (opndSrc2->IsIntConstOpnd())
  2561. {
  2562. Assert(opndSrc2->GetType() == TyInt32);
  2563. opndSrc2 = opndSrc2->Use(this->m_func);
  2564. opndSrc2->AsIntConstOpnd()->DecrValue(1);
  2565. }
  2566. else
  2567. {
  2568. // s1 = DEC s1
  2569. opndSrc2 = opndSrc2->UseWithNewType(TyInt32, this->m_func);
  2570. instr = IR::Instr::New(Js::OpCode::DEC, opndReg, opndReg, this->m_func);
  2571. instrAdd->InsertBefore(instr);
  2572. }
  2573. instr = IR::Instr::New(Js::OpCode::ADD, opndReg, opndReg, opndSrc2, this->m_func);
  2574. #else
  2575. if (opndSrc2->IsAddrOpnd())
  2576. {
  2577. // truncate to untag
  2578. int value = ::Math::PointerCastToIntegralTruncate<int>(opndSrc2->AsAddrOpnd()->m_address);
  2579. if (value == 1)
  2580. {
  2581. instr = IR::Instr::New(Js::OpCode::INC, opndReg, opndReg, this->m_func);
  2582. }
  2583. else
  2584. {
  2585. opndSrc2 = IR::IntConstOpnd::New(value, TyInt32, this->m_func);
  2586. instr = IR::Instr::New(Js::OpCode::ADD, opndReg, opndReg, opndSrc2, this->m_func);
  2587. }
  2588. }
  2589. else
  2590. {
  2591. instr = IR::Instr::New(Js::OpCode::ADD, opndReg, opndReg, opndSrc2, this->m_func);
  2592. }
  2593. #endif
  2594. // s1 = ADD s1, src2
  2595. instrAdd->InsertBefore(instr);
  2596. Legalize(instr);
  2597. // JO $helper
  2598. instr = IR::BranchInstr::New(Js::OpCode::JO, labelHelper, this->m_func);
  2599. instrAdd->InsertBefore(instr);
  2600. //
  2601. // Convert TyInt32 operand, back to TyMachPtr type.
  2602. //
  2603. if(TyMachReg != opndReg->GetType())
  2604. {
  2605. opndReg = opndReg->UseWithNewType(TyMachPtr, this->m_func);
  2606. }
  2607. #if INT32VAR
  2608. // s1 = OR s1, AtomTag_IntPtr
  2609. GenerateInt32ToVarConversion(opndReg, instrAdd);
  2610. #endif
  2611. // dst = MOV s1
  2612. instr = IR::Instr::New(Js::OpCode::MOV, instrAdd->GetDst(), opndReg, this->m_func);
  2613. instrAdd->InsertBefore(instr);
  2614. // JMP $fallthru
  2615. labelFallThru = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  2616. instr = IR::BranchInstr::New(Js::OpCode::JMP, labelFallThru, this->m_func);
  2617. instrAdd->InsertBefore(instr);
  2618. // $helper:
  2619. // (caller generates helper call)
  2620. // $fallthru:
  2621. instrAdd->InsertBefore(labelHelper);
  2622. instrAdd->InsertAfter(labelFallThru);
  2623. return true;
  2624. }
  2625. ///----------------------------------------------------------------------------
  2626. ///
  2627. /// LowererMD::GenerateFastSub
  2628. ///
  2629. ///
  2630. ///----------------------------------------------------------------------------
  2631. bool
  2632. LowererMD::GenerateFastSub(IR::Instr * instrSub)
  2633. {
  2634. // Given:
  2635. //
  2636. // dst = Sub src1, src2
  2637. //
  2638. // Generate:
  2639. //
  2640. // (If not 2 Int31's, jump to $helper.)
  2641. // s1 = MOV src1
  2642. // s1 = SUB s1, src2 -- try an inline sub
  2643. // JO $helper -- bail if the subtract overflowed
  2644. // JNE $helper
  2645. // s1 = INC s1 -- restore the var tag on the result [Int31 only]
  2646. // s1 = OR s1, AtomTag_IntPtr [Int32 only]
  2647. // dst = MOV s1
  2648. // JMP $fallthru
  2649. // $helper:
  2650. // (caller generates helper call)
  2651. // $fallthru:
  2652. IR::Instr * instr;
  2653. IR::LabelInstr * labelHelper;
  2654. IR::LabelInstr * labelFallThru;
  2655. IR::Opnd * opndReg;
  2656. IR::Opnd * opndSrc1;
  2657. IR::Opnd * opndSrc2;
  2658. opndSrc1 = instrSub->GetSrc1();
  2659. opndSrc2 = instrSub->GetSrc2();
  2660. AssertMsg(opndSrc1 && opndSrc2, "Expected 2 src opnd's on Sub instruction");
  2661. // Not tagged ints?
  2662. if (opndSrc1->IsRegOpnd() && opndSrc1->AsRegOpnd()->IsNotInt())
  2663. {
  2664. return false;
  2665. }
  2666. if (opndSrc2->IsRegOpnd() && opndSrc2->AsRegOpnd()->IsNotInt())
  2667. {
  2668. return false;
  2669. }
  2670. // Tagged ints?
  2671. bool isTaggedInts = false;
  2672. if (opndSrc1->IsTaggedInt())
  2673. {
  2674. if (opndSrc2->IsTaggedInt())
  2675. {
  2676. isTaggedInts = true;
  2677. }
  2678. }
  2679. labelHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
  2680. if (!isTaggedInts)
  2681. {
  2682. // (If not 2 Int31's, jump to $helper.)
  2683. this->GenerateSmIntPairTest(instrSub, opndSrc1, opndSrc2, labelHelper);
  2684. }
  2685. //
  2686. // For 32 bit arithmetic we copy them and set the size of operands to be 32 bits. This is
  2687. // relevant only on AMD64.
  2688. //
  2689. opndSrc1 = opndSrc1->UseWithNewType(TyInt32, this->m_func);
  2690. opndSrc2 = opndSrc2->UseWithNewType(TyInt32, this->m_func);
  2691. // s1 = MOV src1
  2692. opndReg = IR::RegOpnd::New(TyInt32, this->m_func);
  2693. instr = IR::Instr::New(Js::OpCode::MOV, opndReg, opndSrc1, this->m_func);
  2694. instrSub->InsertBefore(instr);
  2695. // s1 = SUB s1, src2
  2696. instr = IR::Instr::New(Js::OpCode::SUB, opndReg, opndReg, opndSrc2, this->m_func);
  2697. instrSub->InsertBefore(instr);
  2698. // JO $helper
  2699. instr = IR::BranchInstr::New(Js::OpCode::JO, labelHelper, this->m_func);
  2700. instrSub->InsertBefore(instr);
  2701. #if !INT32VAR
  2702. // s1 = INC s1
  2703. instr = IR::Instr::New(Js::OpCode::INC, opndReg, opndReg, this->m_func);
  2704. instrSub->InsertBefore(instr);
  2705. #endif
  2706. //
  2707. // Convert TyInt32 operand, back to TyMachPtr type.
  2708. //
  2709. if(TyMachReg != opndReg->GetType())
  2710. {
  2711. opndReg = opndReg->UseWithNewType(TyMachPtr, this->m_func);
  2712. }
  2713. #if INT32VAR
  2714. // s1 = OR s1, AtomTag_IntPtr
  2715. GenerateInt32ToVarConversion(opndReg, instrSub);
  2716. #endif
  2717. // dst = MOV s1
  2718. instr = IR::Instr::New(Js::OpCode::MOV, instrSub->GetDst(), opndReg, this->m_func);
  2719. instrSub->InsertBefore(instr);
  2720. // JMP $fallthru
  2721. labelFallThru = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  2722. instr = IR::BranchInstr::New(Js::OpCode::JMP, labelFallThru, this->m_func);
  2723. instrSub->InsertBefore(instr);
  2724. // $helper:
  2725. // (caller generates helper call)
  2726. // $fallthru:
  2727. instrSub->InsertBefore(labelHelper);
  2728. instrSub->InsertAfter(labelFallThru);
  2729. return true;
  2730. }
  2731. ///----------------------------------------------------------------------------
  2732. ///
  2733. /// LowererMD::GenerateFastMul
  2734. ///
  2735. ///----------------------------------------------------------------------------
  2736. bool
  2737. LowererMD::GenerateFastMul(IR::Instr * instrMul)
  2738. {
  2739. // Given:
  2740. //
  2741. // dst = Mul src1, src2
  2742. //
  2743. // Generate:
  2744. //
  2745. // (If not 2 Int31's, jump to $helper.)
  2746. // s1 = MOV src1
  2747. // s1 = DEC s1 -- clear the var tag from the value to be multiplied [Int31 only]
  2748. // s2 = MOV src2
  2749. // s2 = SAR s2, Js::VarTag_Shift -- extract the real src2 amount from the var [Int31 only]
  2750. // s1 = IMUL s1, s2 -- do the signed mul
  2751. // JO $helper -- bail if the result overflowed
  2752. // s3 = MOV s1
  2753. // TEST s3, s3 -- Check result is 0. might be -0. Result is -0 when a negative number is multiplied with 0.
  2754. // JEQ $zero
  2755. // JMP $nonzero
  2756. // $zero: -- result of mul was 0. try to check for -0
  2757. // s2 = ADD s2, src1 -- Add src1 to s2
  2758. // JGT $nonzero -- positive 0. [Int31 only]
  2759. // JGE $nonzero -- positive 0. [Int32 only]
  2760. // dst = ToVar(-0.0) -- load negative 0
  2761. // JMP $fallthru
  2762. // $nonzero:
  2763. // s3 = INC s3 -- restore the var tag on the result [Int31 only]
  2764. // s3 = OR s3, AtomTag_IntPtr [Int32 only]
  2765. // dst= MOV s3
  2766. // JMP $fallthru
  2767. // $helper:
  2768. // (caller generates helper call)
  2769. // $fallthru:
  2770. IR::LabelInstr * labelHelper;
  2771. IR::LabelInstr * labelFallThru;
  2772. IR::LabelInstr * labelNonZero;
  2773. IR::Instr * instr;
  2774. IR::RegOpnd * opndReg1;
  2775. IR::RegOpnd * opndReg2;
  2776. IR::RegOpnd * s3;
  2777. IR::Opnd * opndSrc1;
  2778. IR::Opnd * opndSrc2;
  2779. opndSrc1 = instrMul->GetSrc1();
  2780. opndSrc2 = instrMul->GetSrc2();
  2781. AssertMsg(opndSrc1 && opndSrc2, "Expected 2 src opnd's on mul instruction");
  2782. if (opndSrc1->IsRegOpnd() && opndSrc1->AsRegOpnd()->IsNotInt())
  2783. {
  2784. return true;
  2785. }
  2786. if (opndSrc2->IsRegOpnd() && opndSrc2->AsRegOpnd()->IsNotInt())
  2787. {
  2788. return true;
  2789. }
  2790. // (If not 2 Int31's, jump to $helper.)
  2791. labelHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
  2792. labelNonZero = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  2793. labelFallThru = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  2794. this->GenerateSmIntPairTest(instrMul, opndSrc1, opndSrc2, labelHelper);
  2795. //
  2796. // For 32 bit arithmetic we copy them and set the size of operands to be 32 bits. This is
  2797. // relevant only on AMD64.
  2798. //
  2799. opndSrc1 = opndSrc1->UseWithNewType(TyInt32, this->m_func);
  2800. opndSrc2 = opndSrc2->UseWithNewType(TyInt32, this->m_func);
  2801. if (opndSrc1->IsImmediateOpnd())
  2802. {
  2803. IR::Opnd * temp = opndSrc1;
  2804. opndSrc1 = opndSrc2;
  2805. opndSrc2 = temp;
  2806. }
  2807. // s1 = MOV src1
  2808. opndReg1 = IR::RegOpnd::New(TyInt32, this->m_func);
  2809. instr = IR::Instr::New(Js::OpCode::MOV, opndReg1, opndSrc1, this->m_func);
  2810. instrMul->InsertBefore(instr);
  2811. #if !INT32VAR
  2812. // s1 = DEC s1
  2813. instr = IR::Instr::New(Js::OpCode::DEC, opndReg1, opndReg1, this->m_func);
  2814. instrMul->InsertBefore(instr);
  2815. #endif
  2816. if (opndSrc2->IsImmediateOpnd())
  2817. {
  2818. Assert(opndSrc2->IsAddrOpnd() && opndSrc2->AsAddrOpnd()->IsVar());
  2819. IR::Opnd *opnd2 = IR::IntConstOpnd::New(Js::TaggedInt::ToInt32(opndSrc2->AsAddrOpnd()->m_address), TyInt32, this->m_func);
  2820. // s2 = MOV src2
  2821. opndReg2 = IR::RegOpnd::New(TyInt32, this->m_func);
  2822. instr = IR::Instr::New(Js::OpCode::MOV, opndReg2, opnd2, this->m_func);
  2823. instrMul->InsertBefore(instr);
  2824. }
  2825. else
  2826. {
  2827. // s2 = MOV src2
  2828. opndReg2 = IR::RegOpnd::New(TyInt32, this->m_func);
  2829. instr = IR::Instr::New(Js::OpCode::MOV, opndReg2, opndSrc2, this->m_func);
  2830. instrMul->InsertBefore(instr);
  2831. #if !INT32VAR
  2832. // s2 = SAR s2, Js::VarTag_Shift
  2833. instr = IR::Instr::New(
  2834. Js::OpCode::SAR, opndReg2, opndReg2,
  2835. IR::IntConstOpnd::New(Js::VarTag_Shift, TyInt8, this->m_func), this->m_func);
  2836. instrMul->InsertBefore(instr);
  2837. #endif
  2838. }
  2839. // s1 = IMUL s1, s2
  2840. instr = IR::Instr::New(Js::OpCode::IMUL2, opndReg1, opndReg1, opndReg2, this->m_func);
  2841. instrMul->InsertBefore(instr);
  2842. // JO $helper
  2843. instr = IR::BranchInstr::New(Js::OpCode::JO, labelHelper, this->m_func);
  2844. instrMul->InsertBefore(instr);
  2845. // MOV s3, s1
  2846. s3 = IR::RegOpnd::New(TyInt32, this->m_func);
  2847. instr = IR::Instr::New(Js::OpCode::MOV, s3, opndReg1, this->m_func);
  2848. instrMul->InsertBefore(instr);
  2849. // TEST s3, s3
  2850. instr = IR::Instr::New(Js::OpCode::TEST, this->m_func);
  2851. instr->SetSrc1(s3);
  2852. instr->SetSrc2(s3);
  2853. instrMul->InsertBefore(instr);
  2854. // JEQ $zero
  2855. IR::LabelInstr *labelZero = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
  2856. instr = IR::BranchInstr::New(Js::OpCode::JEQ, labelZero, this->m_func);
  2857. instrMul->InsertBefore(instr);
  2858. // JMP $nonzero
  2859. instr = IR::BranchInstr::New(Js::OpCode::JMP, labelNonZero, this->m_func);
  2860. instrMul->InsertBefore(instr);
  2861. // $zero:
  2862. instrMul->InsertBefore(labelZero);
  2863. // s2 = ADD s2, src1
  2864. instr = IR::Instr::New(Js::OpCode::ADD, opndReg2, opndReg2, opndSrc1, this->m_func);
  2865. instrMul->InsertBefore(instr);
  2866. Legalize(instr);
  2867. // JGT $nonzero
  2868. #if INT32VAR
  2869. Js::OpCode greaterOpCode = Js::OpCode::JGE;
  2870. #else
  2871. Js::OpCode greaterOpCode = Js::OpCode::JGT;
  2872. #endif
  2873. instr = IR::BranchInstr::New(greaterOpCode, labelNonZero, this->m_func);
  2874. instrMul->InsertBefore(instr);
  2875. // dst = ToVar(-0.0) -- load negative 0
  2876. instr = IR::Instr::New(Js::OpCode::MOV, instrMul->GetDst(), m_lowerer->LoadLibraryValueOpnd(instrMul, LibraryValue::ValueNegativeZero), this->m_func);
  2877. instrMul->InsertBefore(instr);
  2878. // JMP $fallthru
  2879. instr = IR::BranchInstr::New(Js::OpCode::JMP, labelFallThru, this->m_func);
  2880. instrMul->InsertBefore(instr);
  2881. // $nonzero:
  2882. instrMul->InsertBefore(labelNonZero);
  2883. #if !INT32VAR
  2884. // s3 = INC s3
  2885. instr = IR::Instr::New(Js::OpCode::INC, s3, s3, this->m_func);
  2886. instrMul->InsertBefore(instr);
  2887. #endif
  2888. //
  2889. // Convert TyInt32 operand, back to TyMachPtr type.
  2890. // Cast is fine. We know ChangeType returns IR::Opnd * but it
  2891. // preserves the Type.
  2892. //
  2893. if(TyMachReg != s3->GetType())
  2894. {
  2895. s3 = static_cast<IR::RegOpnd *>(s3->UseWithNewType(TyMachPtr, this->m_func));
  2896. }
  2897. #if INT32VAR
  2898. // s3 = OR s3, AtomTag_IntPtr
  2899. GenerateInt32ToVarConversion(s3, instrMul);
  2900. #endif
  2901. // dst = MOV s3
  2902. instr = IR::Instr::New(Js::OpCode::MOV, instrMul->GetDst(), s3, this->m_func);
  2903. instrMul->InsertBefore(instr);
  2904. // JMP $fallthru
  2905. instr = IR::BranchInstr::New(Js::OpCode::JMP, labelFallThru, this->m_func);
  2906. instrMul->InsertBefore(instr);
  2907. // $helper:
  2908. // (caller generates helper call)
  2909. // $fallthru:
  2910. instrMul->InsertBefore(labelHelper);
  2911. instrMul->InsertAfter(labelFallThru);
  2912. return true;
  2913. }
  2914. bool
  2915. LowererMD::GenerateFastNeg(IR::Instr * instrNeg)
  2916. {
  2917. // Given:
  2918. //
  2919. // dst = Not src
  2920. //
  2921. // Generate:
  2922. //
  2923. // if not int, jump $helper
  2924. // if src == 0 -- test for zero (must be handled by the runtime to preserve
  2925. // JEQ $helper difference btw +0 and -0)
  2926. // dst = MOV src
  2927. // dst = NEG dst -- do an inline NEG
  2928. // dst = ADD dst, 2 -- restore the var tag on the result [int31 only]
  2929. // JO $helper
  2930. // dst = OR dst, AtomTag_Ptr [int32 only]
  2931. // JMP $fallthru
  2932. // $helper:
  2933. // (caller generates helper call)
  2934. // $fallthru:
  2935. IR::Instr * instr;
  2936. IR::LabelInstr * labelHelper = nullptr;
  2937. IR::LabelInstr * labelFallThru = nullptr;
  2938. IR::Opnd * opndSrc1;
  2939. IR::Opnd * opndDst;
  2940. bool usingNewDst = false;
  2941. opndSrc1 = instrNeg->GetSrc1();
  2942. AssertMsg(opndSrc1, "Expected src opnd on Neg instruction");
  2943. if(opndSrc1->IsEqual(instrNeg->GetDst()))
  2944. {
  2945. usingNewDst = true;
  2946. opndDst = IR::RegOpnd::New(TyInt32, this->m_func);
  2947. }
  2948. else
  2949. {
  2950. opndDst = instrNeg->GetDst()->UseWithNewType(TyInt32, this->m_func);
  2951. }
  2952. if (opndSrc1->IsRegOpnd() && opndSrc1->AsRegOpnd()->m_sym->IsIntConst())
  2953. {
  2954. IR::Opnd *newOpnd;
  2955. IntConstType value = opndSrc1->AsRegOpnd()->m_sym->GetIntConstValue();
  2956. if (value == 0)
  2957. {
  2958. // If the negate operand is zero, the result is -0.0, which is a Number rather than an Int31.
  2959. newOpnd = m_lowerer->LoadLibraryValueOpnd(instrNeg, LibraryValue::ValueNegativeZero);
  2960. }
  2961. else
  2962. {
  2963. // negation below can overflow because max negative int32 value > max positive value by 1.
  2964. newOpnd = IR::AddrOpnd::NewFromNumber(-(int64)value, m_func);
  2965. }
  2966. instrNeg->ClearBailOutInfo();
  2967. instrNeg->FreeSrc1();
  2968. instrNeg->SetSrc1(newOpnd);
  2969. instrNeg = this->ChangeToAssign(instrNeg);
  2970. // Skip lowering call to helper
  2971. return false;
  2972. }
  2973. bool isInt = (opndSrc1->IsTaggedInt());
  2974. if (opndSrc1->IsRegOpnd() && opndSrc1->AsRegOpnd()->IsNotInt())
  2975. {
  2976. return true;
  2977. }
  2978. labelHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
  2979. if (!isInt)
  2980. {
  2981. GenerateSmIntTest(opndSrc1, instrNeg, labelHelper);
  2982. }
  2983. //
  2984. // For 32 bit arithmetic we copy them and set the size of operands to be 32 bits. This is
  2985. // relevant only on AMD64.
  2986. //
  2987. opndSrc1 = opndSrc1->UseWithNewType(TyInt32, this->m_func);
  2988. GenerateTaggedZeroTest(opndSrc1, instrNeg, labelHelper);
  2989. // dst = MOV src
  2990. instr = IR::Instr::New(Js::OpCode::MOV, opndDst, opndSrc1, this->m_func);
  2991. instrNeg->InsertBefore(instr);
  2992. // dst = NEG dst
  2993. instr = IR::Instr::New(Js::OpCode::NEG, opndDst, opndDst, this->m_func);
  2994. instrNeg->InsertBefore(instr);
  2995. #if !INT32VAR
  2996. // dst = ADD dst, 2
  2997. instr = IR::Instr::New(Js::OpCode::ADD, opndDst, opndDst, IR::IntConstOpnd::New(2, TyInt32, this->m_func), this->m_func);
  2998. instrNeg->InsertBefore(instr);
  2999. #endif
  3000. // JO $helper
  3001. instr = IR::BranchInstr::New(Js::OpCode::JO, labelHelper, this->m_func);
  3002. instrNeg->InsertBefore(instr);
  3003. //
  3004. // Convert TyInt32 operand, back to TyMachPtr type.
  3005. //
  3006. if(TyMachReg != opndDst->GetType())
  3007. {
  3008. opndDst = opndDst->UseWithNewType(TyMachPtr, this->m_func);
  3009. }
  3010. #if INT32VAR
  3011. GenerateInt32ToVarConversion(opndDst, instrNeg);
  3012. #endif
  3013. if(usingNewDst)
  3014. {
  3015. instr = IR::Instr::New(Js::OpCode::MOV, instrNeg->GetDst(), opndDst, this->m_func);
  3016. instrNeg->InsertBefore(instr);
  3017. }
  3018. // JMP $fallthru
  3019. labelFallThru = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  3020. instr = IR::BranchInstr::New(Js::OpCode::JMP, labelFallThru, this->m_func);
  3021. instrNeg->InsertBefore(instr);
  3022. // $helper:
  3023. // (caller generates helper sequence)
  3024. // $fallthru:
  3025. AssertMsg(labelHelper, "Should not be NULL");
  3026. instrNeg->InsertBefore(labelHelper);
  3027. instrNeg->InsertAfter(labelFallThru);
  3028. return true;
  3029. }
  3030. void
  3031. LowererMD::GenerateFastBrS(IR::BranchInstr *brInstr)
  3032. {
  3033. IR::Opnd *src1 = brInstr->UnlinkSrc1();
  3034. Assert(src1->IsIntConstOpnd() || src1->IsAddrOpnd() || src1->IsRegOpnd());
  3035. IR::Instr *cmpInstr = IR::Instr::New(Js::OpCode::TEST, this->m_func);
  3036. cmpInstr->SetSrc1(m_lowerer->LoadOptimizationOverridesValueOpnd(brInstr, OptimizationOverridesValue::OptimizationOverridesSideEffects));
  3037. cmpInstr->SetSrc2(src1);
  3038. brInstr->InsertBefore(cmpInstr);
  3039. Legalize(cmpInstr);
  3040. Js::OpCode opcode;
  3041. switch(brInstr->m_opcode)
  3042. {
  3043. case Js::OpCode::BrHasSideEffects:
  3044. opcode = Js::OpCode::JNE;
  3045. break;
  3046. case Js::OpCode::BrNotHasSideEffects:
  3047. opcode = Js::OpCode::JEQ;
  3048. break;
  3049. default:
  3050. Assert(UNREACHED);
  3051. __assume(false);
  3052. }
  3053. brInstr->m_opcode = opcode;
  3054. }
  3055. ///----------------------------------------------------------------------------
  3056. ///
  3057. /// LowererMD::GenerateSmIntPairTest
  3058. ///
  3059. /// Generate code to test whether the given operands are both Int31 vars
  3060. /// and branch to the given label if not.
  3061. ///
  3062. ///----------------------------------------------------------------------------
  3063. #if !INT32VAR
  3064. IR::Instr *
  3065. LowererMD::GenerateSmIntPairTest(
  3066. IR::Instr * instrInsert,
  3067. IR::Opnd * opndSrc1,
  3068. IR::Opnd * opndSrc2,
  3069. IR::LabelInstr * labelFail)
  3070. {
  3071. IR::Opnd * opndReg;
  3072. IR::Instr * instrPrev = instrInsert->m_prev;
  3073. IR::Instr * instr;
  3074. Assert(opndSrc1->GetType() == TyVar);
  3075. Assert(opndSrc2->GetType() == TyVar);
  3076. if (opndSrc1->IsTaggedInt())
  3077. {
  3078. IR::Opnd *tempOpnd = opndSrc1;
  3079. opndSrc1 = opndSrc2;
  3080. opndSrc2 = tempOpnd;
  3081. }
  3082. if (opndSrc2->IsTaggedInt())
  3083. {
  3084. if (opndSrc1->IsTaggedInt())
  3085. {
  3086. return instrPrev;
  3087. }
  3088. // TEST src1, AtomTag
  3089. // JEQ $fail
  3090. instr = IR::Instr::New(Js::OpCode::TEST, this->m_func);
  3091. instr->SetSrc1(opndSrc1);
  3092. instr->SetSrc2(IR::IntConstOpnd::New(Js::AtomTag, TyInt8, this->m_func));
  3093. instrInsert->InsertBefore(instr);
  3094. }
  3095. else
  3096. {
  3097. // s1 = MOV src1
  3098. // s1 = AND s1, 1
  3099. // TEST s1, src2
  3100. // JEQ $fail
  3101. // s1 = MOV src1
  3102. opndReg = IR::RegOpnd::New(TyMachReg, this->m_func);
  3103. instr = IR::Instr::New(Js::OpCode::MOV, opndReg, opndSrc1, this->m_func);
  3104. instrInsert->InsertBefore(instr);
  3105. // s1 = AND s1, AtomTag
  3106. instr = IR::Instr::New(
  3107. Js::OpCode::AND, opndReg, opndReg, IR::IntConstOpnd::New(Js::AtomTag, TyInt8, this->m_func), this->m_func);
  3108. instrInsert->InsertBefore(instr);
  3109. // TEST s1, src2
  3110. instr = IR::Instr::New(Js::OpCode::TEST, this->m_func);
  3111. instr->SetSrc1(opndReg);
  3112. instr->SetSrc2(opndSrc2);
  3113. instrInsert->InsertBefore(instr);
  3114. }
  3115. // JEQ $fail
  3116. instr = IR::BranchInstr::New(Js::OpCode::JEQ, labelFail, this->m_func);
  3117. instrInsert->InsertBefore(instr);
  3118. return instrPrev;
  3119. }
  3120. #else
  3121. IR::Instr *
  3122. LowererMD::GenerateSmIntPairTest(
  3123. IR::Instr * instrInsert,
  3124. IR::Opnd * opndSrc1,
  3125. IR::Opnd * opndSrc2,
  3126. IR::LabelInstr * labelFail)
  3127. {
  3128. IR::Opnd * opndReg;
  3129. IR::Instr * instrPrev = instrInsert->m_prev;
  3130. IR::Instr * instr;
  3131. Assert(opndSrc1->GetType() == TyVar);
  3132. Assert(opndSrc2->GetType() == TyVar);
  3133. if (opndSrc1->IsTaggedInt())
  3134. {
  3135. IR::Opnd *tempOpnd = opndSrc1;
  3136. opndSrc1 = opndSrc2;
  3137. opndSrc2 = tempOpnd;
  3138. }
  3139. if (opndSrc2->IsTaggedInt())
  3140. {
  3141. if (opndSrc1->IsTaggedInt())
  3142. {
  3143. return instrPrev;
  3144. }
  3145. GenerateSmIntTest(opndSrc1, instrInsert, labelFail);
  3146. return instrPrev;
  3147. }
  3148. else
  3149. {
  3150. opndReg = IR::RegOpnd::New(TyMachReg, this->m_func);
  3151. #ifdef SHIFTLOAD
  3152. instr = IR::Instr::New(Js::OpCode::SHLD, opndReg, opndSrc1, IR::IntConstOpnd::New(16, TyInt8, this->m_func), this->m_func);
  3153. instrInsert->InsertBefore(instr);
  3154. instr = IR::Instr::New(Js::OpCode::SHLD, opndReg, opndSrc2, IR::IntConstOpnd::New(16, TyInt8, this->m_func), this->m_func);
  3155. instrInsert->InsertBefore(instr);
  3156. #else
  3157. IR::Opnd * opndReg1;
  3158. // s1 = MOV src1
  3159. // s1 = SHR s1, VarTag_Shift
  3160. // s2 = MOV src2
  3161. // s2 = SHR s2, 32
  3162. // s1 = OR s1, s2 ------ move both tags to the lower 32 bits
  3163. // CMP s1, AtomTag_Pair ------ compare the tags together to the expected tag pair
  3164. // JNE $fail
  3165. // s1 = MOV src1
  3166. instr = IR::Instr::New(Js::OpCode::MOV, opndReg, opndSrc1, this->m_func);
  3167. instrInsert->InsertBefore(instr);
  3168. // s1 = SHR s1, VarTag_Shift
  3169. instr = IR::Instr::New(Js::OpCode::SHR, opndReg, opndReg, IR::IntConstOpnd::New(Js::VarTag_Shift, TyInt8, this->m_func), this->m_func);
  3170. instrInsert->InsertBefore(instr);
  3171. // s2 = MOV src2
  3172. opndReg1 = IR::RegOpnd::New(TyMachReg, this->m_func);
  3173. instr = IR::Instr::New(Js::OpCode::MOV, opndReg1, opndSrc2, this->m_func);
  3174. instrInsert->InsertBefore(instr);
  3175. // s2 = SHR s2, 32
  3176. instr = IR::Instr::New(Js::OpCode::SHR, opndReg1, opndReg1, IR::IntConstOpnd::New(32, TyInt8, this->m_func), this->m_func);
  3177. instrInsert->InsertBefore(instr);
  3178. // s1 = OR s1, s2
  3179. instr = IR::Instr::New(Js::OpCode::OR, opndReg, opndReg, opndReg1, this->m_func);
  3180. instrInsert->InsertBefore(instr);
  3181. #endif
  3182. opndReg = opndReg->UseWithNewType(TyInt32, this->m_func)->AsRegOpnd();
  3183. // CMP s1, AtomTag_Pair
  3184. instr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  3185. instr->SetSrc1(opndReg);
  3186. instr->SetSrc2(IR::IntConstOpnd::New(Js::AtomTag_Pair, TyInt32, this->m_func, true));
  3187. instrInsert->InsertBefore(instr);
  3188. }
  3189. // JNE $fail
  3190. instr = IR::BranchInstr::New(Js::OpCode::JNE, labelFail, this->m_func);
  3191. instrInsert->InsertBefore(instr);
  3192. return instrPrev;
  3193. }
  3194. #endif
  3195. IR::BranchInstr *
  3196. LowererMD::GenerateLocalInlineCacheCheck(
  3197. IR::Instr * instrLdSt,
  3198. IR::RegOpnd * opndType,
  3199. IR::RegOpnd * inlineCache,
  3200. IR::LabelInstr * labelNext,
  3201. bool checkTypeWithoutProperty)
  3202. {
  3203. // Generate:
  3204. //
  3205. // CMP s1, [&(inlineCache->u.local.type/typeWithoutProperty)]
  3206. // JNE $next
  3207. IR::Instr * instr;
  3208. IR::Opnd* typeOpnd;
  3209. if (checkTypeWithoutProperty)
  3210. {
  3211. typeOpnd = IR::IndirOpnd::New(inlineCache, (int32)offsetof(Js::InlineCache, u.local.typeWithoutProperty), TyMachReg, instrLdSt->m_func);
  3212. }
  3213. else
  3214. {
  3215. typeOpnd = IR::IndirOpnd::New(inlineCache, (int32)offsetof(Js::InlineCache, u.local.type), TyMachReg, instrLdSt->m_func);
  3216. }
  3217. // CMP type, [&(inlineCache->u.local.type/typeWithoutProperty)]
  3218. instr = IR::Instr::New(Js::OpCode::CMP, instrLdSt->m_func);
  3219. instr->SetSrc1(opndType);
  3220. instr->SetSrc2(typeOpnd);
  3221. instrLdSt->InsertBefore(instr);
  3222. // JNE $next
  3223. IR::BranchInstr * branchInstr = IR::BranchInstr::New(Js::OpCode::JNE, labelNext, instrLdSt->m_func);
  3224. instrLdSt->InsertBefore(branchInstr);
  3225. return branchInstr;
  3226. }
  3227. IR::BranchInstr *
  3228. LowererMD::GenerateProtoInlineCacheCheck(
  3229. IR::Instr * instrLdSt,
  3230. IR::RegOpnd * opndType,
  3231. IR::RegOpnd * inlineCache,
  3232. IR::LabelInstr * labelNext)
  3233. {
  3234. // Generate:
  3235. //
  3236. // CMP s1, [&(inlineCache->u.proto.type)]
  3237. // JNE $next
  3238. IR::Instr * instr;
  3239. IR::Opnd* typeOpnd = IR::IndirOpnd::New(inlineCache, (int32)offsetof(Js::InlineCache, u.proto.type), TyMachReg, instrLdSt->m_func);
  3240. // CMP s1, [&(inlineCache->u.proto.type)]
  3241. instr = IR::Instr::New(Js::OpCode::CMP, instrLdSt->m_func);
  3242. instr->SetSrc1(opndType);
  3243. instr->SetSrc2(typeOpnd);
  3244. instrLdSt->InsertBefore(instr);
  3245. // JNE $next
  3246. IR::BranchInstr * branchInstr = IR::BranchInstr::New(Js::OpCode::JNE, labelNext, instrLdSt->m_func);
  3247. instrLdSt->InsertBefore(branchInstr);
  3248. return branchInstr;
  3249. }
  3250. IR::BranchInstr *
  3251. LowererMD::GenerateFlagInlineCacheCheck(
  3252. IR::Instr * instrLdSt,
  3253. IR::RegOpnd * opndType,
  3254. IR::RegOpnd * opndInlineCache,
  3255. IR::LabelInstr * labelNext)
  3256. {
  3257. // Generate:
  3258. //
  3259. // CMP s1, [&(inlineCache->u.accessor.type)]
  3260. // JNE $next
  3261. IR::Instr * instr;
  3262. IR::Opnd* typeOpnd;
  3263. typeOpnd = IR::IndirOpnd::New(opndInlineCache, (int32)offsetof(Js::InlineCache, u.accessor.type), TyMachReg, instrLdSt->m_func);
  3264. // CMP s1, [&(inlineCache->u.flag.type)]
  3265. instr = IR::Instr::New(Js::OpCode::CMP, instrLdSt->m_func);
  3266. instr->SetSrc1(opndType);
  3267. instr->SetSrc2(typeOpnd);
  3268. instrLdSt->InsertBefore(instr);
  3269. // JNE $next
  3270. IR::BranchInstr * branchInstr = IR::BranchInstr::New(Js::OpCode::JNE, labelNext, instrLdSt->m_func);
  3271. instrLdSt->InsertBefore(branchInstr);
  3272. return branchInstr;
  3273. }
  3274. IR::BranchInstr *
  3275. LowererMD::GenerateFlagInlineCacheCheckForNoGetterSetter(
  3276. IR::Instr * instrLdSt,
  3277. IR::RegOpnd * opndInlineCache,
  3278. IR::LabelInstr * labelNext)
  3279. {
  3280. // Generate:
  3281. //
  3282. // TEST [&(inlineCache->u.accessor.flags)], (Js::InlineCacheGetterFlag | Js::InlineCacheSetterFlag)
  3283. // JNE $next
  3284. IR::Instr * instr;
  3285. IR::Opnd* flagsOpnd;
  3286. flagsOpnd = IR::IndirOpnd::New(opndInlineCache, 0, TyInt8, instrLdSt->m_func);
  3287. // TEST [&(inlineCache->u.accessor.flags)], (Js::InlineCacheGetterFlag | Js::InlineCacheSetterFlag)
  3288. instr = IR::Instr::New(Js::OpCode::TEST,instrLdSt->m_func);
  3289. instr->SetSrc1(flagsOpnd);
  3290. instr->SetSrc2(IR::IntConstOpnd::New((Js::InlineCacheGetterFlag | Js::InlineCacheSetterFlag) << 1, TyInt8, instrLdSt->m_func));
  3291. instrLdSt->InsertBefore(instr);
  3292. // JNE $next
  3293. IR::BranchInstr * branchInstr = IR::BranchInstr::New(Js::OpCode::JNE, labelNext, instrLdSt->m_func);
  3294. instrLdSt->InsertBefore(branchInstr);
  3295. return branchInstr;
  3296. }
  3297. void
  3298. LowererMD::GenerateFlagInlineCacheCheckForGetterSetter(
  3299. IR::Instr * insertBeforeInstr,
  3300. IR::RegOpnd * opndInlineCache,
  3301. IR::LabelInstr * labelNext)
  3302. {
  3303. uint accessorFlagMask;
  3304. if (PHASE_OFF(Js::InlineGettersPhase, insertBeforeInstr->m_func->GetJnFunction()))
  3305. {
  3306. accessorFlagMask = Js::InlineCache::GetSetterFlagMask();
  3307. }
  3308. else if (PHASE_OFF(Js::InlineSettersPhase, insertBeforeInstr->m_func->GetJnFunction()))
  3309. {
  3310. accessorFlagMask = Js::InlineCache::GetGetterFlagMask();
  3311. }
  3312. else
  3313. {
  3314. accessorFlagMask = Js::InlineCache::GetGetterSetterFlagMask();
  3315. }
  3316. // Generate:
  3317. //
  3318. // TEST [&(inlineCache->u.accessor.flags)], Js::InlineCacheGetterFlag | Js::InlineCacheSetterFlag
  3319. // JEQ $next
  3320. IR::Instr * instr;
  3321. IR::Opnd* flagsOpnd;
  3322. flagsOpnd = IR::IndirOpnd::New(opndInlineCache, (int32)offsetof(Js::InlineCache, u.accessor.rawUInt16), TyInt8, insertBeforeInstr->m_func);
  3323. // TEST [&(inlineCache->u.accessor.flags)], InlineCacheGetterFlag | InlineCacheSetterFlag
  3324. instr = IR::Instr::New(Js::OpCode::TEST,this->m_func);
  3325. instr->SetSrc1(flagsOpnd);
  3326. instr->SetSrc2(IR::IntConstOpnd::New(accessorFlagMask, TyInt8, this->m_func));
  3327. insertBeforeInstr->InsertBefore(instr);
  3328. // JEQ $next
  3329. instr = IR::BranchInstr::New(Js::OpCode::JEQ, labelNext, this->m_func);
  3330. insertBeforeInstr->InsertBefore(instr);
  3331. }
  3332. void
  3333. LowererMD::GenerateLdFldFromLocalInlineCache(
  3334. IR::Instr * instrLdFld,
  3335. IR::RegOpnd * opndBase,
  3336. IR::Opnd * opndDst,
  3337. IR::RegOpnd * inlineCache,
  3338. IR::LabelInstr * labelFallThru,
  3339. bool isInlineSlot)
  3340. {
  3341. // Generate:
  3342. //
  3343. // s1 = MOV base->slots -- load the slot array
  3344. // s2 = MOVZXw [&(inlineCache->u.local.slotIndex)] -- load the cached slot index
  3345. // dst = MOV [s1 + s2* Scale] -- load the value directly from the slot
  3346. // JMP $fallthru
  3347. IR::Instr * instr;
  3348. IR::Opnd* slotIndexOpnd;
  3349. IR::IndirOpnd * opndIndir;
  3350. IR::RegOpnd * opndSlotArray = nullptr;
  3351. if (!isInlineSlot)
  3352. {
  3353. opndSlotArray = IR::RegOpnd::New(TyMachReg, instrLdFld->m_func);
  3354. opndIndir = IR::IndirOpnd::New(opndBase, Js::DynamicObject::GetOffsetOfAuxSlots(), TyMachReg, instrLdFld->m_func);
  3355. instr = IR::Instr::New(Js::OpCode::MOV, opndSlotArray, opndIndir, instrLdFld->m_func);
  3356. instrLdFld->InsertBefore(instr);
  3357. }
  3358. // s2 = MOVZXw [&(inlineCache->u.local.slotIndex)] -- load the cached slot index
  3359. IR::RegOpnd * opndReg2 = IR::RegOpnd::New(TyMachReg, instrLdFld->m_func);
  3360. slotIndexOpnd = IR::IndirOpnd::New(inlineCache, (int32)offsetof(Js::InlineCache, u.local.slotIndex), TyUint16, instrLdFld->m_func);
  3361. instr = IR::Instr::New(Js::OpCode::MOVZXW, opndReg2, slotIndexOpnd, instrLdFld->m_func);
  3362. instrLdFld->InsertBefore(instr);
  3363. if (isInlineSlot)
  3364. {
  3365. // dst = MOV [base + s2* Scale] -- load the value directly from the slot
  3366. opndIndir = IR::IndirOpnd::New(opndBase, opndReg2, LowererMDArch::GetDefaultIndirScale(), TyMachReg, instrLdFld->m_func);
  3367. instr = IR::Instr::New(Js::OpCode::MOV, opndDst, opndIndir, instrLdFld->m_func);
  3368. instrLdFld->InsertBefore(instr);
  3369. }
  3370. else
  3371. {
  3372. // dst = MOV [s1 + s2* Scale] -- load the value directly from the slot
  3373. opndIndir = IR::IndirOpnd::New(opndSlotArray, opndReg2, LowererMDArch::GetDefaultIndirScale(), TyMachReg, instrLdFld->m_func);
  3374. instr = IR::Instr::New(Js::OpCode::MOV, opndDst, opndIndir, instrLdFld->m_func);
  3375. instrLdFld->InsertBefore(instr);
  3376. }
  3377. // JMP $fallthru
  3378. instr = IR::BranchInstr::New(Js::OpCode::JMP, labelFallThru, instrLdFld->m_func);
  3379. instrLdFld->InsertBefore(instr);
  3380. }
  3381. void
  3382. LowererMD::GenerateLdLocalFldFromFlagInlineCache(
  3383. IR::Instr * instrLdFld,
  3384. IR::RegOpnd * opndBase,
  3385. IR::Opnd * opndDst,
  3386. IR::RegOpnd * opndInlineCache,
  3387. IR::LabelInstr * labelFallThru,
  3388. bool isInlineSlot)
  3389. {
  3390. // Generate:
  3391. //
  3392. // s1 = MOV [&base->slots] -- load the slot array
  3393. // s2 = MOVZXW [&(inlineCache->u.accessor.slotIndex)] -- load the cached slot index
  3394. // dst = MOV [s1 + s2*4]
  3395. // JMP $fallthru
  3396. IR::Instr * instr;
  3397. IR::Opnd* slotIndexOpnd;
  3398. IR::IndirOpnd * opndIndir;
  3399. IR::RegOpnd * opndSlotArray = nullptr;
  3400. if (!isInlineSlot)
  3401. {
  3402. opndSlotArray = IR::RegOpnd::New(TyMachReg, instrLdFld->m_func);
  3403. opndIndir = IR::IndirOpnd::New(opndBase, Js::DynamicObject::GetOffsetOfAuxSlots(), TyMachReg, instrLdFld->m_func);
  3404. instr = IR::Instr::New(Js::OpCode::MOV, opndSlotArray, opndIndir, instrLdFld->m_func);
  3405. instrLdFld->InsertBefore(instr);
  3406. }
  3407. // s2 = MOVZXW [&(inlineCache->u.accessor.slotIndex)] -- load the cached slot index
  3408. IR::RegOpnd *opndSlotIndex = IR::RegOpnd::New(TyMachReg, instrLdFld->m_func);
  3409. slotIndexOpnd = IR::IndirOpnd::New(opndInlineCache, (int32)offsetof(Js::InlineCache, u.accessor.slotIndex), TyUint16, instrLdFld->m_func);
  3410. instr = IR::Instr::New(Js::OpCode::MOVZXW, opndSlotIndex, slotIndexOpnd, instrLdFld->m_func);
  3411. instrLdFld->InsertBefore(instr);
  3412. if (isInlineSlot)
  3413. {
  3414. // dst = MOV [s1 + s2*4]
  3415. opndIndir = IR::IndirOpnd::New(opndBase, opndSlotIndex, LowererMDArch::GetDefaultIndirScale(), TyMachReg, instrLdFld->m_func);
  3416. instr = IR::Instr::New(Js::OpCode::MOV, opndDst, opndIndir, instrLdFld->m_func);
  3417. instrLdFld->InsertBefore(instr);
  3418. }
  3419. else
  3420. {
  3421. // dst = MOV [s1 + s2*4]
  3422. opndIndir = IR::IndirOpnd::New(opndSlotArray, opndSlotIndex, LowererMDArch::GetDefaultIndirScale(), TyMachReg, instrLdFld->m_func);
  3423. instr = IR::Instr::New(Js::OpCode::MOV, opndDst, opndIndir, instrLdFld->m_func);
  3424. instrLdFld->InsertBefore(instr);
  3425. }
  3426. // JMP $fallthru
  3427. instr = IR::BranchInstr::New(Js::OpCode::JMP, labelFallThru, instrLdFld->m_func);
  3428. instrLdFld->InsertBefore(instr);
  3429. }
  3430. void
  3431. LowererMD::GenerateLdFldFromFlagInlineCache(
  3432. IR::Instr * insertBeforeInstr,
  3433. IR::RegOpnd * opndBase,
  3434. IR::Opnd * opndDst,
  3435. IR::RegOpnd * opndInlineCache,
  3436. IR::LabelInstr * labelFallThru,
  3437. bool isInlineSlot)
  3438. {
  3439. // Generate:
  3440. //
  3441. // s1 = MOV [&(inlineCache->u.accessor.object)] -- load the cached prototype object
  3442. // s1 = MOV [&s1->slots] -- load the slot array
  3443. // s2 = MOVZXW [&(inlineCache->u.accessor.slotIndex)] -- load the cached slot index
  3444. // dst = MOV [s1 + s2*4]
  3445. // JMP $fallthru
  3446. IR::Instr * instr;
  3447. IR::Opnd* inlineCacheObjOpnd;
  3448. IR::IndirOpnd * opndIndir;
  3449. IR::RegOpnd * opndObjSlots = nullptr;
  3450. inlineCacheObjOpnd = IR::IndirOpnd::New(opndInlineCache, (int32)offsetof(Js::InlineCache, u.accessor.object), TyMachReg, this->m_func);
  3451. // s1 = MOV [&(inlineCache->u.accessor.object)] -- load the cached prototype object
  3452. IR::RegOpnd *opndObject = IR::RegOpnd::New(TyMachReg, this->m_func);
  3453. instr = IR::Instr::New(Js::OpCode::MOV, opndObject, inlineCacheObjOpnd, this->m_func);
  3454. insertBeforeInstr->InsertBefore(instr);
  3455. if (!isInlineSlot)
  3456. {
  3457. // s1 = MOV [&s1->slots] -- load the slot array
  3458. opndObjSlots = IR::RegOpnd::New(TyMachReg, this->m_func);
  3459. opndIndir = IR::IndirOpnd::New(opndObject, Js::DynamicObject::GetOffsetOfAuxSlots(), TyMachReg, this->m_func);
  3460. instr = IR::Instr::New(Js::OpCode::MOV, opndObjSlots, opndIndir, this->m_func);
  3461. insertBeforeInstr->InsertBefore(instr);
  3462. }
  3463. // s2 = MOVZXW [&(inlineCache->u.accessor.slotIndex)] -- load the cached slot index
  3464. IR::RegOpnd *opndSlotIndex = IR::RegOpnd::New(TyMachReg, this->m_func);
  3465. IR::Opnd* slotIndexOpnd = IR::IndirOpnd::New(opndInlineCache, (int32)offsetof(Js::InlineCache, u.accessor.slotIndex), TyUint16, this->m_func);
  3466. instr = IR::Instr::New(Js::OpCode::MOVZXW, opndSlotIndex, slotIndexOpnd, this->m_func);
  3467. insertBeforeInstr->InsertBefore(instr);
  3468. if (isInlineSlot)
  3469. {
  3470. // dst = MOV [s1 + s2*4]
  3471. opndIndir = IR::IndirOpnd::New(opndObject, opndSlotIndex, this->lowererMDArch.GetDefaultIndirScale(), TyMachReg, this->m_func);
  3472. instr = IR::Instr::New(Js::OpCode::MOV, opndDst, opndIndir, this->m_func);
  3473. insertBeforeInstr->InsertBefore(instr);
  3474. }
  3475. else
  3476. {
  3477. // dst = MOV [s1 + s2*4]
  3478. opndIndir = IR::IndirOpnd::New(opndObjSlots, opndSlotIndex, this->lowererMDArch.GetDefaultIndirScale(), TyMachReg, this->m_func);
  3479. instr = IR::Instr::New(Js::OpCode::MOV, opndDst, opndIndir, this->m_func);
  3480. insertBeforeInstr->InsertBefore(instr);
  3481. }
  3482. // JMP $fallthru
  3483. instr = IR::BranchInstr::New(Js::OpCode::JMP, labelFallThru, this->m_func);
  3484. insertBeforeInstr->InsertBefore(instr);
  3485. }
  3486. void
  3487. LowererMD::GenerateLdFldFromProtoInlineCache(
  3488. IR::Instr * instrLdFld,
  3489. IR::RegOpnd * opndBase,
  3490. IR::Opnd * opndDst,
  3491. IR::RegOpnd * inlineCache,
  3492. IR::LabelInstr * labelFallThru,
  3493. bool isInlineSlot)
  3494. {
  3495. // Generate:
  3496. //
  3497. // s1 = MOV [&(inlineCache->u.proto.prototypeObject)] -- load the cached prototype object
  3498. // s1 = MOV [&s1->slots] -- load the slot array
  3499. // s2 = MOVZXW [&(inlineCache->u.proto.slotIndex)] -- load the cached slot index
  3500. // dst = MOV [s1 + s2*4]
  3501. // JMP $fallthru
  3502. IR::Instr * instr;
  3503. IR::Opnd* inlineCacheProtoOpnd;
  3504. IR::IndirOpnd * opndIndir;
  3505. IR::RegOpnd * opndProtoSlots = nullptr;
  3506. inlineCacheProtoOpnd = IR::IndirOpnd::New(inlineCache, (int32)offsetof(Js::InlineCache, u.proto.prototypeObject), TyMachReg, instrLdFld->m_func);
  3507. // s1 = MOV [&(inlineCache->u.proto.prototypeObject)] -- load the cached prototype object
  3508. IR::RegOpnd *opndProto = IR::RegOpnd::New(TyMachReg, instrLdFld->m_func);
  3509. instr = IR::Instr::New(Js::OpCode::MOV, opndProto, inlineCacheProtoOpnd, instrLdFld->m_func);
  3510. instrLdFld->InsertBefore(instr);
  3511. if (!isInlineSlot)
  3512. {
  3513. // s1 = MOV [&s1->slots] -- load the slot array
  3514. opndProtoSlots = IR::RegOpnd::New(TyMachReg, instrLdFld->m_func);
  3515. opndIndir = IR::IndirOpnd::New(opndProto, Js::DynamicObject::GetOffsetOfAuxSlots(), TyMachReg, instrLdFld->m_func);
  3516. instr = IR::Instr::New(Js::OpCode::MOV, opndProtoSlots, opndIndir, instrLdFld->m_func);
  3517. instrLdFld->InsertBefore(instr);
  3518. }
  3519. // s2 = MOVZXW [&(inlineCache->u.proto.slotIndex)] -- load the cached slot index
  3520. IR::RegOpnd *opndSlotIndex = IR::RegOpnd::New(TyMachReg, instrLdFld->m_func);
  3521. IR::Opnd* slotIndexOpnd = IR::IndirOpnd::New(inlineCache, (int32)offsetof(Js::InlineCache, u.proto.slotIndex), TyUint16, instrLdFld->m_func);
  3522. instr = IR::Instr::New(Js::OpCode::MOVZXW, opndSlotIndex, slotIndexOpnd, instrLdFld->m_func);
  3523. instrLdFld->InsertBefore(instr);
  3524. if (isInlineSlot)
  3525. {
  3526. // dst = MOV [s1 + s2*4]
  3527. opndIndir = IR::IndirOpnd::New(opndProto, opndSlotIndex, LowererMDArch::GetDefaultIndirScale(), TyMachReg, instrLdFld->m_func);
  3528. instr = IR::Instr::New(Js::OpCode::MOV, opndDst, opndIndir, instrLdFld->m_func);
  3529. instrLdFld->InsertBefore(instr);
  3530. }
  3531. else
  3532. {
  3533. // dst = MOV [s1 + s2*4]
  3534. opndIndir = IR::IndirOpnd::New(opndProtoSlots, opndSlotIndex, LowererMDArch::GetDefaultIndirScale(), TyMachReg, instrLdFld->m_func);
  3535. instr = IR::Instr::New(Js::OpCode::MOV, opndDst, opndIndir, instrLdFld->m_func);
  3536. instrLdFld->InsertBefore(instr);
  3537. }
  3538. // JMP $fallthru
  3539. instr = IR::BranchInstr::New(Js::OpCode::JMP, labelFallThru, instrLdFld->m_func);
  3540. instrLdFld->InsertBefore(instr);
  3541. }
  3542. void
  3543. LowererMD::GenerateLoadTaggedType(IR::Instr * instrLdSt, IR::RegOpnd * opndType, IR::RegOpnd * opndTaggedType)
  3544. {
  3545. // Generate
  3546. //
  3547. // MOV taggedType, type
  3548. // OR taggedType, InlineCacheAuxSlotTypeTag
  3549. // MOV taggedType, type
  3550. {
  3551. IR::Instr * instrMov = IR::Instr::New(Js::OpCode::MOV, opndTaggedType, opndType, instrLdSt->m_func);
  3552. instrLdSt->InsertBefore(instrMov);
  3553. }
  3554. // OR taggedType, InlineCacheAuxSlotTypeTag
  3555. {
  3556. IR::IntConstOpnd * opndAuxSlotTag = IR::IntConstOpnd::New(InlineCacheAuxSlotTypeTag, TyInt8, instrLdSt->m_func);
  3557. IR::Instr * instrAnd = IR::Instr::New(Js::OpCode::OR, opndTaggedType, opndTaggedType, opndAuxSlotTag, instrLdSt->m_func);
  3558. instrLdSt->InsertBefore(instrAnd);
  3559. }
  3560. }
  3561. ///----------------------------------------------------------------------------
  3562. ///
  3563. /// LowererMD::GenerateFastLdMethodFromFlags
  3564. ///
  3565. /// Make use of the helper to cache the type and slot index used to do a LdFld
  3566. /// and do an inline load from the appropriate slot if the type hasn't changed
  3567. /// since the last time this LdFld was executed.
  3568. ///
  3569. ///----------------------------------------------------------------------------
  3570. bool
  3571. LowererMD::GenerateFastLdMethodFromFlags(IR::Instr * instrLdFld)
  3572. {
  3573. IR::LabelInstr * labelFallThru;
  3574. IR::LabelInstr * bailOutLabel;
  3575. IR::Opnd * opndSrc;
  3576. IR::Opnd * opndDst;
  3577. IR::RegOpnd * opndBase;
  3578. IR::RegOpnd * opndType;
  3579. IR::RegOpnd * opndInlineCache;
  3580. opndSrc = instrLdFld->GetSrc1();
  3581. AssertMsg(opndSrc->IsSymOpnd() && opndSrc->AsSymOpnd()->IsPropertySymOpnd() && opndSrc->AsSymOpnd()->m_sym->IsPropertySym(),
  3582. "Expected property sym operand as src of LdFldFlags");
  3583. IR::PropertySymOpnd * propertySymOpnd = opndSrc->AsPropertySymOpnd();
  3584. Assert(!instrLdFld->DoStackArgsOpt(this->m_func));
  3585. if (propertySymOpnd->IsTypeCheckSeqCandidate())
  3586. {
  3587. AssertMsg(propertySymOpnd->HasObjectTypeSym(), "Type optimized property sym operand without a type sym?");
  3588. StackSym *typeSym = propertySymOpnd->GetObjectTypeSym();
  3589. opndType = IR::RegOpnd::New(typeSym, TyMachReg, this->m_func);
  3590. }
  3591. else
  3592. {
  3593. opndType = IR::RegOpnd::New(TyMachReg, this->m_func);
  3594. }
  3595. opndBase = propertySymOpnd->CreatePropertyOwnerOpnd(m_func);
  3596. opndDst = instrLdFld->GetDst();
  3597. opndInlineCache = IR::RegOpnd::New(TyMachPtr, this->m_func);
  3598. labelFallThru = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  3599. // Label to jump to (or fall through to) when bailing out
  3600. bailOutLabel = IR::LabelInstr::New(Js::OpCode::Label, instrLdFld->m_func, true /* isOpHelper */);
  3601. instrLdFld->InsertBefore(IR::Instr::New(Js::OpCode::MOV, opndInlineCache, m_lowerer->LoadRuntimeInlineCacheOpnd(instrLdFld, propertySymOpnd), this->m_func));
  3602. IR::LabelInstr * labelFlagAux = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  3603. // Check the flag cache with the untagged type
  3604. this->m_lowerer->GenerateObjectTestAndTypeLoad(instrLdFld, opndBase, opndType, bailOutLabel);
  3605. // Blindly do the check for getter flag first and then do the type check
  3606. // We avoid repeated check for getter flag when the function object may be in either
  3607. // inline slots or auxiliary slots
  3608. GenerateFlagInlineCacheCheckForGetterSetter(instrLdFld, opndInlineCache, bailOutLabel);
  3609. GenerateFlagInlineCacheCheck(instrLdFld, opndType, opndInlineCache, labelFlagAux);
  3610. GenerateLdFldFromFlagInlineCache(instrLdFld, opndBase, opndDst, opndInlineCache, labelFallThru, true);
  3611. // Check the flag cache with the tagged type
  3612. instrLdFld->InsertBefore(labelFlagAux);
  3613. IR::RegOpnd * opndTaggedType = IR::RegOpnd::New(TyMachReg, this->m_func);
  3614. GenerateLoadTaggedType(instrLdFld, opndType, opndTaggedType);
  3615. GenerateFlagInlineCacheCheck(instrLdFld, opndTaggedType, opndInlineCache, bailOutLabel);
  3616. GenerateLdFldFromFlagInlineCache(instrLdFld, opndBase, opndDst, opndInlineCache, labelFallThru, false);
  3617. instrLdFld->InsertBefore(bailOutLabel);
  3618. instrLdFld->InsertAfter(labelFallThru);
  3619. // Generate the bailout helper call. 'instr' will be changed to the CALL into the bailout function, so it can't be used for
  3620. // ordering instructions anymore.
  3621. instrLdFld->UnlinkSrc1();
  3622. this->m_lowerer->GenerateBailOut(instrLdFld);
  3623. return true;
  3624. }
  3625. void
  3626. LowererMD::GenerateLoadPolymorphicInlineCacheSlot(IR::Instr * instrLdSt, IR::RegOpnd * opndInlineCache, IR::RegOpnd * opndType, uint polymorphicInlineCacheSize)
  3627. {
  3628. // Generate
  3629. //
  3630. // MOV r1, type
  3631. // SHR r1, PolymorphicInlineCacheShift
  3632. // AND r1, (size - 1)
  3633. // SHL r1, log2(sizeof(Js::InlineCache))
  3634. // LEA inlineCache, [inlineCache + r1]
  3635. // MOV r1, type
  3636. IR::RegOpnd * opndOffset = IR::RegOpnd::New(TyMachPtr, instrLdSt->m_func);
  3637. IR::Instr * instr = IR::Instr::New(Js::OpCode::MOV, opndOffset, opndType, instrLdSt->m_func);
  3638. instrLdSt->InsertBefore(instr);
  3639. IntConstType rightShiftAmount = PolymorphicInlineCacheShift;
  3640. IntConstType leftShiftAmount = Math::Log2(sizeof(Js::InlineCache));
  3641. // instead of generating
  3642. // SHR r1, PolymorphicInlineCacheShift
  3643. // AND r1, (size - 1)
  3644. // SHL r1, log2(sizeof(Js::InlineCache))
  3645. //
  3646. // we can generate:
  3647. // SHR r1, (PolymorphicInlineCacheShift - log2(sizeof(Js::InlineCache))
  3648. // AND r1, (size - 1) << log2(sizeof(Js::InlineCache))
  3649. Assert(rightShiftAmount > leftShiftAmount);
  3650. instr = IR::Instr::New(Js::OpCode::SHR, opndOffset, opndOffset, IR::IntConstOpnd::New(rightShiftAmount - leftShiftAmount, TyUint8, instrLdSt->m_func, true), instrLdSt->m_func);
  3651. instrLdSt->InsertBefore(instr);
  3652. instr = IR::Instr::New(Js::OpCode::AND, opndOffset, opndOffset, IR::AddrOpnd::New((void*)((IntConstType)(polymorphicInlineCacheSize - 1) << leftShiftAmount), IR::AddrOpndKindConstant, instrLdSt->m_func, true), instrLdSt->m_func);
  3653. instrLdSt->InsertBefore(instr);
  3654. // LEA inlineCache, [inlineCache + r1]
  3655. IR::IndirOpnd * indirOpnd = IR::IndirOpnd::New(opndInlineCache, opndOffset, TyMachPtr, instrLdSt->m_func);
  3656. instr = IR::Instr::New(Js::OpCode::LEA, opndInlineCache, indirOpnd, instrLdSt->m_func);
  3657. instrLdSt->InsertBefore(instr);
  3658. }
  3659. void
  3660. LowererMD::ChangeToWriteBarrierAssign(IR::Instr * assignInstr)
  3661. {
  3662. #ifdef RECYCLER_WRITE_BARRIER_JIT
  3663. if (assignInstr->GetSrc1()->IsWriteBarrierTriggerableValue())
  3664. {
  3665. IR::RegOpnd * writeBarrierAddrRegOpnd = IR::RegOpnd::New(TyMachPtr, assignInstr->m_func);
  3666. IR::Instr * leaInstr = IR::Instr::New(Js::OpCode::LEA, writeBarrierAddrRegOpnd, assignInstr->UnlinkDst(), assignInstr->m_func);
  3667. assignInstr->InsertBefore(leaInstr);
  3668. assignInstr->SetDst(IR::IndirOpnd::New(writeBarrierAddrRegOpnd, 0, TyMachReg, assignInstr->m_func));
  3669. GenerateWriteBarrier(writeBarrierAddrRegOpnd, assignInstr->m_next);
  3670. }
  3671. #endif
  3672. ChangeToAssign(assignInstr);
  3673. }
  3674. void
  3675. LowererMD::GenerateWriteBarrierAssign(IR::MemRefOpnd * opndDst, IR::Opnd * opndSrc, IR::Instr * insertBeforeInstr)
  3676. {
  3677. Lowerer::InsertMove(opndDst, opndSrc, insertBeforeInstr);
  3678. #ifdef RECYCLER_WRITE_BARRIER_JIT
  3679. if (opndSrc->IsWriteBarrierTriggerableValue())
  3680. {
  3681. void * address = opndDst->AsMemRefOpnd()->GetMemLoc();
  3682. #ifdef RECYCLER_WRITE_BARRIER_BYTE
  3683. IR::MemRefOpnd * cardTableEntry = IR::MemRefOpnd::New(
  3684. &RecyclerWriteBarrierManager::GetAddressOfCardTable()[RecyclerWriteBarrierManager::GetCardTableIndex(address)], TyInt8, insertBeforeInstr->m_func);
  3685. IR::Instr * movInstr = IR::Instr::New(Js::OpCode::MOV, cardTableEntry, IR::IntConstOpnd::New(1, TyInt8, insertBeforeInstr->m_func), insertBeforeInstr->m_func);
  3686. insertBeforeInstr->InsertBefore(movInstr);
  3687. #else
  3688. IR::MemRefOpnd * cardTableEntry = IR::MemRefOpnd::New(
  3689. &RecyclerWriteBarrierManager::GetAddressOfCardTable()[RecyclerWriteBarrierManager::GetCardTableIndex(address)], TyMachPtr, insertBeforeInstr->m_func);
  3690. IR::Instr * orInstr = IR::Instr::New(Js::OpCode::OR, cardTableEntry,
  3691. IR::IntConstOpnd::New(1 << ((uint)address >> 7), TyInt32, insertBeforeInstr->m_func), insertBeforeInstr->m_func);
  3692. insertBeforeInstr->InsertBefore(orInstr);
  3693. #endif
  3694. }
  3695. #endif
  3696. }
  3697. void
  3698. LowererMD::GenerateWriteBarrierAssign(IR::IndirOpnd * opndDst, IR::Opnd * opndSrc, IR::Instr * insertBeforeInstr)
  3699. {
  3700. #ifdef RECYCLER_WRITE_BARRIER_JIT
  3701. if (opndSrc->IsWriteBarrierTriggerableValue())
  3702. {
  3703. IR::RegOpnd * writeBarrierAddrRegOpnd = IR::RegOpnd::New(TyMachPtr, insertBeforeInstr->m_func);
  3704. insertBeforeInstr->InsertBefore(IR::Instr::New(Js::OpCode::LEA, writeBarrierAddrRegOpnd, opndDst, insertBeforeInstr->m_func));
  3705. insertBeforeInstr->InsertBefore(IR::Instr::New(Js::OpCode::MOV,
  3706. IR::IndirOpnd::New(writeBarrierAddrRegOpnd, 0, TyMachReg, insertBeforeInstr->m_func), opndSrc, insertBeforeInstr->m_func));
  3707. GenerateWriteBarrier(writeBarrierAddrRegOpnd, insertBeforeInstr);
  3708. // The mov happens above, and it's slightly faster doing it that way since we've already calculated the address we're writing to
  3709. return;
  3710. }
  3711. #endif
  3712. Lowerer::InsertMove(opndDst, opndSrc, insertBeforeInstr);
  3713. return;
  3714. }
  3715. #ifdef RECYCLER_WRITE_BARRIER_JIT
  3716. void
  3717. LowererMD::GenerateWriteBarrier(IR::Opnd * writeBarrierAddrRegOpnd, IR::Instr * insertBeforeInstr)
  3718. {
  3719. #if defined(RECYCLER_WRITE_BARRIER_BYTE)
  3720. IR::RegOpnd * indexOpnd = IR::RegOpnd::New(TyMachPtr, insertBeforeInstr->m_func);
  3721. IR::Instr * loadIndexInstr = IR::Instr::New(Js::OpCode::MOV, indexOpnd, writeBarrierAddrRegOpnd, insertBeforeInstr->m_func);
  3722. insertBeforeInstr->InsertBefore(loadIndexInstr);
  3723. IR::Instr * shiftBitInstr = IR::Instr::New(Js::OpCode::SHR, indexOpnd, indexOpnd,
  3724. IR::IntConstOpnd::New(12 /* 1 << 12 = 4096 */, TyInt32, insertBeforeInstr->m_func), insertBeforeInstr->m_func);
  3725. insertBeforeInstr->InsertBefore(shiftBitInstr);
  3726. IR::RegOpnd * cardTableRegOpnd = IR::RegOpnd::New(TyMachReg, insertBeforeInstr->m_func);
  3727. IR::Instr * cardTableAddrInstr = IR::Instr::New(Js::OpCode::MOV, cardTableRegOpnd,
  3728. IR::AddrOpnd::New(RecyclerWriteBarrierManager::GetAddressOfCardTable(), IR::AddrOpndKindDynamicMisc, insertBeforeInstr->m_func),
  3729. insertBeforeInstr->m_func);
  3730. insertBeforeInstr->InsertBefore(cardTableAddrInstr);
  3731. IR::IndirOpnd * cardTableEntryOpnd = IR::IndirOpnd::New(cardTableRegOpnd, indexOpnd,
  3732. TyInt8, insertBeforeInstr->m_func);
  3733. IR::Instr * movInstr = IR::Instr::New(Js::OpCode::MOV, cardTableEntryOpnd, IR::IntConstOpnd::New(1, TyInt8, insertBeforeInstr->m_func), insertBeforeInstr->m_func);
  3734. insertBeforeInstr->InsertBefore(movInstr);
  3735. #else
  3736. Assert(writeBarrierAddrRegOpnd->IsRegOpnd());
  3737. IR::RegOpnd * shiftBitOpnd = IR::RegOpnd::New(TyInt32, insertBeforeInstr->m_func);
  3738. shiftBitOpnd->SetReg(LowererMDArch::GetRegShiftCount());
  3739. IR::Instr * moveShiftBitOpnd = IR::Instr::New(Js::OpCode::MOV, shiftBitOpnd, writeBarrierAddrRegOpnd, insertBeforeInstr->m_func);
  3740. insertBeforeInstr->InsertBefore(moveShiftBitOpnd);
  3741. IR::Instr * shiftBitInstr = IR::Instr::New(Js::OpCode::SHR, shiftBitOpnd, shiftBitOpnd,
  3742. IR::IntConstOpnd::New(7 /* 1 << 7 = 128 */, TyInt32, insertBeforeInstr->m_func), insertBeforeInstr->m_func);
  3743. insertBeforeInstr->InsertBefore(shiftBitInstr);
  3744. IR::RegOpnd * bitOpnd = IR::RegOpnd::New(TyInt32, insertBeforeInstr->m_func);
  3745. IR::Instr * mov1Instr = IR::Instr::New(Js::OpCode::MOV, bitOpnd,
  3746. IR::IntConstOpnd::New(1, TyInt32, insertBeforeInstr->m_func), insertBeforeInstr->m_func);
  3747. insertBeforeInstr->InsertBefore(mov1Instr);
  3748. IR::Instr * bitInstr = IR::Instr::New(Js::OpCode::SHL, bitOpnd, bitOpnd, shiftBitOpnd, insertBeforeInstr->m_func);
  3749. insertBeforeInstr->InsertBefore(bitInstr);
  3750. IR::RegOpnd * indexOpnd = shiftBitOpnd;
  3751. IR::Instr * indexInstr = IR::Instr::New(Js::OpCode::SHR, indexOpnd, indexOpnd,
  3752. IR::IntConstOpnd::New(5 /* 1 << 5 = 32 */, TyInt32, insertBeforeInstr->m_func), insertBeforeInstr->m_func);
  3753. insertBeforeInstr->InsertBefore(indexInstr);
  3754. IR::RegOpnd * cardTableRegOpnd = IR::RegOpnd::New(TyMachReg, insertBeforeInstr->m_func);
  3755. IR::Instr * cardTableAddrInstr = IR::Instr::New(Js::OpCode::MOV, cardTableRegOpnd,
  3756. IR::AddrOpnd::New(RecyclerWriteBarrierManager::GetAddressOfCardTable(), IR::AddrOpndKindDynamicMisc, insertBeforeInstr->m_func),
  3757. insertBeforeInstr->m_func);
  3758. insertBeforeInstr->InsertBefore(cardTableAddrInstr);
  3759. IR::IndirOpnd * cardTableEntryOpnd = IR::IndirOpnd::New(cardTableRegOpnd, indexOpnd, LowererMDArch::GetDefaultIndirScale(),
  3760. TyInt32, insertBeforeInstr->m_func);
  3761. IR::Instr * orInstr = IR::Instr::New(Js::OpCode::OR, cardTableEntryOpnd, cardTableEntryOpnd,
  3762. bitOpnd, insertBeforeInstr->m_func);
  3763. insertBeforeInstr->InsertBefore(orInstr);
  3764. #endif
  3765. }
  3766. #endif
  3767. void
  3768. LowererMD::GenerateStFldFromLocalInlineCache(
  3769. IR::Instr * instrStFld,
  3770. IR::RegOpnd * opndBase,
  3771. IR::Opnd * opndSrc,
  3772. IR::RegOpnd * inlineCache,
  3773. IR::LabelInstr * labelFallThru,
  3774. bool isInlineSlot)
  3775. {
  3776. IR::Instr * instr;
  3777. IR::Opnd* slotIndexOpnd;
  3778. IR::RegOpnd * opndIndirBase = opndBase;
  3779. if (!isInlineSlot)
  3780. {
  3781. // slotArray = MOV base->slots -- load the slot array
  3782. IR::RegOpnd * opndSlotArray = IR::RegOpnd::New(TyMachReg, instrStFld->m_func);
  3783. IR::IndirOpnd * opndIndir = IR::IndirOpnd::New(opndBase, Js::DynamicObject::GetOffsetOfAuxSlots(), TyMachReg, instrStFld->m_func);
  3784. instr = IR::Instr::New(Js::OpCode::MOV, opndSlotArray, opndIndir, instrStFld->m_func);
  3785. instrStFld->InsertBefore(instr);
  3786. opndIndirBase = opndSlotArray;
  3787. }
  3788. // slotIndex = MOV [&inlineCache->u.local.inlineSlotOffsetOrAuxSlotIndex] -- load the cached slot offset or index
  3789. IR::RegOpnd * opndSlotIndex = IR::RegOpnd::New(TyMachReg, instrStFld->m_func);
  3790. slotIndexOpnd = IR::IndirOpnd::New(inlineCache, (int32)offsetof(Js::InlineCache, u.local.slotIndex), TyUint16, instrStFld->m_func);
  3791. instr = IR::Instr::New(Js::OpCode::MOVZXW, opndSlotIndex, slotIndexOpnd, instrStFld->m_func);
  3792. instrStFld->InsertBefore(instr);
  3793. // [base + slotIndex * (1 << indirScale)] = MOV src -- store the value directly to the slot
  3794. // [slotArray + slotIndex * (1 << indirScale)] = MOV src -- store the value directly to the slot
  3795. IR::IndirOpnd * storeLocIndirOpnd = IR::IndirOpnd::New(opndIndirBase, opndSlotIndex,
  3796. LowererMDArch::GetDefaultIndirScale(), TyMachReg, instrStFld->m_func);
  3797. GenerateWriteBarrierAssign(storeLocIndirOpnd, opndSrc, instrStFld);
  3798. // JMP $fallthru
  3799. instr = IR::BranchInstr::New(Js::OpCode::JMP, labelFallThru, instrStFld->m_func);
  3800. instrStFld->InsertBefore(instr);
  3801. }
  3802. void LowererMD::InsertIncUInt8PreventOverflow(
  3803. IR::Opnd *const dst,
  3804. IR::Opnd *const src,
  3805. IR::Instr *const insertBeforeInstr,
  3806. IR::Instr * *const onOverflowInsertBeforeInstrRef)
  3807. {
  3808. Assert(dst);
  3809. Assert(dst->GetType() == TyUint8);
  3810. Assert(src);
  3811. Assert(src->GetType() == TyUint8);
  3812. Assert(insertBeforeInstr);
  3813. Func *const func = insertBeforeInstr->m_func;
  3814. // Generate:
  3815. // cmp src, static_cast<uint8>(-1)
  3816. // jeq $done
  3817. // dst = add src, 1
  3818. // $noOverflow:
  3819. IR::LabelInstr *const noOverflowLabel = Lowerer::InsertLabel(false, insertBeforeInstr);
  3820. Lowerer::InsertCompareBranch(src, IR::IntConstOpnd::New(static_cast<uint8>(-1), TyUint8, func, true),
  3821. Js::OpCode::BrEq_A, noOverflowLabel, noOverflowLabel);
  3822. // inc dst, src
  3823. Lowerer::InsertAdd(true, dst, src, IR::IntConstOpnd::New(1, TyUint8, func, true), noOverflowLabel);
  3824. // $done:
  3825. if(onOverflowInsertBeforeInstrRef)
  3826. {
  3827. *onOverflowInsertBeforeInstrRef = noOverflowLabel;
  3828. }
  3829. }
  3830. void LowererMD::InsertDecUInt8PreventOverflow(
  3831. IR::Opnd *const dst,
  3832. IR::Opnd *const src,
  3833. IR::Instr *const insertBeforeInstr,
  3834. IR::Instr * *const onOverflowInsertBeforeInstrRef)
  3835. {
  3836. Assert(dst);
  3837. Assert(dst->GetType() == TyUint8);
  3838. Assert(src);
  3839. Assert(src->GetType() == TyUint8);
  3840. Assert(insertBeforeInstr);
  3841. Func *const func = insertBeforeInstr->m_func;
  3842. // Generate:
  3843. // sub dst, src, 1
  3844. // jnc $noOverflow
  3845. // mov dst, 0
  3846. // $noOverflow:
  3847. IR::LabelInstr *const noOverflowLabel = Lowerer::InsertLabel(false, insertBeforeInstr);
  3848. // sub dst, src, 1
  3849. IR::Instr *const instr = IR::Instr::New(Js::OpCode::SUB, dst, src, IR::IntConstOpnd::New(1, TyUint8, func, true), func);
  3850. noOverflowLabel->InsertBefore(instr);
  3851. MakeDstEquSrc1(instr);
  3852. // jnc $noOverflow
  3853. Lowerer::InsertBranch(Js::OpCode::BrGe_A, true, noOverflowLabel, noOverflowLabel);
  3854. // mov dst, 0
  3855. Lowerer::InsertMove(dst, IR::IntConstOpnd::New(0, TyUint8, func, true), noOverflowLabel);
  3856. // $noOverflow:
  3857. if(onOverflowInsertBeforeInstrRef)
  3858. {
  3859. *onOverflowInsertBeforeInstrRef = noOverflowLabel;
  3860. }
  3861. }
  3862. //----------------------------------------------------------------------------
  3863. //
  3864. // LowererMD::GenerateFastScopedLdFld
  3865. //
  3866. // Make use of the helper to cache the type and slot index used to do a ScopedLdFld
  3867. // when the scope is an array of length 1.
  3868. // Extract the only element from array and do an inline load from the appropriate slot
  3869. // if the type hasn't changed since the last time this ScopedLdFld was executed.
  3870. //
  3871. //----------------------------------------------------------------------------
  3872. IR::Instr *
  3873. LowererMD::GenerateFastScopedLdFld(IR::Instr * instrLdScopedFld)
  3874. {
  3875. // CMP [base + offset(length)], 1 -- get the length on array and test if it is 1.
  3876. // JNE $helper
  3877. // MOV r1, [base + offset(scopes)] -- load the first scope
  3878. // MOV r2, r1->type
  3879. // CMP r2, [&(inlineCache->u.local.type)] -- check type
  3880. // JNE $helper
  3881. // MOV r1, r1->slots -- load the slots array
  3882. // MOV r2 , [&(inlineCache->u.local.slotIndex)] -- load the cached slot index
  3883. // MOV dst, [r1+r2] -- load the value from the slot
  3884. // JMP $fallthru
  3885. // $helper:
  3886. // dst = CALL PatchGetPropertyScoped(inlineCache, base, field, defaultInstance, scriptContext)
  3887. // $fallthru:
  3888. IR::RegOpnd * opndBase;
  3889. IR::Instr * instr;
  3890. IR::IndirOpnd * indirOpnd;
  3891. IR::LabelInstr * labelHelper;
  3892. IR::Opnd * opndDst;
  3893. IR::RegOpnd * inlineCache;
  3894. IR::RegOpnd *r1;
  3895. IR::LabelInstr * labelFallThru;
  3896. IR::Opnd *propertySrc = instrLdScopedFld->GetSrc1();
  3897. AssertMsg(propertySrc->IsSymOpnd() && propertySrc->AsSymOpnd()->IsPropertySymOpnd() && propertySrc->AsSymOpnd()->m_sym->IsPropertySym(),
  3898. "Expected property sym operand as src of LdScoped");
  3899. IR::PropertySymOpnd * propertySymOpnd = propertySrc->AsPropertySymOpnd();
  3900. opndBase = propertySymOpnd->CreatePropertyOwnerOpnd(m_func);
  3901. IR::Opnd *srcBase = instrLdScopedFld->GetSrc2();
  3902. AssertMsg(srcBase->IsRegOpnd(), "Expected reg opnd as src2");
  3903. //opndBase = srcBase;
  3904. //IR::IndirOpnd * indirOpnd = src->AsIndirOpnd();
  3905. labelHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
  3906. AssertMsg(opndBase->m_sym->m_isSingleDef, "We assume this isn't redefined");
  3907. // CMP [base + offset(length)], 1 -- get the length on array and test if it is 1.
  3908. indirOpnd = IR::IndirOpnd::New(opndBase, Js::FrameDisplay::GetOffsetOfLength(), TyInt16, this->m_func);
  3909. instr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  3910. instr->SetSrc1(indirOpnd);
  3911. instr->SetSrc2(IR::IntConstOpnd::New(0x1, TyInt8, this->m_func));
  3912. instrLdScopedFld->InsertBefore(instr);
  3913. // JNE $helper
  3914. instr = IR::BranchInstr::New(Js::OpCode::JNE, labelHelper, this->m_func);
  3915. instrLdScopedFld->InsertBefore(instr);
  3916. // MOV r1, [base + offset(scopes)] -- load the first scope
  3917. indirOpnd = IR::IndirOpnd::New(opndBase, Js::FrameDisplay::GetOffsetOfScopes(), TyMachReg, this->m_func);
  3918. r1 = IR::RegOpnd::New(TyMachReg, this->m_func);
  3919. instr = IR::Instr::New(Js::OpCode::MOV, r1, indirOpnd, this->m_func);
  3920. instrLdScopedFld->InsertBefore(instr);
  3921. //first load the inlineCache type
  3922. inlineCache = IR::RegOpnd::New(TyMachPtr, this->m_func);
  3923. Assert(inlineCache != nullptr);
  3924. IR::RegOpnd * opndType = IR::RegOpnd::New(TyMachReg, this->m_func);
  3925. opndDst = instrLdScopedFld->GetDst();
  3926. labelFallThru = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  3927. r1->m_sym->m_isNotInt = true;
  3928. // Load the type
  3929. this->m_lowerer->GenerateObjectTestAndTypeLoad(instrLdScopedFld, r1, opndType, labelHelper);
  3930. // Check the local cache with the tagged type
  3931. IR::RegOpnd * opndTaggedType = IR::RegOpnd::New(TyMachReg, this->m_func);
  3932. GenerateLoadTaggedType(instrLdScopedFld, opndType, opndTaggedType);
  3933. instrLdScopedFld->InsertBefore(IR::Instr::New(Js::OpCode::MOV, inlineCache, m_lowerer->LoadRuntimeInlineCacheOpnd(instrLdScopedFld, propertySymOpnd), this->m_func));
  3934. GenerateLocalInlineCacheCheck(instrLdScopedFld, opndTaggedType, inlineCache, labelHelper);
  3935. GenerateLdFldFromLocalInlineCache(instrLdScopedFld, r1, opndDst, inlineCache, labelFallThru, false);
  3936. // $helper:
  3937. // dst = CALL PatchGetPropertyScoped(inlineCache, opndBase, propertyId, srcBase, scriptContext)
  3938. // $fallthru:
  3939. instrLdScopedFld->InsertBefore(labelHelper);
  3940. instrLdScopedFld->InsertAfter(labelFallThru);
  3941. return instrLdScopedFld->m_prev;
  3942. }
  3943. //----------------------------------------------------------------------------
  3944. //
  3945. // LowererMD::GenerateFastScopedStFld
  3946. //
  3947. // Make use of the helper to cache the type and slot index used to do a ScopedStFld
  3948. // when the scope is an array of length 1.
  3949. // Extract the only element from array and do an inline load from the appropriate slot
  3950. // if the type hasn't changed since the last time this ScopedStFld was executed.
  3951. //
  3952. //----------------------------------------------------------------------------
  3953. IR::Instr *
  3954. LowererMD::GenerateFastScopedStFld(IR::Instr * instrStScopedFld)
  3955. {
  3956. // CMP [base + offset(length)], 1 -- get the length on array and test if it is 1.
  3957. // JNE $helper
  3958. // MOV r1, [base + offset(scopes)] -- load the first scope
  3959. // MOV r2, r1->type
  3960. // CMP r2, [&(inlineCache->u.local.type)] -- check type
  3961. // JNE $helper
  3962. // MOV r1, r1->slots -- load the slots array
  3963. // MOV r2, [&(inlineCache->u.local.slotIndex)] -- load the cached slot index
  3964. // [r1 + r2*4] = MOV value -- store the value directly to the slot
  3965. // JMP $fallthru
  3966. // $helper:
  3967. // CALL PatchSetPropertyScoped(inlineCache, base, field, value, defaultInstance, scriptContext)
  3968. // $fallthru:
  3969. IR::RegOpnd * opndBase;
  3970. IR::Instr * instr;
  3971. IR::IndirOpnd * indirOpnd;
  3972. IR::LabelInstr * labelHelper;
  3973. IR::Opnd * opndDst;
  3974. IR::RegOpnd * inlineCache;
  3975. IR::RegOpnd *r1;
  3976. IR::LabelInstr * labelFallThru;
  3977. IR::Opnd *newValue = instrStScopedFld->GetSrc1();
  3978. // IR::Opnd *defaultInstance = instrStScopedFld->UnlinkSrc2();
  3979. opndDst = instrStScopedFld->GetDst();
  3980. AssertMsg(opndDst->IsSymOpnd() && opndDst->AsSymOpnd()->IsPropertySymOpnd() && opndDst->AsSymOpnd()->m_sym->IsPropertySym(),
  3981. "Expected property sym operand as dst of StScoped");
  3982. IR::PropertySymOpnd * propertySymOpnd = opndDst->AsPropertySymOpnd();
  3983. opndBase = propertySymOpnd->CreatePropertyOwnerOpnd(m_func);
  3984. labelHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
  3985. AssertMsg(opndBase->m_sym->m_isSingleDef, "We assume this isn't redefined");
  3986. // CMP [base + offset(length)], 1 -- get the length on array and test if it is 1.
  3987. indirOpnd = IR::IndirOpnd::New(opndBase, Js::FrameDisplay::GetOffsetOfLength(), TyInt16, this->m_func);
  3988. instr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  3989. instr->SetSrc1(indirOpnd);
  3990. instr->SetSrc2(IR::IntConstOpnd::New(0x1, TyInt8, this->m_func));
  3991. instrStScopedFld->InsertBefore(instr);
  3992. // JNE $helper
  3993. instr = IR::BranchInstr::New(Js::OpCode::JNE, labelHelper, this->m_func);
  3994. instrStScopedFld->InsertBefore(instr);
  3995. // MOV r1, [base + offset(scopes)] -- load the first scope
  3996. indirOpnd = IR::IndirOpnd::New(opndBase, Js::FrameDisplay::GetOffsetOfScopes(), TyMachReg, this->m_func);
  3997. r1 = IR::RegOpnd::New(TyMachReg, this->m_func);
  3998. instr = IR::Instr::New(Js::OpCode::MOV, r1, indirOpnd, this->m_func);
  3999. instrStScopedFld->InsertBefore(instr);
  4000. //first load the inlineCache type
  4001. inlineCache = IR::RegOpnd::New(TyMachPtr, this->m_func);
  4002. Assert(inlineCache != nullptr);
  4003. IR::RegOpnd * opndType = IR::RegOpnd::New(TyMachReg, this->m_func);
  4004. labelFallThru = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  4005. r1->m_sym->m_isNotInt = true;
  4006. // Load the type
  4007. this->m_lowerer->GenerateObjectTestAndTypeLoad(instrStScopedFld, r1, opndType, labelHelper);
  4008. // Check the local cache with the tagged type
  4009. IR::RegOpnd * opndTaggedType = IR::RegOpnd::New(TyMachReg, this->m_func);
  4010. GenerateLoadTaggedType(instrStScopedFld, opndType, opndTaggedType);
  4011. instrStScopedFld->InsertBefore(IR::Instr::New(Js::OpCode::MOV, inlineCache, m_lowerer->LoadRuntimeInlineCacheOpnd(instrStScopedFld, propertySymOpnd), this->m_func));
  4012. GenerateLocalInlineCacheCheck(instrStScopedFld, opndTaggedType, inlineCache, labelHelper);
  4013. GenerateStFldFromLocalInlineCache(instrStScopedFld, r1, newValue, inlineCache, labelFallThru, false);
  4014. // $helper:
  4015. // CALL PatchSetPropertyScoped(inlineCache, opndBase, propertyId, newValue, defaultInstance, scriptContext)
  4016. // $fallthru:
  4017. instrStScopedFld->InsertBefore(labelHelper);
  4018. instrStScopedFld->InsertAfter(labelFallThru);
  4019. return instrStScopedFld->m_prev;
  4020. }
  4021. IR::Opnd *
  4022. LowererMD::CreateStackArgumentsSlotOpnd()
  4023. {
  4024. StackSym *sym = StackSym::New(TyMachReg, this->m_func);
  4025. sym->m_offset = -MachArgsSlotOffset;
  4026. sym->m_allocated = true;
  4027. return IR::SymOpnd::New(sym, TyMachReg, this->m_func);
  4028. }
  4029. IR::RegOpnd *
  4030. LowererMD::GenerateUntagVar(IR::RegOpnd * src, IR::LabelInstr * labelFail, IR::Instr * insertBeforeInstr, bool generateTagCheck)
  4031. {
  4032. Assert(src->IsVar());
  4033. // MOV valueOpnd, index
  4034. IR::RegOpnd *valueOpnd = IR::RegOpnd::New(TyInt32, this->m_func);
  4035. //
  4036. // Convert Index to 32 bits.
  4037. //
  4038. IR::Opnd * opnd = src->UseWithNewType(TyMachReg, this->m_func);
  4039. #if INT32VAR
  4040. if (generateTagCheck)
  4041. {
  4042. Assert(!opnd->IsTaggedInt());
  4043. this->GenerateSmIntTest(opnd, insertBeforeInstr, labelFail);
  4044. }
  4045. // Moving into r2 clears the tag bits on AMD64.
  4046. IR::Instr * instr = IR::Instr::New(Js::OpCode::MOV_TRUNC, valueOpnd, opnd, this->m_func);
  4047. insertBeforeInstr->InsertBefore(instr);
  4048. #else
  4049. IR::Instr * instr = IR::Instr::New(Js::OpCode::MOV, valueOpnd, opnd, this->m_func);
  4050. insertBeforeInstr->InsertBefore(instr);
  4051. // SAR valueOpnd, Js::VarTag_Shift
  4052. instr = IR::Instr::New(Js::OpCode::SAR, valueOpnd, valueOpnd,
  4053. IR::IntConstOpnd::New(Js::VarTag_Shift, TyInt8, this->m_func), this->m_func);
  4054. insertBeforeInstr->InsertBefore(instr);
  4055. if (generateTagCheck)
  4056. {
  4057. Assert(!opnd->IsTaggedInt());
  4058. // SAR set the carry flag (CF) to 1 if the lower bit is 1
  4059. // JAE will jmp if CF = 0
  4060. instr = IR::BranchInstr::New(Js::OpCode::JAE, labelFail, this->m_func);
  4061. insertBeforeInstr->InsertBefore(instr);
  4062. }
  4063. #endif
  4064. return valueOpnd;
  4065. }
  4066. IR::RegOpnd *LowererMD::LoadNonnegativeIndex(
  4067. IR::RegOpnd *indexOpnd,
  4068. const bool skipNegativeCheck,
  4069. IR::LabelInstr *const notTaggedIntLabel,
  4070. IR::LabelInstr *const negativeLabel,
  4071. IR::Instr *const insertBeforeInstr)
  4072. {
  4073. Assert(indexOpnd);
  4074. Assert(indexOpnd->IsVar() || indexOpnd->GetType() == TyInt32 || indexOpnd->GetType() == TyUint32);
  4075. Assert(indexOpnd->GetType() != TyUint32 || skipNegativeCheck);
  4076. Assert(!indexOpnd->IsVar() || notTaggedIntLabel);
  4077. Assert(skipNegativeCheck || negativeLabel);
  4078. Assert(insertBeforeInstr);
  4079. if(indexOpnd->IsVar())
  4080. {
  4081. if (indexOpnd->GetValueType().IsLikelyFloat()
  4082. #ifdef _M_IX86
  4083. && AutoSystemInfo::Data.SSE2Available()
  4084. #endif
  4085. )
  4086. {
  4087. return m_lowerer->LoadIndexFromLikelyFloat(indexOpnd, skipNegativeCheck, notTaggedIntLabel, negativeLabel, insertBeforeInstr);
  4088. }
  4089. // mov intIndex, index
  4090. // sar intIndex, 1
  4091. // jae $notTaggedIntOrNegative
  4092. indexOpnd = GenerateUntagVar(indexOpnd, notTaggedIntLabel, insertBeforeInstr, !indexOpnd->IsTaggedInt());
  4093. }
  4094. if(!skipNegativeCheck)
  4095. {
  4096. // test index, index
  4097. // js $notTaggedIntOrNegative
  4098. Lowerer::InsertTestBranch(indexOpnd, indexOpnd, Js::OpCode::JSB, negativeLabel, insertBeforeInstr);
  4099. }
  4100. return indexOpnd;
  4101. }
  4102. IR::IndirOpnd *
  4103. LowererMD::GenerateFastElemIStringIndexCommon(IR::Instr * instrInsert, bool isStore, IR::IndirOpnd * indirOpnd, IR::LabelInstr * labelHelper)
  4104. {
  4105. IR::RegOpnd *indexOpnd = indirOpnd->GetIndexOpnd();
  4106. IR::RegOpnd *baseOpnd = indirOpnd->GetBaseOpnd();
  4107. Assert(baseOpnd != nullptr);
  4108. Assert(indexOpnd->GetValueType().IsLikelyString());
  4109. // Generates:
  4110. // CMP indexOpnd, PropertyString::`vtable' -- check if index is property string
  4111. // JNE $helper
  4112. // MOV propertyCacheOpnd, index->propCache
  4113. // TEST baseOpnd, AtomTag -- check base not tagged int
  4114. // JNE $helper
  4115. // MOV objectTypeOpnd, baseOpnd->type
  4116. // CMP [propertyCacheOpnd->type], objectTypeOpnd -- check if object type match the cache
  4117. // JNE $helper
  4118. // CMP [propertyCacheOpnd->isInlineSlot,1] -- check if it is inline slots
  4119. // JEQ $inlineSlot
  4120. // MOV slotOpnd, [baseOpnd->slot] -- load the aux slot
  4121. // JMP $afterLabel
  4122. // $inlineSlot:
  4123. // MOV slotOpnd, baseOpnd -- use the object as start of the slot offset
  4124. // $afterLabel:
  4125. // MOVZXW offsetOpnd, [propertyCacheOpnd->dataSlotIndex] -- load the slot index
  4126. // <use [slotOpnd + offsetOpnd * PtrSize]>
  4127. // CMP indexOpnd, PropertyString::`vtable' -- check if index is property string
  4128. // JNE $helper
  4129. this->m_lowerer->InsertCompareBranch(
  4130. IR::IndirOpnd::New(indexOpnd, 0, TyMachPtr, this->m_func),
  4131. m_lowerer->LoadVTableValueOpnd(instrInsert, VTableValue::VtablePropertyString),
  4132. Js::OpCode::BrNeq_A, labelHelper, instrInsert);
  4133. // MOV propertyCacheOpnd, indexOpnd->propCache
  4134. IR::RegOpnd * propertyCacheOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
  4135. IR::Instr * loadPropertyCacheInstr = IR::Instr::New(Js::OpCode::MOV, propertyCacheOpnd,
  4136. IR::IndirOpnd::New(indexOpnd, Js::PropertyString::GetOffsetOfPropertyCache(), TyMachPtr,
  4137. this->m_func), this->m_func);
  4138. instrInsert->InsertBefore(loadPropertyCacheInstr);
  4139. // TEST baseOpnd, AtomTag -- check base not tagged int
  4140. // JNE $helper
  4141. if(!baseOpnd->IsNotTaggedValue())
  4142. {
  4143. GenerateObjectTest(baseOpnd, instrInsert, labelHelper);
  4144. }
  4145. // MOV s2, baseOpnd->type
  4146. // CMP [propertyCacheOpnd->type], s2 -- check if object type match the cache
  4147. // JNE $helper
  4148. IR::RegOpnd * objectTypeOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
  4149. IR::Instr * loadObjectTypeInstr = IR::Instr::New(Js::OpCode::MOV,
  4150. objectTypeOpnd, IR::IndirOpnd::New(baseOpnd, Js::RecyclableObject::GetOffsetOfType(), TyMachPtr, this->m_func),
  4151. this->m_func);
  4152. instrInsert->InsertBefore(loadObjectTypeInstr);
  4153. IR::Instr * checkTypeInstr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  4154. checkTypeInstr->SetSrc1(IR::IndirOpnd::New(propertyCacheOpnd, (int32)offsetof(Js::PropertyCache, type), TyMachPtr, this->m_func));
  4155. checkTypeInstr->SetSrc2(objectTypeOpnd);
  4156. instrInsert->InsertBefore(checkTypeInstr);
  4157. instrInsert->InsertBefore(IR::BranchInstr::New(Js::OpCode::JNE, labelHelper, this->m_func));
  4158. if (isStore)
  4159. {
  4160. IR::IndirOpnd* isStoreEnabledOpnd = IR::IndirOpnd::New(propertyCacheOpnd, (int32)offsetof(Js::PropertyCache, isStoreFieldEnabled), TyInt8, this->m_func);
  4161. IR::IntConstOpnd* zeroOpnd = IR::IntConstOpnd::New(0, TyInt8, this->m_func, /* dontEncode = */ true);
  4162. this->m_lowerer->InsertCompareBranch(isStoreEnabledOpnd, zeroOpnd, Js::OpCode::BrEq_A, labelHelper, instrInsert);
  4163. }
  4164. // CMP [propertyCacheOpnd->isInlineSlot,1] -- check if it is inline slots
  4165. // JEQ $inlineSlot
  4166. IR::Instr * inlineSlotTestInstr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  4167. inlineSlotTestInstr->SetSrc1(IR::IndirOpnd::New(propertyCacheOpnd, (int32)offsetof(Js::PropertyCache, isInlineSlot), TyInt8, this->m_func));
  4168. inlineSlotTestInstr->SetSrc2(IR::IntConstOpnd::New(1, TyInt8, this->m_func));
  4169. instrInsert->InsertBefore(inlineSlotTestInstr);
  4170. IR::LabelInstr * isInlineSlotLabel = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  4171. instrInsert->InsertBefore(IR::BranchInstr::New(Js::OpCode::JEQ, isInlineSlotLabel, this->m_func));
  4172. // MOV slotOpnd, [baseOpnd->slot] -- load the aux slot
  4173. // JMP $afterLabel
  4174. IR::RegOpnd * slotOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
  4175. instrInsert->InsertBefore(IR::Instr::New(Js::OpCode::MOV, slotOpnd,
  4176. IR::IndirOpnd::New(baseOpnd, Js::DynamicObject::GetOffsetOfAuxSlots(), TyMachPtr, this->m_func), this->m_func));
  4177. IR::LabelInstr * afterLabel = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  4178. instrInsert->InsertBefore(IR::BranchInstr::New(Js::OpCode::JMP, afterLabel, this->m_func));
  4179. // $inlineSlot:
  4180. // MOV slotOpnd, baseOpnd -- use the object as start of the slot offset
  4181. instrInsert->InsertBefore(isInlineSlotLabel);
  4182. instrInsert->InsertBefore(IR::Instr::New(Js::OpCode::MOV, slotOpnd, baseOpnd, this->m_func));
  4183. // $afterLabel:
  4184. // MOVZXW offsetOpnd, [propertyCacheOpnd->dataSlotIndex] -- load the slot index
  4185. instrInsert->InsertBefore(afterLabel);
  4186. IR::RegOpnd * offsetOpnd = IR::RegOpnd::New(TyInt32, this->m_func);
  4187. instrInsert->InsertBefore(IR::Instr::New(Js::OpCode::MOVZXW, offsetOpnd,
  4188. IR::IndirOpnd::New(propertyCacheOpnd, (int32)offsetof(Js::PropertyCache, dataSlotIndex), TyUint16, this->m_func), this->m_func));
  4189. // return [slotOpnd + offsetOpnd * PtrSize]
  4190. return IR::IndirOpnd::New(slotOpnd, offsetOpnd, this->GetDefaultIndirScale(), TyVar, this->m_func);
  4191. }
  4192. void
  4193. LowererMD::GenerateFastBrBReturn(IR::Instr *instr)
  4194. {
  4195. Assert(instr->m_opcode == Js::OpCode::BrOnEmpty || instr->m_opcode == Js::OpCode::BrOnNotEmpty);
  4196. AssertMsg(instr->GetSrc1() != nullptr && instr->GetSrc2() == nullptr, "Expected 1 src opnds on BrB");
  4197. Assert(instr->GetSrc1()->IsRegOpnd());
  4198. IR::RegOpnd * forInEnumeratorOpnd = instr->GetSrc1()->AsRegOpnd();
  4199. IR::LabelInstr * labelHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
  4200. // MOV firstPrototypeOpnd, forInEnumerator->firstPrototype
  4201. // TEST firstPrototypeOpnd, firstPrototypeOpnd
  4202. // JNE $helper
  4203. IR::RegOpnd * firstPrototypeOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
  4204. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, firstPrototypeOpnd,
  4205. IR::IndirOpnd::New(forInEnumeratorOpnd, Js::ForInObjectEnumerator::GetOffsetOfFirstPrototype(), TyMachPtr, this->m_func), this->m_func));
  4206. IR::Instr * checkFirstPrototypeNullInstr = IR::Instr::New(Js::OpCode::TEST, this->m_func);
  4207. checkFirstPrototypeNullInstr->SetSrc1(firstPrototypeOpnd);
  4208. checkFirstPrototypeNullInstr->SetSrc2(firstPrototypeOpnd);
  4209. instr->InsertBefore(checkFirstPrototypeNullInstr);
  4210. instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JNE, labelHelper, this->m_func));
  4211. typedef Js::DynamicObjectSnapshotEnumeratorWPCache<Js::BigPropertyIndex, true, false> SmallDynamicObjectSnapshotEnumeratorWPCache;
  4212. // MOV currentEnumeratorOpnd, forInEnumerator->currentEnumerator
  4213. // CMP currentEnumeratorOpnd, SmallDynamicObjectSnapshotEnumeratorWPCache::`vtable
  4214. // JNE $helper
  4215. IR::RegOpnd * currentEnumeratorOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
  4216. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, currentEnumeratorOpnd,
  4217. IR::IndirOpnd::New(forInEnumeratorOpnd, Js::ForInObjectEnumerator::GetOffsetOfCurrentEnumerator(), TyMachPtr, this->m_func), this->m_func));
  4218. this->m_lowerer->InsertCompareBranch(
  4219. IR::IndirOpnd::New(currentEnumeratorOpnd, 0, TyMachPtr, this->m_func),
  4220. m_lowerer->LoadVTableValueOpnd(instr, VTableValue::VtableSmallDynamicObjectSnapshotEnumeratorWPCache),
  4221. Js::OpCode::BrNeq_A, labelHelper, instr);
  4222. // MOV arrayEnumeratorOpnd, currentEnumerator->arrayEnumerator
  4223. // TEST arrayEnumeratorOpnd, arrayEnumeratorOpnd
  4224. // JNE $helper
  4225. IR::RegOpnd * arrayEnumeratorOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
  4226. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, arrayEnumeratorOpnd,
  4227. IR::IndirOpnd::New(currentEnumeratorOpnd, SmallDynamicObjectSnapshotEnumeratorWPCache::GetOffsetOfArrayEnumerator(), TyMachPtr, this->m_func), this->m_func));
  4228. IR::Instr * checkArrayEnumeratorNullInstr = IR::Instr::New(Js::OpCode::TEST, this->m_func);
  4229. checkArrayEnumeratorNullInstr->SetSrc1(arrayEnumeratorOpnd);
  4230. checkArrayEnumeratorNullInstr->SetSrc2(arrayEnumeratorOpnd);
  4231. instr->InsertBefore(checkArrayEnumeratorNullInstr);
  4232. instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JNE, labelHelper, this->m_func));
  4233. // MOV objectOpnd, currentEnumerator->object
  4234. // MOV initialTypeOpnd, currentEnumerator->initialType
  4235. // CMP initialTypeOpnd, objectOpnd->type
  4236. // JNE $helper
  4237. IR::RegOpnd * objectOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
  4238. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, objectOpnd,
  4239. IR::IndirOpnd::New(currentEnumeratorOpnd, SmallDynamicObjectSnapshotEnumeratorWPCache::GetOffsetOfObject(), TyMachPtr, this->m_func), this->m_func));
  4240. IR::RegOpnd * initialTypeOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
  4241. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, initialTypeOpnd,
  4242. IR::IndirOpnd::New(currentEnumeratorOpnd, SmallDynamicObjectSnapshotEnumeratorWPCache::GetOffsetOfInitialType(), TyMachPtr, this->m_func), this->m_func));
  4243. IR::Instr * checkTypeInstr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  4244. checkTypeInstr->SetSrc1(initialTypeOpnd);
  4245. checkTypeInstr->SetSrc2(IR::IndirOpnd::New(objectOpnd, Js::DynamicObject::GetOffsetOfType(), TyMachPtr, this->m_func));
  4246. instr->InsertBefore(checkTypeInstr);
  4247. instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JNE, labelHelper, this->m_func));
  4248. // MOV enumeratedCountOpnd, currentEnumeratorOpnd->enumeratedCount
  4249. // MOV cachedDataOpnd, currentEnumeratorOpnd->cachedData
  4250. // CMP enumeratedCountOpnd, cachedDataOpnd->cachedCount
  4251. // JGE $helper
  4252. IR::RegOpnd * enumeratedCountOpnd = IR::RegOpnd::New(TyUint32, m_func);
  4253. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, enumeratedCountOpnd,
  4254. IR::IndirOpnd::New(currentEnumeratorOpnd, SmallDynamicObjectSnapshotEnumeratorWPCache::GetOffsetOfEnumeratedCount(), TyUint32, this->m_func), this->m_func));
  4255. IR::RegOpnd * cachedDataOpnd = IR::RegOpnd::New(TyMachPtr, m_func);
  4256. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, cachedDataOpnd,
  4257. IR::IndirOpnd::New(currentEnumeratorOpnd, SmallDynamicObjectSnapshotEnumeratorWPCache::GetOffsetOfCachedData(), TyMachPtr, this->m_func), this->m_func));
  4258. IR::Instr * checkEnumeratedCountInstr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  4259. checkEnumeratedCountInstr->SetSrc1(enumeratedCountOpnd);
  4260. checkEnumeratedCountInstr->SetSrc2(IR::IndirOpnd::New(cachedDataOpnd, SmallDynamicObjectSnapshotEnumeratorWPCache::GetOffsetOfCachedDataCachedCount(), TyUint32, this->m_func));
  4261. instr->InsertBefore(checkEnumeratedCountInstr);
  4262. instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JGE, labelHelper, this->m_func));
  4263. // MOV propertyAttributesOpnd, cachedData->attributes
  4264. // MOV objectPropertyAttributesOpnd, propertyAttributesOpnd[enumeratedCount]
  4265. // CMP objectPropertyAttributesOpnd & PropertyEnumerable, PropertyEnumerable
  4266. // JNE $helper
  4267. IR::RegOpnd * propertyAttributesOpnd = IR::RegOpnd::New(TyMachPtr, m_func);
  4268. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, propertyAttributesOpnd,
  4269. IR::IndirOpnd::New(cachedDataOpnd, SmallDynamicObjectSnapshotEnumeratorWPCache::GetOffsetOfCachedDataPropertyAttributes(), TyMachPtr, this->m_func), this->m_func));
  4270. IR::RegOpnd * objectPropertyAttributesOpnd = IR::RegOpnd::New(TyUint8, m_func);
  4271. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, objectPropertyAttributesOpnd,
  4272. IR::IndirOpnd::New(propertyAttributesOpnd, enumeratedCountOpnd, IndirScale1, TyUint8, this->m_func), this->m_func));
  4273. IR::Instr * andPropertyEnumerableInstr = Lowerer::InsertAnd(IR::RegOpnd::New(TyUint8, instr->m_func), objectPropertyAttributesOpnd, IR::IntConstOpnd::New(0x01, TyUint8, this->m_func), instr);
  4274. IR::Instr * checkEnumerableInstr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  4275. checkEnumerableInstr->SetSrc1(andPropertyEnumerableInstr->GetDst());
  4276. checkEnumerableInstr->SetSrc2(IR::IntConstOpnd::New(0x01, TyUint8, this->m_func));
  4277. instr->InsertBefore(checkEnumerableInstr);
  4278. instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JNE, labelHelper, this->m_func));
  4279. IR::Opnd * opndDst = instr->GetDst(); // ForIn result propertyString
  4280. Assert(opndDst->IsRegOpnd());
  4281. // MOV stringsOpnd, cachedData->strings
  4282. // MOV opndDst, stringsOpnd[enumeratedCount]
  4283. IR::RegOpnd * stringsOpnd = IR::RegOpnd::New(TyMachPtr, m_func);
  4284. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, stringsOpnd,
  4285. IR::IndirOpnd::New(cachedDataOpnd, SmallDynamicObjectSnapshotEnumeratorWPCache::GetOffsetOfCachedDataStrings(), TyMachPtr, this->m_func), this->m_func));
  4286. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, opndDst,
  4287. IR::IndirOpnd::New(stringsOpnd, enumeratedCountOpnd, this->GetDefaultIndirScale(), TyVar, this->m_func), this->m_func));
  4288. // MOV indexesOpnd, cachedData->indexes
  4289. // MOV objectIndexOpnd, indexesOpnd[enumeratedCount]
  4290. // MOV currentEnumeratorOpnd->objectIndex, objectIndexOpnd
  4291. IR::RegOpnd * indexesOpnd = IR::RegOpnd::New(TyMachPtr, m_func);
  4292. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, indexesOpnd,
  4293. IR::IndirOpnd::New(cachedDataOpnd, SmallDynamicObjectSnapshotEnumeratorWPCache::GetOffsetOfCachedDataIndexes(), TyMachPtr, this->m_func), this->m_func));
  4294. IR::RegOpnd * objectIndexOpnd = IR::RegOpnd::New(TyUint32, m_func);
  4295. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, objectIndexOpnd,
  4296. IR::IndirOpnd::New(indexesOpnd, enumeratedCountOpnd, IndirScale4, TyUint32, this->m_func), this->m_func));
  4297. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV,
  4298. IR::IndirOpnd::New(currentEnumeratorOpnd, SmallDynamicObjectSnapshotEnumeratorWPCache::GetOffsetOfObjectIndex(), TyUint32, this->m_func),
  4299. objectIndexOpnd, this->m_func));
  4300. // INC enumeratedCountOpnd
  4301. // MOV currentEnumeratorOpnd->enumeratedCount, enumeratedCountOpnd
  4302. instr->InsertBefore(IR::Instr::New(Js::OpCode::INC, enumeratedCountOpnd, enumeratedCountOpnd, this->m_func));
  4303. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV,
  4304. IR::IndirOpnd::New(currentEnumeratorOpnd, SmallDynamicObjectSnapshotEnumeratorWPCache::GetOffsetOfEnumeratedCount(), TyUint32, this->m_func),
  4305. enumeratedCountOpnd, this->m_func));
  4306. // We know result propertyString (opndDst) != NULL
  4307. IR::LabelInstr * labelAfter = instr->GetOrCreateContinueLabel();
  4308. instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JMP,
  4309. instr->m_opcode == Js::OpCode::BrOnNotEmpty ? instr->AsBranchInstr()->GetTarget() : labelAfter,
  4310. this->m_func));
  4311. // $helper
  4312. instr->InsertBefore(labelHelper);
  4313. // $after
  4314. }
  4315. // Inlines fast-path for int Mul/Add or int Mul/Sub. If not int, call MulAdd/MulSub helper
  4316. bool LowererMD::TryGenerateFastMulAdd(IR::Instr * instrAdd, IR::Instr ** pInstrPrev)
  4317. {
  4318. IR::Instr *instrMul = instrAdd->GetPrevRealInstrOrLabel();
  4319. IR::Opnd *addSrc;
  4320. IR::RegOpnd *addCommonSrcOpnd;
  4321. Assert(instrAdd->m_opcode == Js::OpCode::Add_A || instrAdd->m_opcode == Js::OpCode::Sub_A);
  4322. bool isSub = (instrAdd->m_opcode == Js::OpCode::Sub_A) ? true : false;
  4323. // Mul needs to be a single def reg
  4324. if (instrMul->m_opcode != Js::OpCode::Mul_A || instrMul->GetDst()->IsRegOpnd() == false)
  4325. {
  4326. // Cannot generate MulAdd
  4327. return false;
  4328. }
  4329. if (instrMul->HasBailOutInfo())
  4330. {
  4331. // Bailout will be generated for the Add, but not the Mul.
  4332. // We could handle this, but this path isn't used that much anymore.
  4333. return false;
  4334. }
  4335. IR::RegOpnd *regMulDst = instrMul->GetDst()->AsRegOpnd();
  4336. if (regMulDst->m_sym->m_isSingleDef == false)
  4337. {
  4338. // Cannot generate MulAdd
  4339. return false;
  4340. }
  4341. // Only handle a * b + c, so dst of Mul needs to match left source of Add
  4342. if (instrMul->GetDst()->IsEqual(instrAdd->GetSrc1()))
  4343. {
  4344. addCommonSrcOpnd = instrAdd->GetSrc1()->AsRegOpnd();
  4345. addSrc = instrAdd->GetSrc2();
  4346. }
  4347. else if (instrMul->GetDst()->IsEqual(instrAdd->GetSrc2()))
  4348. {
  4349. addSrc = instrAdd->GetSrc1();
  4350. addCommonSrcOpnd = instrAdd->GetSrc2()->AsRegOpnd();
  4351. }
  4352. else
  4353. {
  4354. return false;
  4355. }
  4356. // Only handle a * b + c where c != a * b
  4357. if (instrAdd->GetSrc1()->IsEqual(instrAdd->GetSrc2()))
  4358. {
  4359. return false;
  4360. }
  4361. if (addCommonSrcOpnd->m_isTempLastUse == false)
  4362. {
  4363. return false;
  4364. }
  4365. IR::Opnd *mulSrc1 = instrMul->GetSrc1();
  4366. IR::Opnd *mulSrc2 = instrMul->GetSrc2();
  4367. if (mulSrc1->IsRegOpnd() && mulSrc1->AsRegOpnd()->IsTaggedInt()
  4368. && mulSrc2->IsRegOpnd() && mulSrc2->AsRegOpnd()->IsTaggedInt())
  4369. {
  4370. return false;
  4371. }
  4372. // Save prevInstr for the main lower loop
  4373. *pInstrPrev = instrMul->m_prev;
  4374. // Generate int31 fast-path for Mul, go to MulAdd helper if it fails, or one of the source is marked notInt
  4375. if (!(addSrc->IsRegOpnd() && addSrc->AsRegOpnd()->IsNotInt())
  4376. && !(mulSrc1->IsRegOpnd() && mulSrc1->AsRegOpnd()->IsNotInt())
  4377. && !(mulSrc2->IsRegOpnd() && mulSrc2->AsRegOpnd()->IsNotInt()))
  4378. {
  4379. this->GenerateFastMul(instrMul);
  4380. IR::LabelInstr *labelHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
  4381. IR::Instr *instr = IR::BranchInstr::New(Js::OpCode::JMP, labelHelper, this->m_func);
  4382. instrMul->InsertBefore(instr);
  4383. // Generate int31 fast-path for Add
  4384. bool success;
  4385. if (isSub)
  4386. {
  4387. success = this->GenerateFastSub(instrAdd);
  4388. }
  4389. else
  4390. {
  4391. success = this->GenerateFastAdd(instrAdd);
  4392. }
  4393. if (!success)
  4394. {
  4395. labelHelper->isOpHelper = false;
  4396. }
  4397. // Generate MulAdd helper call
  4398. instrAdd->InsertBefore(labelHelper);
  4399. }
  4400. if (instrAdd->dstIsTempNumber)
  4401. {
  4402. m_lowerer->LoadHelperTemp(instrAdd, instrAdd);
  4403. }
  4404. else
  4405. {
  4406. IR::Opnd *tempOpnd = IR::IntConstOpnd::New(0, TyInt32, this->m_func);
  4407. this->LoadHelperArgument(instrAdd, tempOpnd);
  4408. }
  4409. this->m_lowerer->LoadScriptContext(instrAdd);
  4410. IR::JnHelperMethod helper;
  4411. if (addSrc == instrAdd->GetSrc2())
  4412. {
  4413. instrAdd->FreeSrc1();
  4414. IR::Opnd *addOpnd = instrAdd->UnlinkSrc2();
  4415. this->LoadHelperArgument(instrAdd, addOpnd);
  4416. helper = isSub ? IR::HelperOp_MulSubRight : IR::HelperOp_MulAddRight;
  4417. }
  4418. else
  4419. {
  4420. instrAdd->FreeSrc2();
  4421. IR::Opnd *addOpnd = instrAdd->UnlinkSrc1();
  4422. this->LoadHelperArgument(instrAdd, addOpnd);
  4423. helper = isSub ? IR::HelperOp_MulSubLeft : IR::HelperOp_MulAddLeft;
  4424. }
  4425. IR::Opnd *src2 = instrMul->UnlinkSrc2();
  4426. this->LoadHelperArgument(instrAdd, src2);
  4427. IR::Opnd *src1 = instrMul->UnlinkSrc1();
  4428. this->LoadHelperArgument(instrAdd, src1);
  4429. this->ChangeToHelperCall(instrAdd, helper);
  4430. instrMul->Remove();
  4431. return true;
  4432. }
  4433. void
  4434. LowererMD::GenerateFastAbs(IR::Opnd *dst, IR::Opnd *src, IR::Instr *callInstr, IR::Instr *insertInstr, IR::LabelInstr *labelHelper, IR::LabelInstr *doneLabel)
  4435. {
  4436. // TEST src1, AtomTag
  4437. // JEQ $float
  4438. // MOV EAX, src
  4439. // SAR EAX, AtomTag_Int32
  4440. // CDQ
  4441. // XOR EAX, EDX
  4442. // SUB EAX, EDX
  4443. // SHL EAX, AtomTag_Int32
  4444. // JO $labelHelper
  4445. // INC EAX
  4446. // MOV dst, EAX
  4447. // JMP $done
  4448. // $float
  4449. // CMP [src], JavascriptNumber.vtable
  4450. // JNE $helper
  4451. // MOVSD r1, [src + offsetof(value)]
  4452. // ANDPD r1, absDoubleCst
  4453. // dst = DoubleToVar(r1)
  4454. IR::Instr *instr = nullptr;
  4455. IR::LabelInstr *labelFloat = nullptr;
  4456. bool isInt = false;
  4457. bool isNotInt = false;
  4458. if (src->IsRegOpnd())
  4459. {
  4460. if (src->AsRegOpnd()->IsTaggedInt())
  4461. {
  4462. isInt = true;
  4463. }
  4464. else if (src->AsRegOpnd()->IsNotInt())
  4465. {
  4466. isNotInt = true;
  4467. }
  4468. }
  4469. else if (src->IsAddrOpnd())
  4470. {
  4471. IR::AddrOpnd *varOpnd = src->AsAddrOpnd();
  4472. Assert(varOpnd->IsVar() && Js::TaggedInt::Is(varOpnd->m_address));
  4473. #ifdef _M_X64
  4474. __int64 absValue = ::_abs64(Js::TaggedInt::ToInt32(varOpnd->m_address));
  4475. #else
  4476. __int32 absValue = ::abs(Js::TaggedInt::ToInt32(varOpnd->m_address));
  4477. #endif
  4478. if (!Js::TaggedInt::IsOverflow(absValue))
  4479. {
  4480. varOpnd->SetAddress(Js::TaggedInt::ToVarUnchecked((__int32)absValue), IR::AddrOpndKindConstantVar);
  4481. instr = IR::Instr::New(Js::OpCode::MOV, dst, varOpnd, this->m_func);
  4482. insertInstr->InsertBefore(instr);
  4483. return;
  4484. }
  4485. }
  4486. if (src->IsRegOpnd() == false)
  4487. {
  4488. IR::RegOpnd *regOpnd = IR::RegOpnd::New(TyVar, this->m_func);
  4489. instr = IR::Instr::New(Js::OpCode::MOV, regOpnd, src, this->m_func);
  4490. insertInstr->InsertBefore(instr);
  4491. src = regOpnd;
  4492. }
  4493. #ifdef _M_IX86
  4494. bool emitFloatAbs = !isInt && AutoSystemInfo::Data.SSE2Available();
  4495. #else
  4496. bool emitFloatAbs = !isInt;
  4497. #endif
  4498. if (!isNotInt)
  4499. {
  4500. if (!isInt)
  4501. {
  4502. IR::LabelInstr *label = labelHelper;
  4503. if (emitFloatAbs)
  4504. {
  4505. label = labelFloat = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  4506. }
  4507. GenerateSmIntTest(src, insertInstr, label);
  4508. }
  4509. // MOV EAX, src
  4510. IR::RegOpnd *regEAX = IR::RegOpnd::New(TyInt32, this->m_func);
  4511. regEAX->SetReg(LowererMDArch::GetRegIMulDestLower());
  4512. instr = IR::Instr::New(Js::OpCode::MOV, regEAX, src, this->m_func);
  4513. insertInstr->InsertBefore(instr);
  4514. #ifdef _M_IX86
  4515. // SAR EAX, AtomTag_Int32
  4516. instr = IR::Instr::New(Js::OpCode::SAR, regEAX, regEAX, IR::IntConstOpnd::New(Js::AtomTag_Int32, TyInt32, this->m_func), this->m_func);
  4517. insertInstr->InsertBefore(instr);
  4518. #endif
  4519. IR::RegOpnd *regEDX = IR::RegOpnd::New(TyInt32, this->m_func);
  4520. regEDX->SetReg(LowererMDArch::GetRegIMulHighDestLower());
  4521. // CDQ
  4522. // Note: put EDX on dst to give of def to the EDX lifetime
  4523. instr = IR::Instr::New(Js::OpCode::CDQ, regEDX, this->m_func);
  4524. insertInstr->InsertBefore(instr);
  4525. // XOR EAX, EDX
  4526. instr = IR::Instr::New(Js::OpCode::XOR, regEAX, regEAX, regEDX, this->m_func);
  4527. insertInstr->InsertBefore(instr);
  4528. // SUB EAX, EDX
  4529. instr = IR::Instr::New(Js::OpCode::SUB, regEAX, regEAX, regEDX, this->m_func);
  4530. insertInstr->InsertBefore(instr);
  4531. #ifdef _M_X64
  4532. // abs(INT_MIN) overflows a 32 bit integer.
  4533. // JO $labelHelper
  4534. instr = IR::BranchInstr::New(Js::OpCode::JO, labelHelper, this->m_func);
  4535. insertInstr->InsertBefore(instr);
  4536. #endif
  4537. #ifdef _M_IX86
  4538. // SHL EAX, AtomTag_Int32
  4539. instr = IR::Instr::New(Js::OpCode::SHL, regEAX, regEAX, IR::IntConstOpnd::New(Js::AtomTag_Int32, TyInt32, this->m_func), this->m_func);
  4540. insertInstr->InsertBefore(instr);
  4541. // JO $labelHelper
  4542. instr = IR::BranchInstr::New(Js::OpCode::JO, labelHelper, this->m_func);
  4543. insertInstr->InsertBefore(instr);
  4544. // INC EAX
  4545. instr = IR::Instr::New(Js::OpCode::INC, regEAX, regEAX, this->m_func);
  4546. insertInstr->InsertBefore(instr);
  4547. #endif
  4548. // MOV dst, EAX
  4549. instr = IR::Instr::New(Js::OpCode::MOV, dst, regEAX, this->m_func);
  4550. insertInstr->InsertBefore(instr);
  4551. #ifdef _M_X64
  4552. GenerateInt32ToVarConversion(dst, insertInstr);
  4553. #endif
  4554. }
  4555. if (labelFloat)
  4556. {
  4557. // JMP $done
  4558. instr = IR::BranchInstr::New(Js::OpCode::JMP, doneLabel, this->m_func);
  4559. insertInstr->InsertBefore(instr);
  4560. // $float
  4561. insertInstr->InsertBefore(labelFloat);
  4562. }
  4563. if (emitFloatAbs)
  4564. {
  4565. #if defined(_M_IX86)
  4566. // CMP [src], JavascriptNumber.vtable
  4567. IR::Opnd *opnd = IR::IndirOpnd::New(src->AsRegOpnd(), (int32)0, TyMachPtr, this->m_func);
  4568. instr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  4569. instr->SetSrc1(opnd);
  4570. instr->SetSrc2(m_lowerer->LoadVTableValueOpnd(insertInstr, VTableValue::VtableJavascriptNumber));
  4571. insertInstr->InsertBefore(instr);
  4572. // JNE $helper
  4573. instr = IR::BranchInstr::New(Js::OpCode::JNE, labelHelper, this->m_func);
  4574. insertInstr->InsertBefore(instr);
  4575. // MOVSD r1, [src + offsetof(value)]
  4576. opnd = IR::IndirOpnd::New(src->AsRegOpnd(), Js::JavascriptNumber::GetValueOffset(), TyMachDouble, this->m_func);
  4577. IR::RegOpnd *regOpnd = IR::RegOpnd::New(TyMachDouble, this->m_func);
  4578. instr = IR::Instr::New(Js::OpCode::MOVSD, regOpnd, opnd, this->m_func);
  4579. insertInstr->InsertBefore(instr);
  4580. this->GenerateFloatAbs(regOpnd, insertInstr);
  4581. // dst = DoubleToVar(r1)
  4582. SaveDoubleToVar(callInstr->GetDst()->AsRegOpnd(), regOpnd, callInstr, insertInstr);
  4583. #elif defined(_M_X64)
  4584. // if (typeof(src) == double)
  4585. IR::RegOpnd *src64 = src->AsRegOpnd();
  4586. GenerateFloatTest(src64, insertInstr, labelHelper);
  4587. // dst64 = MOV src64
  4588. insertInstr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, dst, src64, this->m_func));
  4589. // Unconditionally set the sign bit. This will get XORd away when we remove the tag.
  4590. // dst64 = OR 0x8000000000000000
  4591. insertInstr->InsertBefore(IR::Instr::New(Js::OpCode::OR, dst, dst, IR::AddrOpnd::New((void *)MachSignBit, IR::AddrOpndKindConstant, this->m_func), this->m_func));
  4592. #endif
  4593. }
  4594. else if(!isInt)
  4595. {
  4596. // The source is not known to be a tagged int, so either it's definitely not an int (isNotInt), or the int version of
  4597. // abs failed the tag check and jumped here. We can't emit the float version of abs (!emitFloatAbs) due to SSE2 not
  4598. // being available, so jump straight to the helper.
  4599. // JMP $helper
  4600. instr = IR::BranchInstr::New(Js::OpCode::JMP, labelHelper, this->m_func);
  4601. insertInstr->InsertBefore(instr);
  4602. }
  4603. }
  4604. IR::Instr * LowererMD::GenerateFloatAbs(IR::RegOpnd * regOpnd, IR::Instr * insertInstr)
  4605. {
  4606. // ANDPS reg, absDoubleCst
  4607. IR::Opnd * opnd;
  4608. if (regOpnd->IsFloat64())
  4609. {
  4610. opnd = m_lowerer->LoadLibraryValueOpnd(insertInstr, LibraryValue::ValueAbsDoubleCst);
  4611. }
  4612. else
  4613. {
  4614. Assert(regOpnd->IsFloat32());
  4615. opnd = IR::MemRefOpnd::New((void *)&Js::JavascriptNumber::AbsFloatCst, TyFloat32, this->m_func, IR::AddrOpndKindDynamicFloatRef);
  4616. }
  4617. // ANDPS has smaller encoding then ANDPD
  4618. IR::Instr * instr = IR::Instr::New(Js::OpCode::ANDPS, regOpnd, regOpnd, opnd, this->m_func);
  4619. insertInstr->InsertBefore(instr);
  4620. Legalize(instr);
  4621. return instr;
  4622. }
  4623. bool LowererMD::GenerateFastCharAt(Js::BuiltinFunction index, IR::Opnd *dst, IR::Opnd *srcStr, IR::Opnd *srcIndex, IR::Instr *callInstr,
  4624. IR::Instr *insertInstr, IR::LabelInstr *labelHelper, IR::LabelInstr *doneLabel)
  4625. {
  4626. // if regSrcStr is not object, JMP $helper
  4627. // CMP [regSrcStr + offset(type)] , static string type -- check base string type
  4628. // JNE $helper
  4629. // MOV r1, [regSrcStr + offset(m_pszValue)]
  4630. // TEST r1, r1
  4631. // JEQ $helper
  4632. // MOV r2, srcIndex
  4633. // If r2 is not int, JMP $helper
  4634. // Convert r2 to int
  4635. // CMP [regSrcStr + offsetof(length)], r2
  4636. // JBE $helper
  4637. // MOVZX r2, [r1 + r2 * 2]
  4638. // if (charAt)
  4639. // PUSH r1
  4640. // PUSH scriptContext
  4641. // CALL GetStringFromChar
  4642. // MOV dst, EAX
  4643. // else (charCodeAt)
  4644. // if (codePointAt)
  4645. // Lowerer.GenerateFastCodePointAt -- Common inline functions
  4646. // Convert r2 to Var
  4647. // MOV dst, r2
  4648. bool isInt = false;
  4649. bool isNotTaggedValue = false;
  4650. IR::Instr *instr;
  4651. IR::RegOpnd *regSrcStr;
  4652. if (srcStr->IsRegOpnd())
  4653. {
  4654. if (srcStr->AsRegOpnd()->IsTaggedInt())
  4655. {
  4656. isInt = true;
  4657. }
  4658. else if (srcStr->AsRegOpnd()->IsNotTaggedValue())
  4659. {
  4660. isNotTaggedValue = true;
  4661. }
  4662. }
  4663. if (srcStr->IsRegOpnd() == false)
  4664. {
  4665. IR::RegOpnd *regOpnd = IR::RegOpnd::New(TyVar, this->m_func);
  4666. instr = IR::Instr::New(Js::OpCode::MOV, regOpnd, srcStr, this->m_func);
  4667. insertInstr->InsertBefore(instr);
  4668. regSrcStr = regOpnd;
  4669. }
  4670. else
  4671. {
  4672. regSrcStr = srcStr->AsRegOpnd();
  4673. }
  4674. if (!isNotTaggedValue)
  4675. {
  4676. if (!isInt)
  4677. {
  4678. GenerateObjectTest(regSrcStr, insertInstr, labelHelper);
  4679. }
  4680. else
  4681. {
  4682. // Insert delete branch opcode to tell the dbChecks not to assert on this helper label
  4683. IR::Instr *fakeBr = IR::PragmaInstr::New(Js::OpCode::DeletedNonHelperBranch, 0, this->m_func);
  4684. insertInstr->InsertBefore(fakeBr);
  4685. instr = IR::BranchInstr::New(Js::OpCode::JMP, labelHelper, this->m_func);
  4686. insertInstr->InsertBefore(instr);
  4687. }
  4688. }
  4689. // Bail out if index a constant and is less than zero.
  4690. if (srcIndex->IsAddrOpnd() && Js::TaggedInt::ToInt32(srcIndex->AsAddrOpnd()->m_address) < 0)
  4691. {
  4692. labelHelper->isOpHelper = false;
  4693. instr = IR::BranchInstr::New(Js::OpCode::JMP, labelHelper, this->m_func);
  4694. insertInstr->InsertBefore(instr);
  4695. return false;
  4696. }
  4697. this->m_lowerer->GenerateStringTest(regSrcStr, insertInstr, labelHelper, nullptr, false);
  4698. // r1 contains the value of the wchar_t* pointer inside JavascriptString.
  4699. // MOV r1, [regSrcStr + offset(m_pszValue)]
  4700. IR::RegOpnd *r1 = IR::RegOpnd::New(TyMachReg, this->m_func);
  4701. IR::IndirOpnd * indirOpnd = IR::IndirOpnd::New(regSrcStr->AsRegOpnd(), Js::JavascriptString::GetOffsetOfpszValue(), TyMachPtr, this->m_func);
  4702. instr = IR::Instr::New(Js::OpCode::MOV, r1, indirOpnd, this->m_func);
  4703. insertInstr->InsertBefore(instr);
  4704. // TEST r1, r1 -- Null pointer test
  4705. instr = IR::Instr::New(Js::OpCode::TEST, this->m_func);
  4706. instr->SetSrc1(r1);
  4707. instr->SetSrc2(r1);
  4708. insertInstr->InsertBefore(instr);
  4709. // JEQ $helper
  4710. instr = IR::BranchInstr::New(Js::OpCode::JEQ, labelHelper, this->m_func);
  4711. insertInstr->InsertBefore(instr);
  4712. IR::IndirOpnd *strLength = IR::IndirOpnd::New(regSrcStr, offsetof(Js::JavascriptString, m_charLength), TyUint32, this->m_func);
  4713. if (srcIndex->IsAddrOpnd())
  4714. {
  4715. // CMP [regSrcStr + offsetof(length)], index
  4716. instr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  4717. instr->SetSrc1(strLength);
  4718. instr->SetSrc2(IR::IntConstOpnd::New(Js::TaggedInt::ToUInt32(srcIndex->AsAddrOpnd()->m_address), TyUint32, this->m_func));
  4719. insertInstr->InsertBefore(instr);
  4720. // Use unsigned compare, this should handle negative indexes as well (they become > INT_MAX)
  4721. // JBE $helper
  4722. instr = IR::BranchInstr::New(Js::OpCode::JBE, labelHelper, this->m_func);
  4723. insertInstr->InsertBefore(instr);
  4724. indirOpnd = IR::IndirOpnd::New(r1, Js::TaggedInt::ToUInt32(srcIndex->AsAddrOpnd()->m_address) * sizeof(wchar_t), TyInt16, this->m_func);
  4725. }
  4726. else
  4727. {
  4728. IR::RegOpnd *r2 = IR::RegOpnd::New(TyVar, this->m_func);
  4729. // MOV r2, srcIndex
  4730. instr = IR::Instr::New(Js::OpCode::MOV, r2, srcIndex, this->m_func);
  4731. insertInstr->InsertBefore(instr);
  4732. if (!srcIndex->IsRegOpnd() || !srcIndex->AsRegOpnd()->IsTaggedInt())
  4733. {
  4734. GenerateSmIntTest(r2, insertInstr, labelHelper);
  4735. }
  4736. #if INT32VAR
  4737. // Remove the tag
  4738. // MOV r2, [32-bit] r2
  4739. IR::Opnd * r2_32 = r2->UseWithNewType(TyInt32, this->m_func);
  4740. instr = IR::Instr::New(Js::OpCode::MOVSXD, r2, r2_32, this->m_func);
  4741. insertInstr->InsertBefore(instr);
  4742. r2 = r2_32->AsRegOpnd();
  4743. #else
  4744. // r2 = SAR r2, VarTag_Shift
  4745. instr = IR::Instr::New(Js::OpCode::SAR, r2, r2, IR::IntConstOpnd::New(Js::VarTag_Shift, TyInt8, this->m_func), this->m_func);
  4746. insertInstr->InsertBefore(instr);
  4747. #endif
  4748. // CMP [regSrcStr + offsetof(length)], r2
  4749. instr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  4750. instr->SetSrc1(strLength);
  4751. instr->SetSrc2(r2);
  4752. insertInstr->InsertBefore(instr);
  4753. if (r2->GetSize() != MachPtr)
  4754. {
  4755. r2 = r2->UseWithNewType(TyMachPtr, this->m_func)->AsRegOpnd();
  4756. }
  4757. // Use unsigned compare, this should handle negative indexes as well (they become > INT_MAX)
  4758. // JBE $helper
  4759. instr = IR::BranchInstr::New(Js::OpCode::JBE, labelHelper, this->m_func);
  4760. insertInstr->InsertBefore(instr);
  4761. indirOpnd = IR::IndirOpnd::New(r1, r2, 1, TyInt16, this->m_func);
  4762. }
  4763. // MOVZX charReg, [r1 + r2 * 2] -- this is the value of the char
  4764. IR::RegOpnd *charReg = IR::RegOpnd::New(TyMachReg, this->m_func);
  4765. instr = IR::Instr::New(Js::OpCode::MOVZXW, charReg, indirOpnd, this->m_func);
  4766. insertInstr->InsertBefore(instr);
  4767. if (index == Js::BuiltinFunction::String_CharAt)
  4768. {
  4769. this->m_lowerer->GenerateGetSingleCharString(charReg, dst, labelHelper, doneLabel, insertInstr, false);
  4770. }
  4771. else
  4772. {
  4773. Assert(index == Js::BuiltinFunction::String_CharCodeAt || index == Js::BuiltinFunction::String_CodePointAt);
  4774. if (index == Js::BuiltinFunction::String_CodePointAt)
  4775. {
  4776. this->m_lowerer->GenerateFastInlineStringCodePointAt(insertInstr, this->m_func, strLength, srcIndex, charReg, r1);
  4777. }
  4778. GenerateInt32ToVarConversion(charReg, insertInstr);
  4779. // MOV dst, charReg
  4780. instr = IR::Instr::New(Js::OpCode::MOV, dst, charReg, this->m_func);
  4781. insertInstr->InsertBefore(instr);
  4782. }
  4783. return true;
  4784. }
  4785. void
  4786. LowererMD::GenerateClz(IR::Instr * instr)
  4787. {
  4788. Assert(instr->GetSrc1()->IsInt32() || instr->GetSrc1()->IsUInt32());
  4789. Assert(IRType_IsNativeInt(instr->GetDst()->GetType()));
  4790. if (AutoSystemInfo::Data.LZCntAvailable())
  4791. {
  4792. instr->m_opcode = Js::OpCode::LZCNT;
  4793. Legalize(instr);
  4794. }
  4795. else
  4796. {
  4797. // tmp = BSR src
  4798. // JE $label32
  4799. // dst = SUB 31, tmp
  4800. // JMP $done
  4801. // label32:
  4802. // dst = mov 32;
  4803. // $done
  4804. IR::LabelInstr * doneLabel = Lowerer::InsertLabel(false, instr->m_next);
  4805. IR::Opnd * dst = instr->UnlinkDst();
  4806. IR::Opnd * tmpOpnd = IR::RegOpnd::New(TyInt8, m_func);
  4807. instr->SetDst(tmpOpnd);
  4808. instr->m_opcode = Js::OpCode::BSR;
  4809. Legalize(instr);
  4810. IR::LabelInstr * label32 = Lowerer::InsertLabel(false, doneLabel);
  4811. instr = IR::BranchInstr::New(Js::OpCode::JEQ, label32, m_func);
  4812. label32->InsertBefore(instr);
  4813. Lowerer::InsertSub(false, dst, IR::IntConstOpnd::New(31, TyInt8, m_func), tmpOpnd, label32);
  4814. Lowerer::InsertBranch(Js::OpCode::Br, doneLabel, label32);
  4815. Lowerer::InsertMove(dst, IR::IntConstOpnd::New(32, TyInt8, m_func), doneLabel);
  4816. }
  4817. }
  4818. #if !FLOATVAR
  4819. void
  4820. LowererMD::GenerateNumberAllocation(IR::RegOpnd * opndDst, IR::Instr * instrInsert, bool isHelper)
  4821. {
  4822. Js::RecyclerJavascriptNumberAllocator * allocator = this->m_lowerer->GetScriptContext()->GetNumberAllocator();
  4823. IR::Opnd * endAddressOpnd = m_lowerer->LoadNumberAllocatorValueOpnd(instrInsert, NumberAllocatorValue::NumberAllocatorEndAddress);
  4824. IR::Opnd * freeObjectListOpnd = m_lowerer->LoadNumberAllocatorValueOpnd(instrInsert, NumberAllocatorValue::NumberAllocatorFreeObjectList);
  4825. // MOV dst, allocator->freeObjectList
  4826. IR::Instr * loadMemBlockInstr = IR::Instr::New(Js::OpCode::MOV, opndDst, freeObjectListOpnd, this->m_func);
  4827. instrInsert->InsertBefore(loadMemBlockInstr);
  4828. // LEA nextMemBlock, [dst + allocSize]
  4829. IR::RegOpnd * nextMemBlockOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
  4830. IR::Instr * loadNextMemBlockInstr = IR::Instr::New(Js::OpCode::LEA, nextMemBlockOpnd,
  4831. IR::IndirOpnd::New(opndDst, allocator->GetAlignedAllocSize(), TyMachPtr, this->m_func), this->m_func);
  4832. instrInsert->InsertBefore(loadNextMemBlockInstr);
  4833. // CMP nextMemBlock, allocator->endAddress
  4834. IR::Instr * checkInstr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  4835. checkInstr->SetSrc1(nextMemBlockOpnd);
  4836. checkInstr->SetSrc2(endAddressOpnd);
  4837. instrInsert->InsertBefore(checkInstr);
  4838. // JA $helper
  4839. IR::LabelInstr * helperLabel = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
  4840. IR::BranchInstr * branchInstr = IR::BranchInstr::New(Js::OpCode::JA, helperLabel, this->m_func);
  4841. instrInsert->InsertBefore(branchInstr);
  4842. // MOV allocator->freeObjectList, nextMemBlock
  4843. IR::Instr * setFreeObjectListInstr = IR::Instr::New(Js::OpCode::MOV, freeObjectListOpnd, nextMemBlockOpnd, this->m_func);
  4844. instrInsert->InsertBefore(setFreeObjectListInstr);
  4845. // JMP $done
  4846. IR::LabelInstr * doneLabel = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, isHelper);
  4847. IR::BranchInstr * branchToDoneInstr = IR::BranchInstr::New(Js::OpCode::JMP, doneLabel, this->m_func);
  4848. instrInsert->InsertBefore(branchToDoneInstr);
  4849. // $helper:
  4850. instrInsert->InsertBefore(helperLabel);
  4851. // PUSH allocator
  4852. this->LoadHelperArgument(instrInsert, m_lowerer->LoadScriptContextValueOpnd(instrInsert, ScriptContextValue::ScriptContextNumberAllocator));
  4853. // dst = Call AllocUninitalizedNumber
  4854. IR::Instr * instrCall = IR::Instr::New(Js::OpCode::CALL, opndDst,
  4855. IR::HelperCallOpnd::New(IR::HelperAllocUninitializedNumber, this->m_func), this->m_func);
  4856. instrInsert->InsertBefore(instrCall);
  4857. this->lowererMDArch.LowerCall(instrCall, 0);
  4858. // $done:
  4859. instrInsert->InsertBefore(doneLabel);
  4860. }
  4861. #endif
  4862. #ifdef _CONTROL_FLOW_GUARD
  4863. void
  4864. LowererMD::GenerateCFGCheck(IR::Opnd * entryPointOpnd, IR::Instr * insertBeforeInstr)
  4865. {
  4866. //PreReserve segment at this point, as we will definitely using this segment for JITted code(in almost all cases)
  4867. //This is for CFG check optimization
  4868. IR::LabelInstr * callLabelInstr = nullptr;
  4869. char * preReservedRegionStartAddress = nullptr;
  4870. if (m_func->CanAllocInPreReservedHeapPageSegment())
  4871. {
  4872. PreReservedVirtualAllocWrapper * preReservedVirtualAllocator = m_func->GetScriptContext()->GetThreadContext()->GetPreReservedVirtualAllocator();
  4873. preReservedRegionStartAddress = m_func->GetEmitBufferManager()->EnsurePreReservedPageAllocation(preReservedVirtualAllocator);
  4874. if (preReservedRegionStartAddress != nullptr)
  4875. {
  4876. Assert(preReservedVirtualAllocator);
  4877. char* endAddressOfSegment = (char*)preReservedVirtualAllocator->GetPreReservedEndAddress();
  4878. int32 segmentSize = (int32) (endAddressOfSegment - preReservedRegionStartAddress);
  4879. // Generate instructions for local Pre-Reserved Segment Range check
  4880. IR::AddrOpnd * endAddressOfSegmentConstOpnd = IR::AddrOpnd::New(endAddressOfSegment, IR::AddrOpndKindDynamicMisc, m_func);
  4881. IR::RegOpnd *resultOpnd = IR::RegOpnd::New(TyMachReg, this->m_func);
  4882. #if _M_IX86
  4883. //resultOpnd = endAddressOfSegmentConstOpnd - entryPointOpnd
  4884. IR::Instr* subInstr = IR::Instr::New(Js::OpCode::Sub_I4, resultOpnd, endAddressOfSegmentConstOpnd, entryPointOpnd, m_func);
  4885. insertBeforeInstr->InsertBefore(subInstr);
  4886. this->EmitInt4Instr(subInstr);
  4887. #elif _M_X64
  4888. //MOV resultOpnd, endAddressOfSegment
  4889. //resultOpnd = resultOpnd - entryPointOpnd
  4890. IR::Instr *movInstr = IR::Instr::New(Js::OpCode::MOV, resultOpnd, endAddressOfSegmentConstOpnd, this->m_func);
  4891. insertBeforeInstr->InsertBefore(movInstr);
  4892. IR::Instr* subInstr = IR::Instr::New(Js::OpCode::SUB, resultOpnd, resultOpnd, entryPointOpnd, m_func);
  4893. insertBeforeInstr->InsertBefore(subInstr);
  4894. #endif
  4895. //CMP subResultOpnd, segmentSize
  4896. //JL $callLabelInstr:
  4897. AssertMsg((size_t) segmentSize == (size_t) (endAddressOfSegment - preReservedRegionStartAddress), "Need a bigger datatype for segmentSize?");
  4898. IR::IntConstOpnd * segmentSizeOpnd = IR::IntConstOpnd::New(segmentSize, IRType::TyInt32, m_func, true);
  4899. callLabelInstr = IR::LabelInstr::New(Js::OpCode::Label, m_func);
  4900. this->m_lowerer->InsertCompareBranch(resultOpnd, segmentSizeOpnd, Js::OpCode::JBE, callLabelInstr, insertBeforeInstr);
  4901. }
  4902. }
  4903. //MOV ecx, entryPoint
  4904. IR::RegOpnd * entryPointRegOpnd = IR::RegOpnd::New(TyMachReg, this->m_func);
  4905. #if _M_IX86
  4906. entryPointRegOpnd->SetReg(RegECX);
  4907. #elif _M_X64
  4908. entryPointRegOpnd->SetReg(RegRCX);
  4909. #endif
  4910. entryPointRegOpnd->m_isCallArg = true;
  4911. IR::Instr* movInstrEntryPointToRegister = IR::Instr::New(Js::OpCode::MOV, entryPointRegOpnd, entryPointOpnd, this->m_func);
  4912. insertBeforeInstr->InsertBefore(movInstrEntryPointToRegister);
  4913. //Generate CheckCFG CALL here
  4914. IR::HelperCallOpnd *cfgCallOpnd = IR::HelperCallOpnd::New(IR::HelperGuardCheckCall, this->m_func);
  4915. IR::Instr* cfgCallInstr = IR::Instr::New(Js::OpCode::CALL, this->m_func);
  4916. #if _M_IX86
  4917. //call[__guard_check_icall_fptr]
  4918. cfgCallInstr->SetSrc1(cfgCallOpnd);
  4919. #elif _M_X64
  4920. //mov rax, __guard_check_icall_fptr
  4921. IR::RegOpnd *targetOpnd = IR::RegOpnd::New(StackSym::New(TyMachPtr, m_func), RegRAX, TyMachPtr, this->m_func);
  4922. IR::Instr *movInstr = IR::Instr::New(Js::OpCode::MOV, targetOpnd, cfgCallOpnd, this->m_func);
  4923. insertBeforeInstr->InsertBefore(movInstr);
  4924. //call rax
  4925. cfgCallInstr->SetSrc1(targetOpnd);
  4926. #endif
  4927. //CALL cfg(rax)
  4928. insertBeforeInstr->InsertBefore(cfgCallInstr);
  4929. if (preReservedRegionStartAddress != nullptr)
  4930. {
  4931. Assert(callLabelInstr);
  4932. #if DBG
  4933. //Always generate CFG check in DBG build to make sure that the address is still valid
  4934. movInstrEntryPointToRegister->InsertBefore(callLabelInstr);
  4935. #else
  4936. insertBeforeInstr->InsertBefore(callLabelInstr);
  4937. #endif
  4938. }
  4939. }
  4940. #endif
  4941. void
  4942. LowererMD::GenerateFastRecyclerAlloc(size_t allocSize, IR::RegOpnd* newObjDst, IR::Instr* insertionPointInstr, IR::LabelInstr* allocHelperLabel, IR::LabelInstr* allocDoneLabel)
  4943. {
  4944. IR::Opnd * endAddressOpnd;
  4945. IR::Opnd * freeListOpnd;
  4946. Js::ScriptContext* scriptContext = this->m_func->GetScriptContext();
  4947. Recycler* recycler = scriptContext->GetRecycler();
  4948. void* allocatorAddress;
  4949. uint32 endAddressOffset;
  4950. uint32 freeListOffset;
  4951. size_t alignedSize = HeapInfo::GetAlignedSizeNoCheck(allocSize);
  4952. recycler->GetNormalHeapBlockAllocatorInfoForNativeAllocation(alignedSize, allocatorAddress, endAddressOffset, freeListOffset);
  4953. endAddressOpnd = IR::MemRefOpnd::New((char*)allocatorAddress + endAddressOffset, TyMachPtr, this->m_func, IR::AddrOpndKindDynamicRecyclerAllocatorEndAddressRef);
  4954. freeListOpnd = IR::MemRefOpnd::New((char*)allocatorAddress + freeListOffset, TyMachPtr, this->m_func, IR::AddrOpndKindDynamicRecyclerAllocatorFreeListRef);
  4955. const IR::AutoReuseOpnd autoReuseTempOpnd(freeListOpnd, m_func);
  4956. // MOV newObjDst, allocator->freeObjectList
  4957. Lowerer::InsertMove(newObjDst, freeListOpnd, insertionPointInstr);
  4958. // LEA nextMemBlock, [newObjDst + allocSize]
  4959. IR::RegOpnd * nextMemBlockOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
  4960. IR::IndirOpnd* nextMemBlockSrc = IR::IndirOpnd::New(newObjDst, (int32)alignedSize, TyMachPtr, this->m_func);
  4961. IR::Instr * loadNextMemBlockInstr = IR::Instr::New(Js::OpCode::LEA, nextMemBlockOpnd, nextMemBlockSrc, this->m_func);
  4962. insertionPointInstr->InsertBefore(loadNextMemBlockInstr);
  4963. // CMP nextMemBlock, allocator->endAddress
  4964. IR::Instr * checkInstr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  4965. checkInstr->SetSrc1(nextMemBlockOpnd);
  4966. checkInstr->SetSrc2(endAddressOpnd);
  4967. insertionPointInstr->InsertBefore(checkInstr);
  4968. Legalize(checkInstr);
  4969. // JA $allocHelper
  4970. IR::BranchInstr * branchToAllocHelperInstr = IR::BranchInstr::New(Js::OpCode::JA, allocHelperLabel, this->m_func);
  4971. insertionPointInstr->InsertBefore(branchToAllocHelperInstr);
  4972. // MOV allocator->freeObjectList, nextMemBlock
  4973. Lowerer::InsertMove(freeListOpnd, nextMemBlockOpnd, insertionPointInstr);
  4974. // JMP $allocDone
  4975. IR::BranchInstr * branchToAllocDoneInstr = IR::BranchInstr::New(Js::OpCode::JMP, allocDoneLabel, this->m_func);
  4976. insertionPointInstr->InsertBefore(branchToAllocDoneInstr);
  4977. }
  4978. void
  4979. LowererMD::SaveDoubleToVar(IR::RegOpnd * dstOpnd, IR::RegOpnd *opndFloat, IR::Instr *instrOrig, IR::Instr *instrInsert, bool isHelper)
  4980. {
  4981. Assert(opndFloat->GetType() == TyFloat64);
  4982. // Call JSNumber::ToVar to save the float operand to the result of the original (var) instruction
  4983. #if !FLOATVAR
  4984. // We should only generate this if sse2 is available
  4985. Assert(AutoSystemInfo::Data.SSE2Available());
  4986. IR::Opnd * symVTableDst;
  4987. IR::Opnd * symDblDst;
  4988. IR::Opnd * symTypeDst;
  4989. IR::Instr * newInstr;
  4990. IR::Instr * numberInitInsertInstr = nullptr;
  4991. if (instrOrig->dstIsTempNumber)
  4992. {
  4993. // Use the original dst to get the temp number sym
  4994. StackSym * tempNumberSym = this->m_lowerer->GetTempNumberSym(instrOrig->GetDst(), instrOrig->dstIsTempNumberTransferred);
  4995. // LEA dst, &tempSym
  4996. IR::SymOpnd * symTempSrc = IR::SymOpnd::New(tempNumberSym, TyMachPtr, this->m_func);
  4997. IR::Instr * loadTempNumberInstr = IR::Instr::New(Js::OpCode::LEA, dstOpnd, symTempSrc, this->m_func);
  4998. instrInsert->InsertBefore(loadTempNumberInstr);
  4999. symVTableDst = IR::SymOpnd::New(tempNumberSym, TyMachPtr, this->m_func);
  5000. symDblDst = IR::SymOpnd::New(tempNumberSym, (uint32)Js::JavascriptNumber::GetValueOffset(), TyFloat64, this->m_func);
  5001. symTypeDst = IR::SymOpnd::New(tempNumberSym, (uint32)Js::JavascriptNumber::GetOffsetOfType(), TyMachPtr, this->m_func);
  5002. if (this->m_lowerer->outerMostLoopLabel == nullptr)
  5003. {
  5004. // If we are not in loop, just insert in place
  5005. numberInitInsertInstr = instrInsert;
  5006. }
  5007. else
  5008. {
  5009. // Otherwise, initialize in the outer most loop top if we haven't initialized it yet.
  5010. numberInitInsertInstr = this->m_lowerer->initializedTempSym->TestAndSet(tempNumberSym->m_id) ?
  5011. nullptr : this->m_lowerer->outerMostLoopLabel;
  5012. }
  5013. }
  5014. else
  5015. {
  5016. this->GenerateNumberAllocation(dstOpnd, instrInsert, isHelper);
  5017. symVTableDst = IR::IndirOpnd::New(dstOpnd, 0, TyMachPtr, this->m_func);
  5018. symDblDst = IR::IndirOpnd::New(dstOpnd, (uint32)Js::JavascriptNumber::GetValueOffset(), TyFloat64, this->m_func);
  5019. symTypeDst = IR::IndirOpnd::New(dstOpnd, (uint32)Js::JavascriptNumber::GetOffsetOfType(), TyMachPtr, this->m_func);
  5020. numberInitInsertInstr = instrInsert;
  5021. }
  5022. if (numberInitInsertInstr)
  5023. {
  5024. // Inline the case where the dst is marked as temp.
  5025. IR::Opnd *jsNumberVTable = m_lowerer->LoadVTableValueOpnd(numberInitInsertInstr, VTableValue::VtableJavascriptNumber);
  5026. // MOV dst->vtable, JavascriptNumber::vtable
  5027. newInstr = IR::Instr::New(Js::OpCode::MOV, symVTableDst, jsNumberVTable, this->m_func);
  5028. numberInitInsertInstr->InsertBefore(newInstr);
  5029. // MOV dst->type, JavascriptNumber_type
  5030. IR::Opnd *typeOpnd = m_lowerer->LoadLibraryValueOpnd(numberInitInsertInstr, LibraryValue::ValueNumberTypeStatic);
  5031. newInstr = IR::Instr::New(Js::OpCode::MOV, symTypeDst, typeOpnd, this->m_func);
  5032. numberInitInsertInstr->InsertBefore(newInstr);
  5033. }
  5034. // MOVSD dst->value, opndFloat ; copy the float result to the temp JavascriptNumber
  5035. newInstr = IR::Instr::New(Js::OpCode::MOVSD, symDblDst, opndFloat, this->m_func);
  5036. instrInsert->InsertBefore(newInstr);
  5037. #else
  5038. // s1 = MOVD opndFloat
  5039. IR::RegOpnd *s1 = IR::RegOpnd::New(TyMachReg, m_func);
  5040. IR::Instr *movd = IR::Instr::New(Js::OpCode::MOVD, s1, opndFloat, m_func);
  5041. instrInsert->InsertBefore(movd);
  5042. if (m_func->GetJnFunction()->GetIsAsmjsMode())
  5043. {
  5044. // s1 = MOVD src
  5045. // tmp = NOT s1
  5046. // tmp = AND tmp, 0x7FF0000000000000ull
  5047. // test tmp, tmp
  5048. // je helper
  5049. // jmp done
  5050. // helper:
  5051. // tmp2 = AND s1, 0x000FFFFFFFFFFFFFull
  5052. // test tmp2, tmp2
  5053. // je done
  5054. // s1 = JavascriptNumber::k_Nan
  5055. // done:
  5056. IR::RegOpnd *tmp = IR::RegOpnd::New(TyMachReg, m_func);
  5057. IR::Instr * newInstr = IR::Instr::New(Js::OpCode::NOT, tmp, s1, m_func);
  5058. instrInsert->InsertBefore(newInstr);
  5059. LowererMD::MakeDstEquSrc1(newInstr);
  5060. newInstr = IR::Instr::New(Js::OpCode::AND, tmp, tmp, IR::AddrOpnd::New((Js::Var)0x7FF0000000000000, IR::AddrOpndKindConstantVar, m_func, true), m_func);
  5061. instrInsert->InsertBefore(newInstr);
  5062. LowererMD::Legalize(newInstr);
  5063. IR::LabelInstr* helper = Lowerer::InsertLabel(true, instrInsert);
  5064. Lowerer::InsertTestBranch(tmp, tmp, Js::OpCode::BrEq_A, helper, helper);
  5065. IR::LabelInstr* done = Lowerer::InsertLabel(isHelper, instrInsert);
  5066. Lowerer::InsertBranch(Js::OpCode::Br, done, helper);
  5067. IR::RegOpnd *tmp2 = IR::RegOpnd::New(TyMachReg, m_func);
  5068. newInstr = IR::Instr::New(Js::OpCode::AND, tmp2, s1, IR::AddrOpnd::New((Js::Var)0x000FFFFFFFFFFFFFull, IR::AddrOpndKindConstantVar, m_func, true), m_func);
  5069. done->InsertBefore(newInstr);
  5070. LowererMD::Legalize(newInstr);
  5071. Lowerer::InsertTestBranch(tmp2, tmp2, Js::OpCode::BrEq_A, done, done);
  5072. IR::Opnd * opndNaN = IR::AddrOpnd::New((Js::Var)Js::JavascriptNumber::k_Nan, IR::AddrOpndKindConstantVar, m_func, true);
  5073. Lowerer::InsertMove(s1, opndNaN, done);
  5074. }
  5075. // s1 = XOR s1, FloatTag_Value
  5076. // dst = s1
  5077. IR::Instr *setTag = IR::Instr::New(Js::OpCode::XOR,
  5078. s1,
  5079. s1,
  5080. IR::AddrOpnd::New((Js::Var)Js::FloatTag_Value,
  5081. IR::AddrOpndKindConstantVar,
  5082. this->m_func,
  5083. /* dontEncode = */ true),
  5084. this->m_func);
  5085. IR::Instr *movDst = IR::Instr::New(Js::OpCode::MOV, dstOpnd, s1, this->m_func);
  5086. instrInsert->InsertBefore(setTag);
  5087. instrInsert->InsertBefore(movDst);
  5088. LowererMD::Legalize(setTag);
  5089. #endif
  5090. }
  5091. void
  5092. LowererMD::EmitLoadFloatFromNumber(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr)
  5093. {
  5094. IR::LabelInstr *labelDone;
  5095. IR::Instr *instr;
  5096. labelDone = EmitLoadFloatCommon(dst, src, insertInstr, insertInstr->HasBailOutInfo());
  5097. if (labelDone == nullptr)
  5098. {
  5099. // We're done
  5100. insertInstr->Remove();
  5101. return;
  5102. }
  5103. // $Done note: insertAfter
  5104. insertInstr->InsertAfter(labelDone);
  5105. if (!insertInstr->HasBailOutInfo())
  5106. {
  5107. // $Done
  5108. insertInstr->Remove();
  5109. return;
  5110. }
  5111. Assert(!m_func->GetJnFunction()->GetIsAsmjsMode());
  5112. IR::LabelInstr *labelNoBailOut = nullptr;
  5113. IR::SymOpnd *tempSymOpnd = nullptr;
  5114. if (insertInstr->GetBailOutKind() == IR::BailOutPrimitiveButString)
  5115. {
  5116. if (!this->m_func->tempSymDouble)
  5117. {
  5118. this->m_func->tempSymDouble = StackSym::New(TyFloat64, this->m_func);
  5119. this->m_func->StackAllocate(this->m_func->tempSymDouble, MachDouble);
  5120. }
  5121. // LEA r3, tempSymDouble
  5122. IR::RegOpnd *reg3Opnd = IR::RegOpnd::New(TyMachReg, this->m_func);
  5123. tempSymOpnd = IR::SymOpnd::New(this->m_func->tempSymDouble, TyFloat64, this->m_func);
  5124. instr = IR::Instr::New(Js::OpCode::LEA, reg3Opnd, tempSymOpnd, this->m_func);
  5125. insertInstr->InsertBefore(instr);
  5126. // regBoolResult = to_number_fromPrimitive(value, &dst, allowUndef, scriptContext);
  5127. this->m_lowerer->LoadScriptContext(insertInstr);
  5128. IR::IntConstOpnd *allowUndefOpnd;
  5129. if (insertInstr->GetBailOutKind() == IR::BailOutPrimitiveButString)
  5130. {
  5131. allowUndefOpnd = IR::IntConstOpnd::New(true, TyInt32, this->m_func);
  5132. }
  5133. else
  5134. {
  5135. Assert(insertInstr->GetBailOutKind() == IR::BailOutNumberOnly);
  5136. allowUndefOpnd = IR::IntConstOpnd::New(false, TyInt32, this->m_func);
  5137. }
  5138. this->LoadHelperArgument(insertInstr, allowUndefOpnd);
  5139. this->LoadHelperArgument(insertInstr, reg3Opnd);
  5140. this->LoadHelperArgument(insertInstr, src);
  5141. IR::RegOpnd *regBoolResult = IR::RegOpnd::New(TyInt32, this->m_func);
  5142. instr = IR::Instr::New(Js::OpCode::CALL, regBoolResult, IR::HelperCallOpnd::New(IR::HelperOp_ConvNumber_FromPrimitive, this->m_func), this->m_func);
  5143. insertInstr->InsertBefore(instr);
  5144. this->lowererMDArch.LowerCall(instr, 0);
  5145. // TEST regBoolResult, regBoolResult
  5146. instr = IR::Instr::New(Js::OpCode::TEST, this->m_func);
  5147. instr->SetSrc1(regBoolResult);
  5148. instr->SetSrc2(regBoolResult);
  5149. insertInstr->InsertBefore(instr);
  5150. // JNE $noBailOut
  5151. labelNoBailOut = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
  5152. instr = IR::BranchInstr::New(Js::OpCode::JNE, labelNoBailOut, this->m_func);
  5153. insertInstr->InsertBefore(instr);
  5154. }
  5155. // Bailout code
  5156. Assert(insertInstr->m_opcode == Js::OpCode::FromVar);
  5157. insertInstr->UnlinkDst();
  5158. insertInstr->FreeSrc1();
  5159. IR::Instr *bailoutInstr = insertInstr;
  5160. insertInstr = bailoutInstr->m_next;
  5161. this->m_lowerer->GenerateBailOut(bailoutInstr);
  5162. // $noBailOut
  5163. if (labelNoBailOut)
  5164. {
  5165. insertInstr->InsertBefore(labelNoBailOut);
  5166. Assert(dst->IsRegOpnd());
  5167. // MOVSD dst, [pResult].f64
  5168. instr = IR::Instr::New(Js::OpCode::MOVSD, dst, tempSymOpnd, this->m_func);
  5169. insertInstr->InsertBefore(instr);
  5170. }
  5171. }
  5172. IR::LabelInstr*
  5173. LowererMD::EmitLoadFloatCommon(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, bool needHelperLabel)
  5174. {
  5175. IR::Instr *instr;
  5176. Assert(src->GetType() == TyVar);
  5177. Assert(dst->IsFloat());
  5178. bool isFloatConst = false;
  5179. IR::RegOpnd *regFloatOpnd = nullptr;
  5180. if (src->IsRegOpnd() && src->AsRegOpnd()->m_sym->m_isFltConst)
  5181. {
  5182. IR::RegOpnd *regOpnd = src->AsRegOpnd();
  5183. Assert(regOpnd->m_sym->m_isSingleDef);
  5184. Js::Var value = regOpnd->m_sym->GetFloatConstValueAsVar_PostGlobOpt();
  5185. #if FLOATVAR
  5186. double *pDouble = NativeCodeDataNew(this->m_func->GetNativeCodeDataAllocator(), double);
  5187. AnalysisAssert(pDouble);
  5188. *pDouble = Js::JavascriptNumber::GetValue(value);
  5189. IR::MemRefOpnd *memRef = IR::MemRefOpnd::New((BYTE*)pDouble, TyFloat64, this->m_func, IR::AddrOpndKindDynamicDoubleRef);
  5190. #else
  5191. IR::MemRefOpnd *memRef = IR::MemRefOpnd::New((BYTE*)value + Js::JavascriptNumber::GetValueOffset(), TyFloat64, this->m_func,
  5192. IR::AddrOpndKindDynamicDoubleRef);
  5193. #endif
  5194. regFloatOpnd = IR::RegOpnd::New(TyFloat64, this->m_func);
  5195. instr = IR::Instr::New(Js::OpCode::MOVSD, regFloatOpnd, memRef, this->m_func);
  5196. insertInstr->InsertBefore(instr);
  5197. Legalize(instr);
  5198. isFloatConst = true;
  5199. }
  5200. // Src is constant?
  5201. if (src->IsImmediateOpnd() || src->IsFloatConstOpnd())
  5202. {
  5203. regFloatOpnd = IR::RegOpnd::New(TyFloat64, this->m_func);
  5204. m_lowerer->LoadFloatFromNonReg(src, regFloatOpnd, insertInstr);
  5205. isFloatConst = true;
  5206. }
  5207. if (isFloatConst)
  5208. {
  5209. if (dst->GetType() == TyFloat32)
  5210. {
  5211. // CVTSD2SS regOpnd32.f32, regOpnd.f64 -- Convert regOpnd from f64 to f32
  5212. IR::RegOpnd *regOpnd32 = regFloatOpnd->UseWithNewType(TyFloat32, this->m_func)->AsRegOpnd();
  5213. instr = IR::Instr::New(Js::OpCode::CVTSD2SS, regOpnd32, regFloatOpnd, this->m_func);
  5214. insertInstr->InsertBefore(instr);
  5215. // MOVSS dst, regOpnd32
  5216. instr = IR::Instr::New(Js::OpCode::MOVSS, dst, regOpnd32, this->m_func);
  5217. insertInstr->InsertBefore(instr);
  5218. }
  5219. else
  5220. {
  5221. // MOVSD dst, regOpnd
  5222. instr = IR::Instr::New(Js::OpCode::MOVSD, dst, regFloatOpnd, this->m_func);
  5223. insertInstr->InsertBefore(instr);
  5224. }
  5225. return nullptr;
  5226. }
  5227. Assert(src->IsRegOpnd());
  5228. IR::LabelInstr *labelStore = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  5229. IR::LabelInstr *labelHelper;
  5230. IR::LabelInstr *labelDone = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  5231. if (needHelperLabel)
  5232. {
  5233. labelHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
  5234. }
  5235. else
  5236. {
  5237. labelHelper = labelDone;
  5238. }
  5239. bool const isFloat32 = dst->GetType() == TyFloat32;
  5240. IR::RegOpnd *reg2 = ((isFloat32 || !dst->IsRegOpnd()) ? IR::RegOpnd::New(TyMachDouble, this->m_func) : dst->AsRegOpnd());
  5241. // Load the float value in reg2
  5242. this->lowererMDArch.LoadCheckedFloat(src->AsRegOpnd(), reg2, labelStore, labelHelper, insertInstr, needHelperLabel);
  5243. // $Store
  5244. insertInstr->InsertBefore(labelStore);
  5245. if (isFloat32)
  5246. {
  5247. IR::RegOpnd *reg2_32 = reg2->UseWithNewType(TyFloat32, this->m_func)->AsRegOpnd();
  5248. // CVTSD2SS r2_32.f32, r2.f64 -- Convert regOpnd from f64 to f32
  5249. instr = IR::Instr::New(Js::OpCode::CVTSD2SS, reg2_32, reg2, this->m_func);
  5250. insertInstr->InsertBefore(instr);
  5251. // MOVSS dst, r2_32
  5252. instr = IR::Instr::New(Js::OpCode::MOVSS, dst, reg2_32, this->m_func);
  5253. insertInstr->InsertBefore(instr);
  5254. }
  5255. else if (reg2 != dst)
  5256. {
  5257. // MOVSD dst, r2
  5258. instr = IR::Instr::New(Js::OpCode::MOVSD, dst, reg2, this->m_func);
  5259. insertInstr->InsertBefore(instr);
  5260. }
  5261. // JMP $Done
  5262. instr = IR::BranchInstr::New(Js::OpCode::JMP, labelDone, this->m_func);
  5263. insertInstr->InsertBefore(instr);
  5264. if (needHelperLabel)
  5265. {
  5266. // $Helper
  5267. insertInstr->InsertBefore(labelHelper);
  5268. }
  5269. return labelDone;
  5270. }
  5271. IR::RegOpnd *
  5272. LowererMD::EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr)
  5273. {
  5274. IR::LabelInstr *labelDone;
  5275. IR::Instr *instr;
  5276. labelDone = EmitLoadFloatCommon(dst, src, insertInstr, true);
  5277. if (labelDone == nullptr)
  5278. {
  5279. // We're done
  5280. return nullptr;
  5281. }
  5282. IR::Opnd *memAddress = dst;
  5283. if (dst->IsRegOpnd())
  5284. {
  5285. // Create an f64 stack location to store the result of the helper.
  5286. IR::SymOpnd *symOpnd = IR::SymOpnd::New(StackSym::New(dst->GetType(), this->m_func), dst->GetType(), this->m_func);
  5287. this->m_func->StackAllocate(symOpnd->m_sym->AsStackSym(), sizeof(double));
  5288. memAddress = symOpnd;
  5289. }
  5290. // LEA r3, dst
  5291. IR::RegOpnd *reg3Opnd = IR::RegOpnd::New(TyMachReg, this->m_func);
  5292. instr = IR::Instr::New(Js::OpCode::LEA, reg3Opnd, memAddress, this->m_func);
  5293. insertInstr->InsertBefore(instr);
  5294. // to_number_full(value, &dst, scriptContext);
  5295. // Create dummy binary op to convert into helper
  5296. instr = IR::Instr::New(Js::OpCode::Add_A, this->m_func);
  5297. instr->SetSrc1(src);
  5298. instr->SetSrc2(reg3Opnd);
  5299. insertInstr->InsertBefore(instr);
  5300. IR::JnHelperMethod helper;
  5301. if (dst->GetType() == TyFloat32)
  5302. {
  5303. helper = IR::HelperOp_ConvFloat_Helper;
  5304. }
  5305. else
  5306. {
  5307. helper = IR::HelperOp_ConvNumber_Helper;
  5308. }
  5309. this->m_lowerer->LowerBinaryHelperMem(instr, helper);
  5310. if (dst->IsRegOpnd())
  5311. {
  5312. if (dst->GetType() == TyFloat32)
  5313. {
  5314. // MOVSS dst, r32
  5315. instr = IR::Instr::New(Js::OpCode::MOVSS, dst, memAddress, this->m_func);
  5316. insertInstr->InsertBefore(instr);
  5317. }
  5318. else
  5319. {
  5320. // MOVSD dst, [pResult].f64
  5321. instr = IR::Instr::New(Js::OpCode::MOVSD, dst, memAddress, this->m_func);
  5322. insertInstr->InsertBefore(instr);
  5323. }
  5324. }
  5325. // $Done
  5326. insertInstr->InsertBefore(labelDone);
  5327. return nullptr;
  5328. }
  5329. void
  5330. LowererMD::LowerInt4NegWithBailOut(
  5331. IR::Instr *const instr,
  5332. const IR::BailOutKind bailOutKind,
  5333. IR::LabelInstr *const bailOutLabel,
  5334. IR::LabelInstr *const skipBailOutLabel)
  5335. {
  5336. Assert(instr);
  5337. Assert(instr->m_opcode == Js::OpCode::Neg_I4);
  5338. Assert(!instr->HasBailOutInfo());
  5339. Assert(bailOutKind & IR::BailOutOnResultConditions || bailOutKind == IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck);
  5340. Assert(bailOutLabel);
  5341. Assert(instr->m_next == bailOutLabel);
  5342. Assert(skipBailOutLabel);
  5343. instr->ReplaceDst(instr->GetDst()->UseWithNewType(TyInt32, instr->m_func));
  5344. instr->ReplaceSrc1(instr->GetSrc1()->UseWithNewType(TyInt32, instr->m_func));
  5345. // Lower the instruction
  5346. instr->m_opcode = Js::OpCode::NEG;
  5347. Legalize(instr);
  5348. if(bailOutKind & IR::BailOutOnOverflow || bailOutKind == IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck)
  5349. {
  5350. bailOutLabel->InsertBefore(IR::BranchInstr::New(Js::OpCode::JO, bailOutLabel, instr->m_func));
  5351. }
  5352. if(bailOutKind & IR::BailOutOnNegativeZero)
  5353. {
  5354. bailOutLabel->InsertBefore(IR::BranchInstr::New(Js::OpCode::JEQ, bailOutLabel, instr->m_func));
  5355. }
  5356. // Skip bailout
  5357. bailOutLabel->InsertBefore(IR::BranchInstr::New(LowererMD::MDUncondBranchOpcode, skipBailOutLabel, instr->m_func));
  5358. }
  5359. void
  5360. LowererMD::LowerInt4AddWithBailOut(
  5361. IR::Instr *const instr,
  5362. const IR::BailOutKind bailOutKind,
  5363. IR::LabelInstr *const bailOutLabel,
  5364. IR::LabelInstr *const skipBailOutLabel)
  5365. {
  5366. Assert(instr);
  5367. Assert(instr->m_opcode == Js::OpCode::Add_I4);
  5368. Assert(!instr->HasBailOutInfo());
  5369. Assert(
  5370. (bailOutKind & IR::BailOutOnResultConditions) == IR::BailOutOnOverflow ||
  5371. bailOutKind == IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck);
  5372. Assert(bailOutLabel);
  5373. Assert(instr->m_next == bailOutLabel);
  5374. Assert(skipBailOutLabel);
  5375. instr->ReplaceDst(instr->GetDst()->UseWithNewType(TyInt32, instr->m_func));
  5376. instr->ReplaceSrc1(instr->GetSrc1()->UseWithNewType(TyInt32, instr->m_func));
  5377. instr->ReplaceSrc2(instr->GetSrc2()->UseWithNewType(TyInt32, instr->m_func));
  5378. // Restore sources overwritten by the instruction in the bailout path
  5379. const auto dst = instr->GetDst(), src1 = instr->GetSrc1(), src2 = instr->GetSrc2();
  5380. Assert(dst->IsRegOpnd());
  5381. const bool dstEquSrc1 = dst->IsEqual(src1), dstEquSrc2 = dst->IsEqual(src2);
  5382. if(dstEquSrc1 & dstEquSrc2)
  5383. {
  5384. // We have:
  5385. // s1 += s1
  5386. // Which is equivalent to:
  5387. // s1 <<= 1
  5388. //
  5389. // These overflow a signed 32-bit integer when for the initial s1:
  5390. // s1 > 0 && (s1 & 0x40000000) - result is negative after overflow
  5391. // s1 < 0 && !(s1 & 0x40000000) - result is nonnegative after overflow
  5392. //
  5393. // To restore s1 to its value before the operation, we first do an arithmetic right-shift by one bit to undo the
  5394. // left-shift and preserve the sign of the result after overflow. Since the result after overflow always has the
  5395. // opposite sign from the operands (hence the overflow), we just need to invert the sign of the result. The following
  5396. // restores s1 to its value before the instruction:
  5397. // s1 = (s1 >> 1) ^ 0x80000000
  5398. //
  5399. // Generate:
  5400. // sar s1, 1
  5401. // xor s1, 0x80000000
  5402. const auto startBailOutInstr = bailOutLabel->m_next;
  5403. Assert(startBailOutInstr);
  5404. startBailOutInstr->InsertBefore(
  5405. IR::Instr::New(
  5406. Js::OpCode::SAR,
  5407. dst,
  5408. dst,
  5409. IR::IntConstOpnd::New(1, TyInt8, instr->m_func),
  5410. instr->m_func)
  5411. );
  5412. startBailOutInstr->InsertBefore(
  5413. IR::Instr::New(
  5414. Js::OpCode::XOR,
  5415. dst,
  5416. dst,
  5417. IR::IntConstOpnd::New(INT32_MIN, TyInt32, instr->m_func, true /* dontEncode */),
  5418. instr->m_func)
  5419. );
  5420. }
  5421. else if(dstEquSrc1 | dstEquSrc2)
  5422. {
  5423. // We have:
  5424. // s1 += s2
  5425. // Or:
  5426. // s1 = s2 + s1
  5427. //
  5428. // The following restores s1 to its value before the instruction:
  5429. // s1 -= s2
  5430. //
  5431. // Generate:
  5432. // sub s1, s2
  5433. if(dstEquSrc1)
  5434. {
  5435. Assert(src2->IsRegOpnd() || src2->IsIntConstOpnd());
  5436. }
  5437. else
  5438. {
  5439. Assert(src1->IsRegOpnd() || src1->IsIntConstOpnd());
  5440. }
  5441. bailOutLabel->InsertAfter(IR::Instr::New(Js::OpCode::SUB, dst, dst, dstEquSrc1 ? src2 : src1, instr->m_func));
  5442. }
  5443. // Lower the instruction
  5444. ChangeToAdd(instr, true /* needFlags */);
  5445. Legalize(instr);
  5446. // Skip bailout on no overflow
  5447. bailOutLabel->InsertBefore(IR::BranchInstr::New(Js::OpCode::JNO, skipBailOutLabel, instr->m_func));
  5448. // Fall through to bailOutLabel
  5449. }
  5450. void
  5451. LowererMD::LowerInt4SubWithBailOut(
  5452. IR::Instr *const instr,
  5453. const IR::BailOutKind bailOutKind,
  5454. IR::LabelInstr *const bailOutLabel,
  5455. IR::LabelInstr *const skipBailOutLabel)
  5456. {
  5457. Assert(instr);
  5458. Assert(instr->m_opcode == Js::OpCode::Sub_I4);
  5459. Assert(!instr->HasBailOutInfo());
  5460. Assert(
  5461. (bailOutKind & IR::BailOutOnResultConditions) == IR::BailOutOnOverflow ||
  5462. bailOutKind == IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck);
  5463. Assert(bailOutLabel);
  5464. Assert(instr->m_next == bailOutLabel);
  5465. Assert(skipBailOutLabel);
  5466. instr->ReplaceDst(instr->GetDst()->UseWithNewType(TyInt32, instr->m_func));
  5467. instr->ReplaceSrc1(instr->GetSrc1()->UseWithNewType(TyInt32, instr->m_func));
  5468. instr->ReplaceSrc2(instr->GetSrc2()->UseWithNewType(TyInt32, instr->m_func));
  5469. // Restore sources overwritten by the instruction in the bailout path
  5470. const auto dst = instr->GetDst(), src1 = instr->GetSrc1(), src2 = instr->GetSrc2();
  5471. Assert(dst->IsRegOpnd());
  5472. const bool dstEquSrc1 = dst->IsEqual(src1), dstEquSrc2 = dst->IsEqual(src2);
  5473. if(dstEquSrc1 ^ dstEquSrc2)
  5474. {
  5475. // We have:
  5476. // s1 -= s2
  5477. // Or:
  5478. // s1 = s2 - s1
  5479. //
  5480. // The following restores s1 to its value before the instruction:
  5481. // s1 += s2
  5482. // Or:
  5483. // s1 = s2 - s1
  5484. //
  5485. // Generate:
  5486. // neg s1 - only for second case
  5487. // add s1, s2
  5488. if(dstEquSrc1)
  5489. {
  5490. Assert(src2->IsRegOpnd() || src2->IsIntConstOpnd());
  5491. }
  5492. else
  5493. {
  5494. Assert(src1->IsRegOpnd() || src1->IsIntConstOpnd());
  5495. }
  5496. const auto startBailOutInstr = bailOutLabel->m_next;
  5497. Assert(startBailOutInstr);
  5498. if(dstEquSrc2)
  5499. {
  5500. startBailOutInstr->InsertBefore(IR::Instr::New(Js::OpCode::NEG, dst, dst, instr->m_func));
  5501. }
  5502. startBailOutInstr->InsertBefore(IR::Instr::New(Js::OpCode::ADD, dst, dst, dstEquSrc1 ? src2 : src1, instr->m_func));
  5503. }
  5504. // Lower the instruction
  5505. ChangeToSub(instr, true /* needFlags */);
  5506. Legalize(instr);
  5507. // Skip bailout on no overflow
  5508. bailOutLabel->InsertBefore(IR::BranchInstr::New(Js::OpCode::JNO, skipBailOutLabel, instr->m_func));
  5509. // Fall through to bailOutLabel
  5510. }
  5511. bool
  5512. LowererMD::GenerateSimplifiedInt4Mul(
  5513. IR::Instr *const mulInstr,
  5514. const IR::BailOutKind bailOutKind,
  5515. IR::LabelInstr *const bailOutLabel)
  5516. {
  5517. if (AutoSystemInfo::Data.IsAtomPlatform())
  5518. {
  5519. // On Atom, always optimize unless phase is off
  5520. if (PHASE_OFF(Js::AtomPhase, mulInstr->m_func->GetTopFunc()) ||
  5521. PHASE_OFF(Js::MulStrengthReductionPhase, mulInstr->m_func->GetTopFunc()))
  5522. return false;
  5523. }
  5524. else
  5525. {
  5526. // On other platforms, don't optimize unless phase is forced
  5527. if (!PHASE_FORCE(Js::AtomPhase, mulInstr->m_func->GetTopFunc()) &&
  5528. !PHASE_FORCE(Js::MulStrengthReductionPhase, mulInstr->m_func->GetTopFunc()))
  5529. return false;
  5530. }
  5531. Assert(mulInstr);
  5532. Assert(mulInstr->m_opcode == Js::OpCode::Mul_I4);
  5533. IR::Instr *instr = mulInstr, *nextInstr;
  5534. const auto dst = instr->GetDst(), src1 = instr->GetSrc1(), src2 = instr->GetSrc2();
  5535. if (!src1->IsIntConstOpnd() && !src2->IsIntConstOpnd())
  5536. return false;
  5537. // if two const operands, GlobOpt would have folded the computation
  5538. Assert(!(src1->IsIntConstOpnd() && src2->IsIntConstOpnd()));
  5539. Assert(dst->IsRegOpnd());
  5540. const auto constSrc = src1->IsIntConstOpnd() ? src1 : src2;
  5541. const auto nonConstSrc = src1->IsIntConstOpnd() ? src2 : src1;
  5542. const auto constSrcValue = constSrc->AsIntConstOpnd()->AsInt32();
  5543. auto nonConstSrcCopy = nonConstSrc;
  5544. Assert(nonConstSrc->IsRegOpnd());
  5545. bool doOVF = bailOutKind & IR::BailOutOnMulOverflow || bailOutKind == IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck;
  5546. // don't simplify mul by large numbers with OF check
  5547. if (doOVF && (constSrcValue > 3 || constSrcValue < -3))
  5548. return false;
  5549. switch(constSrcValue)
  5550. {
  5551. case -3:
  5552. case 3:
  5553. // if dst = src, we need to have a copy of the src for the ADD/SUB
  5554. if (dst->IsEqual(nonConstSrc))
  5555. {
  5556. nonConstSrcCopy = IR::RegOpnd::New(nonConstSrc->GetType(), instr->m_func);
  5557. // MOV
  5558. Lowerer::InsertMove(nonConstSrcCopy, nonConstSrc, instr);
  5559. }
  5560. instr->UnlinkSrc1();
  5561. instr->UnlinkSrc2();
  5562. // SHL
  5563. instr->m_opcode = Js::OpCode::SHL;
  5564. instr->SetSrc1(nonConstSrc);
  5565. instr->SetSrc2(IR::IntConstOpnd::New((IntConstType) 1, TyInt32, instr->m_func));
  5566. constSrc->Free(instr->m_func);
  5567. Legalize(instr);
  5568. // JO
  5569. if (doOVF)
  5570. {
  5571. nextInstr = IR::BranchInstr::New(Js::OpCode::JO, bailOutLabel, instr->m_func);
  5572. instr->InsertAfter(nextInstr);
  5573. instr = nextInstr;
  5574. }
  5575. // ADD
  5576. nextInstr = IR::Instr::New(Js::OpCode::ADD, dst, dst, nonConstSrcCopy, instr->m_func);
  5577. instr->InsertAfter(nextInstr);
  5578. instr = nextInstr;
  5579. Legalize(instr);
  5580. if (constSrcValue == -3)
  5581. {
  5582. // JO
  5583. if (doOVF)
  5584. {
  5585. nextInstr = IR::BranchInstr::New(Js::OpCode::JO, bailOutLabel, instr->m_func);
  5586. instr->InsertAfter(nextInstr);
  5587. instr = nextInstr;
  5588. }
  5589. // NEG
  5590. nextInstr = IR::Instr::New(Js::OpCode::NEG, dst, dst, instr->m_func);
  5591. instr->InsertAfter(nextInstr);
  5592. instr = nextInstr;
  5593. Legalize(instr);
  5594. }
  5595. // last JO inserted by caller
  5596. return true;
  5597. case -2:
  5598. case 2:
  5599. instr->UnlinkSrc1();
  5600. instr->UnlinkSrc2();
  5601. // SHL
  5602. instr->m_opcode = Js::OpCode::SHL;
  5603. instr->SetSrc1(nonConstSrc);
  5604. instr->SetSrc2(IR::IntConstOpnd::New((IntConstType) 1, TyInt32, instr->m_func));
  5605. constSrc->Free(instr->m_func);
  5606. Legalize(instr);
  5607. if (constSrcValue == -2)
  5608. {
  5609. // JO
  5610. if (doOVF)
  5611. {
  5612. nextInstr = IR::BranchInstr::New(Js::OpCode::JO, bailOutLabel, instr->m_func);
  5613. instr->InsertAfter(nextInstr);
  5614. instr = nextInstr;
  5615. }
  5616. // NEG
  5617. nextInstr = IR::Instr::New(Js::OpCode::NEG, dst, dst, instr->m_func);
  5618. instr->InsertAfter(nextInstr);
  5619. instr = nextInstr;
  5620. Legalize(instr);
  5621. }
  5622. // last JO inserted by caller
  5623. return true;
  5624. case -1:
  5625. instr->UnlinkSrc1();
  5626. instr->UnlinkSrc2();
  5627. // NEG
  5628. instr->m_opcode = Js::OpCode::NEG;
  5629. instr->SetSrc1(nonConstSrc);
  5630. constSrc->Free(instr->m_func);
  5631. Legalize(instr);
  5632. // JO inserted by caller
  5633. return true;
  5634. case 0:
  5635. instr->FreeSrc1();
  5636. instr->FreeSrc2();
  5637. // MOV
  5638. instr->m_opcode = Js::OpCode::MOV;
  5639. instr->SetSrc1(IR::IntConstOpnd::New((IntConstType) 0, TyInt32, instr->m_func));
  5640. Legalize(instr);
  5641. // JO inserted by caller are removed in later phases
  5642. return true;
  5643. case 1:
  5644. instr->UnlinkSrc1();
  5645. instr->UnlinkSrc2();
  5646. // MOV
  5647. instr->m_opcode = Js::OpCode::MOV;
  5648. instr->SetSrc1(nonConstSrc);
  5649. constSrc->Free(instr->m_func);
  5650. Legalize(instr);
  5651. // JO inserted by caller are removed in later phases
  5652. return true;
  5653. default:
  5654. // large numbers with no OF check
  5655. Assert(!doOVF);
  5656. // 2^i
  5657. // -2^i
  5658. if (Math::IsPow2(constSrcValue) || Math::IsPow2(-constSrcValue))
  5659. {
  5660. uint32 shamt = constSrcValue > 0 ? Math::Log2(constSrcValue) : Math::Log2(-constSrcValue);
  5661. instr->UnlinkSrc1();
  5662. instr->UnlinkSrc2();
  5663. // SHL
  5664. instr->m_opcode = Js::OpCode::SHL;
  5665. instr->SetSrc1(nonConstSrc);
  5666. instr->SetSrc2(IR::IntConstOpnd::New((IntConstType) shamt, TyInt32, instr->m_func));
  5667. constSrc->Free(instr->m_func);
  5668. Legalize(instr);
  5669. if (constSrcValue < 0)
  5670. {
  5671. // NEG
  5672. nextInstr = IR::Instr::New(Js::OpCode::NEG, dst, dst, instr->m_func);
  5673. instr->InsertAfter(nextInstr);
  5674. Legalize(instr);
  5675. }
  5676. return true;
  5677. }
  5678. // 2^i + 1
  5679. // 2^i - 1
  5680. if (Math::IsPow2(constSrcValue - 1) || Math::IsPow2(constSrcValue + 1))
  5681. {
  5682. bool plusOne = Math::IsPow2(constSrcValue - 1);
  5683. uint32 shamt = plusOne ? Math::Log2(constSrcValue - 1) : Math::Log2(constSrcValue + 1);
  5684. if (dst->IsEqual(nonConstSrc))
  5685. {
  5686. nonConstSrcCopy = IR::RegOpnd::New(nonConstSrc->GetType(), instr->m_func);
  5687. // MOV
  5688. Lowerer::InsertMove(nonConstSrcCopy, nonConstSrc, instr);
  5689. }
  5690. instr->UnlinkSrc1();
  5691. instr->UnlinkSrc2();
  5692. // SHL
  5693. instr->m_opcode = Js::OpCode::SHL;
  5694. instr->SetSrc1(nonConstSrc);
  5695. instr->SetSrc2(IR::IntConstOpnd::New((IntConstType) shamt, TyInt32, instr->m_func));
  5696. constSrc->Free(instr->m_func);
  5697. Legalize(instr);
  5698. // ADD/SUB
  5699. nextInstr = IR::Instr::New(plusOne ? Js::OpCode::ADD : Js::OpCode::SUB, dst, dst, nonConstSrcCopy, instr->m_func);
  5700. instr->InsertAfter(nextInstr);
  5701. instr = nextInstr;
  5702. Legalize(instr);
  5703. return true;
  5704. }
  5705. return false;
  5706. }
  5707. }
  5708. void
  5709. LowererMD::LowerInt4MulWithBailOut(
  5710. IR::Instr *const instr,
  5711. const IR::BailOutKind bailOutKind,
  5712. IR::LabelInstr *const bailOutLabel,
  5713. IR::LabelInstr *const skipBailOutLabel)
  5714. {
  5715. Assert(instr);
  5716. Assert(instr->m_opcode == Js::OpCode::Mul_I4);
  5717. Assert(!instr->HasBailOutInfo());
  5718. Assert(bailOutKind & IR::BailOutOnResultConditions || bailOutKind == IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck);
  5719. Assert(bailOutLabel);
  5720. Assert(instr->m_next == bailOutLabel);
  5721. Assert(skipBailOutLabel);
  5722. instr->ReplaceDst(instr->GetDst()->UseWithNewType(TyInt32, instr->m_func));
  5723. instr->ReplaceSrc1(instr->GetSrc1()->UseWithNewType(TyInt32, instr->m_func));
  5724. instr->ReplaceSrc2(instr->GetSrc2()->UseWithNewType(TyInt32, instr->m_func));
  5725. IR::LabelInstr *checkForNegativeZeroLabel = nullptr;
  5726. if(bailOutKind & IR::BailOutOnNegativeZero)
  5727. {
  5728. // We have:
  5729. // s3 = s1 * s2
  5730. //
  5731. // If the result is zero, we need to check and only bail out if it would be -0. The following determines this:
  5732. // bailOut = (s1 < 0 || s2 < 0) (either s1 or s2 has to be zero for the result to be zero, so we don't emit zero checks)
  5733. //
  5734. // Note, however, that if in future we decide to ignore mul overflow in some cases, and overflow occurs with one of the operands as negative,
  5735. // this can lead to bailout. Will handle that case if ever we decide to ignore mul overflow.
  5736. //
  5737. // Generate:
  5738. // $checkForNegativeZeroLabel:
  5739. // test s1, s1
  5740. // js $bailOutLabel
  5741. // test s2, s2
  5742. // jns $skipBailOutLabel
  5743. // (fall through to bail out)
  5744. const auto dst = instr->GetDst(), src1 = instr->GetSrc1(), src2 = instr->GetSrc2();
  5745. Assert(dst->IsRegOpnd());
  5746. Assert(!src1->IsEqual(src2)); // cannot result in -0 if both operands are the same; GlobOpt should have figured that out
  5747. checkForNegativeZeroLabel = IR::LabelInstr::New(Js::OpCode::Label, instr->m_func, true);
  5748. bailOutLabel->InsertBefore(checkForNegativeZeroLabel);
  5749. if(src1->IsIntConstOpnd() || src2->IsIntConstOpnd())
  5750. {
  5751. Assert(!(src1->IsIntConstOpnd() && src2->IsIntConstOpnd())); // if this results in -0, GlobOpt should have avoided type specialization
  5752. const auto constSrc = src1->IsIntConstOpnd() ? src1 : src2;
  5753. const auto nonConstSrc = src1->IsIntConstOpnd() ? src2 : src1;
  5754. Assert(nonConstSrc->IsRegOpnd());
  5755. const auto newInstr = IR::Instr::New(Js::OpCode::TEST, instr->m_func);
  5756. newInstr->SetSrc1(nonConstSrc);
  5757. newInstr->SetSrc2(nonConstSrc);
  5758. bailOutLabel->InsertBefore(newInstr);
  5759. const auto constSrcValue = constSrc->AsIntConstOpnd()->GetValue();
  5760. if(constSrcValue == 0)
  5761. {
  5762. bailOutLabel->InsertBefore(IR::BranchInstr::New(Js::OpCode::JNSB, skipBailOutLabel, instr->m_func));
  5763. }
  5764. else
  5765. {
  5766. Assert(constSrcValue < 0); // cannot result in -0 if one operand is positive; GlobOpt should have figured that out
  5767. bailOutLabel->InsertBefore(IR::BranchInstr::New(Js::OpCode::JNE, skipBailOutLabel, instr->m_func));
  5768. }
  5769. }
  5770. else
  5771. {
  5772. auto newInstr = IR::Instr::New(Js::OpCode::TEST, instr->m_func);
  5773. newInstr->SetSrc1(src1);
  5774. newInstr->SetSrc2(src1);
  5775. bailOutLabel->InsertBefore(newInstr);
  5776. bailOutLabel->InsertBefore(IR::BranchInstr::New(Js::OpCode::JSB, bailOutLabel, instr->m_func));
  5777. newInstr = IR::Instr::New(Js::OpCode::TEST, instr->m_func);
  5778. newInstr->SetSrc1(src2);
  5779. newInstr->SetSrc2(src2);
  5780. bailOutLabel->InsertBefore(newInstr);
  5781. bailOutLabel->InsertBefore(IR::BranchInstr::New(Js::OpCode::JNSB, skipBailOutLabel, instr->m_func));
  5782. }
  5783. // Fall through to bailOutLabel
  5784. }
  5785. const bool needsOverflowCheck =
  5786. bailOutKind & IR::BailOutOnMulOverflow || bailOutKind == IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck;
  5787. AssertMsg(!instr->ShouldCheckForNon32BitOverflow() || (needsOverflowCheck && instr->ShouldCheckForNon32BitOverflow()), "Non 32-bit overflow check required without bailout info");
  5788. bool simplifiedMul = LowererMD::GenerateSimplifiedInt4Mul(instr, bailOutKind, bailOutLabel);
  5789. // Lower the instruction
  5790. if (!simplifiedMul)
  5791. {
  5792. LowererMD::ChangeToMul(instr, needsOverflowCheck);
  5793. }
  5794. const auto insertBeforeInstr = checkForNegativeZeroLabel ? checkForNegativeZeroLabel : bailOutLabel;
  5795. if(needsOverflowCheck)
  5796. {
  5797. // do we care about int32 or non-int32 overflow ?
  5798. if (!simplifiedMul && !instr->ShouldCheckFor32BitOverflow() && instr->ShouldCheckForNon32BitOverflow())
  5799. LowererMD::EmitNon32BitOvfCheck(instr, insertBeforeInstr, bailOutLabel);
  5800. else
  5801. insertBeforeInstr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JO, bailOutLabel, instr->m_func));
  5802. }
  5803. if(bailOutKind & IR::BailOutOnNegativeZero)
  5804. {
  5805. // On zero, branch to determine whether the result would be -0
  5806. Assert(checkForNegativeZeroLabel);
  5807. const auto newInstr = IR::Instr::New(Js::OpCode::TEST, instr->m_func);
  5808. const auto dst = instr->GetDst();
  5809. newInstr->SetSrc1(dst);
  5810. newInstr->SetSrc2(dst);
  5811. insertBeforeInstr->InsertBefore(newInstr);
  5812. insertBeforeInstr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JEQ, checkForNegativeZeroLabel, instr->m_func));
  5813. }
  5814. // Skip bailout
  5815. insertBeforeInstr->InsertBefore(IR::BranchInstr::New(LowererMD::MDUncondBranchOpcode, skipBailOutLabel, instr->m_func));
  5816. }
  5817. void
  5818. LowererMD::LowerInt4RemWithBailOut(
  5819. IR::Instr *const instr,
  5820. const IR::BailOutKind bailOutKind,
  5821. IR::LabelInstr *const bailOutLabel,
  5822. IR::LabelInstr *const skipBailOutLabel) const
  5823. {
  5824. Assert(instr);
  5825. Assert(instr->m_opcode == Js::OpCode::Rem_I4);
  5826. Assert(!instr->HasBailOutInfo());
  5827. Assert(bailOutKind & IR::BailOutOnNegativeZero);
  5828. Assert(bailOutLabel);
  5829. Assert(instr->m_next == bailOutLabel);
  5830. Assert(skipBailOutLabel);
  5831. instr->ReplaceDst(instr->GetDst()->UseWithNewType(TyInt32, instr->m_func));
  5832. instr->ReplaceSrc1(instr->GetSrc1()->UseWithNewType(TyInt32, instr->m_func));
  5833. instr->ReplaceSrc2(instr->GetSrc2()->UseWithNewType(TyInt32, instr->m_func));
  5834. bool fastPath = m_lowerer->GenerateSimplifiedInt4Rem(instr, skipBailOutLabel);
  5835. // We have:
  5836. // s3 = s1 % s2
  5837. //
  5838. // If the result is zero, we need to check and only bail out if it would be -0. The following determines this:
  5839. // bailOut = (s3 == 0 && s1 < 0)
  5840. //
  5841. // Generate:
  5842. // $checkForNegativeZeroLabel:
  5843. // test s3, s3
  5844. // jne $skipBailOutLabel
  5845. // test s1, s1
  5846. // jns $skipBailOutLabel
  5847. // (fall through to bail out)
  5848. IR::Opnd *dst = instr->GetDst(), *src1 = instr->GetSrc1();
  5849. Assert(dst->IsRegOpnd());
  5850. IR::Instr * newInstr = IR::Instr::New(Js::OpCode::TEST, instr->m_func);
  5851. newInstr->SetSrc1(dst);
  5852. newInstr->SetSrc2(dst);
  5853. bailOutLabel->InsertBefore(newInstr);
  5854. bailOutLabel->InsertBefore(IR::BranchInstr::New(Js::OpCode::JNE, skipBailOutLabel, instr->m_func));
  5855. // Fast path already checks if s1 >= 0
  5856. if (!fastPath)
  5857. {
  5858. newInstr = IR::Instr::New(Js::OpCode::TEST, instr->m_func);
  5859. newInstr->SetSrc1(src1);
  5860. newInstr->SetSrc2(src1);
  5861. bailOutLabel->InsertBefore(newInstr);
  5862. bailOutLabel->InsertBefore(IR::BranchInstr::New(Js::OpCode::JNSB, skipBailOutLabel, instr->m_func));
  5863. }
  5864. // Fall through to bailOutLabel
  5865. // Lower the instruction
  5866. LowererMDArch::EmitInt4Instr(instr);
  5867. }
  5868. IR::Instr *
  5869. LowererMD::LoadFloatZero(IR::Opnd * opndDst, IR::Instr * instrInsert)
  5870. {
  5871. return IR::Instr::New(Js::OpCode::MOVSD_ZERO, opndDst, instrInsert->m_func);
  5872. }
  5873. IR::Instr *
  5874. LowererMD::LoadFloatValue(IR::Opnd * opndDst, double value, IR::Instr * instrInsert)
  5875. {
  5876. // Floating point zero is a common value to load. Let's use a single memory location instead of allocating new memory for each.
  5877. const bool isFloatZero = value == 0.0 && !Js::JavascriptNumber::IsNegZero(value); // (-0.0 == 0.0) yields true
  5878. IR::Instr * instr;
  5879. if (isFloatZero)
  5880. {
  5881. instr = LoadFloatZero(opndDst, instrInsert);
  5882. }
  5883. else if (opndDst->IsFloat64())
  5884. {
  5885. double *pValue = NativeCodeDataNew(instrInsert->m_func->GetNativeCodeDataAllocator(), double, value);
  5886. IR::Opnd * opnd = IR::MemRefOpnd::New((void*)pValue, TyMachDouble, instrInsert->m_func, IR::AddrOpndKindDynamicDoubleRef);
  5887. instr = IR::Instr::New(LowererMDArch::GetAssignOp(TyMachDouble), opndDst, opnd, instrInsert->m_func);
  5888. }
  5889. else
  5890. {
  5891. Assert(opndDst->IsFloat32());
  5892. float * pValue = NativeCodeDataNew(instrInsert->m_func->GetNativeCodeDataAllocator(), float, (float)value);
  5893. IR::Opnd * opnd = IR::MemRefOpnd::New((void *)pValue, TyFloat32, instrInsert->m_func, IR::AddrOpndKindDynamicFloatRef);
  5894. instr = IR::Instr::New(LowererMDArch::GetAssignOp(TyFloat32), opndDst, opnd, instrInsert->m_func);
  5895. }
  5896. instrInsert->InsertBefore(instr);
  5897. Legalize(instr);
  5898. return instr;
  5899. }
  5900. IR::Instr *
  5901. LowererMD::EnsureAdjacentArgs(IR::Instr * instrArg)
  5902. {
  5903. // Ensure that the arg instructions for a given call site are adjacent.
  5904. // This isn't normally desirable for CQ, but it's required by, for instance, the cloner,
  5905. // which must clone a complete call sequence.
  5906. IR::Opnd * opnd = instrArg->GetSrc2();
  5907. IR::Instr * instrNextArg;
  5908. StackSym * sym;
  5909. AssertMsg(opnd, "opnd");
  5910. while (opnd->IsSymOpnd())
  5911. {
  5912. sym = opnd->AsSymOpnd()->m_sym->AsStackSym();
  5913. IR::Instr * instrNextArg = sym->m_instrDef;
  5914. Assert(instrNextArg);
  5915. instrNextArg->SinkInstrBefore(instrArg);
  5916. instrArg = instrNextArg;
  5917. opnd = instrArg->GetSrc2();
  5918. }
  5919. sym = opnd->AsRegOpnd()->m_sym;
  5920. instrNextArg = sym->m_instrDef;
  5921. Assert(instrNextArg && instrNextArg->m_opcode == Js::OpCode::StartCall);
  5922. // The StartCall can be trivially moved down.
  5923. if (instrNextArg->m_next != instrArg)
  5924. {
  5925. instrNextArg->UnlinkStartCallFromBailOutInfo(instrArg);
  5926. instrNextArg->Unlink();
  5927. instrArg->InsertBefore(instrNextArg);
  5928. }
  5929. return instrNextArg->m_prev;
  5930. }
  5931. #if INT32VAR
  5932. //
  5933. // Convert an int32 to Var representation.
  5934. //
  5935. void LowererMD::GenerateInt32ToVarConversion( IR::Opnd * opndSrc, IR::Instr * insertInstr )
  5936. {
  5937. AssertMsg(TySize[opndSrc->GetType()] == MachPtr, "For this to work it should be a 64-bit register");
  5938. IR::Instr* instr = IR::Instr::New(Js::OpCode::BTS, opndSrc, opndSrc, IR::IntConstOpnd::New(Js::VarTag_Shift, TyInt8, this->m_func), this->m_func);
  5939. insertInstr->InsertBefore(instr);
  5940. }
  5941. //
  5942. // jump to $labelHelper, based on the result of CMP
  5943. //
  5944. void LowererMD::GenerateSmIntTest(IR::Opnd *opndSrc, IR::Instr *insertInstr, IR::LabelInstr *labelHelper, IR::Instr **instrFirst /* = nullptr */, bool fContinueLabel /*= false*/)
  5945. {
  5946. AssertMsg(opndSrc->GetSize() == MachPtr, "64-bit register required");
  5947. IR::Opnd * opndReg = IR::RegOpnd::New(TyMachReg, this->m_func);
  5948. #ifdef SHIFTLOAD
  5949. // s1 = SHLD src1, 16 - Shift top 16-bits of src1 to s1
  5950. IR::Instr* instr = IR::Instr::New(Js::OpCode::SHLD, opndReg, opndSrc, IR::IntConstOpnd::New(16, TyInt8, this->m_func), this->m_func);
  5951. insertInstr->InsertBefore(instr);
  5952. if (instrFirst)
  5953. {
  5954. *instrFirst = instr;
  5955. }
  5956. // CMP s1.i16, AtomTag.i16
  5957. IR::Opnd *opndReg16 = opndReg->Copy(m_func);
  5958. opndReg16->SetType(TyInt16);
  5959. instr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  5960. instr->SetSrc1(opndReg16);
  5961. instr->SetSrc2(IR::IntConstOpnd::New(Js::AtomTag, TyInt16, this->m_func, /* dontEncode = */ true));
  5962. insertInstr->InsertBefore(instr);
  5963. #else
  5964. // s1 = MOV src1 - Move to a temporary
  5965. IR::Instr * instr = IR::Instr::New(Js::OpCode::MOV, opndReg, opndSrc, this->m_func);
  5966. insertInstr->InsertBefore(instr);
  5967. if (instrFirst)
  5968. {
  5969. *instrFirst = instr;
  5970. }
  5971. // s1 = SHR s1, VarTag_Shift
  5972. instr = IR::Instr::New(Js::OpCode::SHR, opndReg, opndReg, IR::IntConstOpnd::New(Js::VarTag_Shift, TyInt8, this->m_func), this->m_func);
  5973. insertInstr->InsertBefore(instr);
  5974. // CMP s1, AtomTag
  5975. instr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  5976. instr->SetSrc1(opndReg);
  5977. instr->SetSrc2(IR::IntConstOpnd::New(Js::AtomTag, TyInt32, this->m_func, /* dontEncode = */ true));
  5978. insertInstr->InsertBefore(instr);
  5979. #endif
  5980. if(fContinueLabel)
  5981. {
  5982. // JEQ $labelHelper
  5983. instr = IR::BranchInstr::New(Js::OpCode::JEQ, labelHelper, this->m_func);
  5984. }
  5985. else
  5986. {
  5987. // JNE $labelHelper
  5988. instr = IR::BranchInstr::New(Js::OpCode::JNE, labelHelper, this->m_func);
  5989. }
  5990. insertInstr->InsertBefore(instr);
  5991. }
  5992. //
  5993. // If lower 32-bits are zero (value is zero), jump to $helper.
  5994. //
  5995. void LowererMD::GenerateTaggedZeroTest( IR::Opnd * opndSrc, IR::Instr * insertInstr, IR::LabelInstr * labelHelper )
  5996. {
  5997. // Cast the var to 32 bit integer.
  5998. if(opndSrc->GetSize() != 4)
  5999. {
  6000. opndSrc = opndSrc->UseWithNewType(TyUint32, this->m_func);
  6001. }
  6002. AssertMsg(TySize[opndSrc->GetType()] == 4, "This technique works only on the 32-bit version");
  6003. // TEST src1, src1
  6004. IR::Instr* instr = IR::Instr::New(Js::OpCode::TEST, this->m_func);
  6005. instr->SetSrc1(opndSrc);
  6006. instr->SetSrc2(opndSrc);
  6007. insertInstr->InsertBefore(instr);
  6008. if(labelHelper != nullptr)
  6009. {
  6010. // JZ $labelHelper
  6011. instr = IR::BranchInstr::New(Js::OpCode::JEQ, labelHelper, this->m_func);
  6012. insertInstr->InsertBefore(instr);
  6013. }
  6014. }
  6015. //
  6016. // If top 16 bits are not zero i.e. it is NOT object, jump to $helper.
  6017. //
  6018. bool LowererMD::GenerateObjectTest(IR::Opnd * opndSrc, IR::Instr * insertInstr, IR::LabelInstr * labelTarget, bool fContinueLabel)
  6019. {
  6020. AssertMsg(opndSrc->GetSize() == MachPtr, "64-bit register required");
  6021. if (opndSrc->IsTaggedValue() && fContinueLabel)
  6022. {
  6023. // Insert delete branch opcode to tell the dbChecks not to assert on the helper label we may fall through into
  6024. IR::Instr *fakeBr = IR::PragmaInstr::New(Js::OpCode::DeletedNonHelperBranch, 0, this->m_func);
  6025. insertInstr->InsertBefore(fakeBr);
  6026. return false;
  6027. }
  6028. else if (opndSrc->IsNotTaggedValue() && !fContinueLabel)
  6029. {
  6030. return false;
  6031. }
  6032. IR::Opnd * opndReg = IR::RegOpnd::New(TyMachReg, this->m_func);
  6033. // s1 = MOV src1 - Move to a temporary
  6034. IR::Instr * instr = IR::Instr::New(Js::OpCode::MOV, opndReg, opndSrc, this->m_func);
  6035. insertInstr->InsertBefore(instr);
  6036. // s1 = SHR s1, VarTag_Shift
  6037. instr = IR::Instr::New(Js::OpCode::SHR, opndReg, opndReg, IR::IntConstOpnd::New(Js::VarTag_Shift, TyInt8, this->m_func), this->m_func);
  6038. insertInstr->InsertBefore(instr);
  6039. if (fContinueLabel)
  6040. {
  6041. // JEQ $labelHelper
  6042. instr = IR::BranchInstr::New(Js::OpCode::JEQ, labelTarget, this->m_func);
  6043. insertInstr->InsertBefore(instr);
  6044. IR::LabelInstr *labelHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
  6045. insertInstr->InsertBefore(labelHelper);
  6046. }
  6047. else
  6048. {
  6049. // JNZ $labelHelper
  6050. instr = IR::BranchInstr::New(Js::OpCode::JNE, labelTarget, this->m_func);
  6051. insertInstr->InsertBefore(instr);
  6052. }
  6053. return true;
  6054. }
  6055. #else
  6056. //
  6057. // Convert an int32 value to a Var.
  6058. //
  6059. void LowererMD::GenerateInt32ToVarConversion( IR::Opnd * opndSrc, IR::Instr * insertInstr )
  6060. {
  6061. // SHL r1, AtomTag
  6062. IR::Instr * instr = IR::Instr::New(Js::OpCode::SHL, opndSrc, opndSrc, IR::IntConstOpnd::New(Js::AtomTag, TyInt32, this->m_func), this->m_func);
  6063. insertInstr->InsertBefore(instr);
  6064. // INC r1
  6065. instr = IR::Instr::New(Js::OpCode::INC, opndSrc, opndSrc, this->m_func);
  6066. insertInstr->InsertBefore(instr);
  6067. }
  6068. //
  6069. // jump to $labelHelper, based on the result of TEST
  6070. //
  6071. void LowererMD::GenerateSmIntTest(IR::Opnd *opndSrc, IR::Instr *insertInstr, IR::LabelInstr *labelHelper, IR::Instr **instrFirst /* = nullptr */, bool fContinueLabel /*= false*/)
  6072. {
  6073. if (opndSrc->IsTaggedInt() && !fContinueLabel)
  6074. {
  6075. return;
  6076. }
  6077. else if (opndSrc->IsNotTaggedValue() && fContinueLabel)
  6078. {
  6079. return;
  6080. }
  6081. // TEST src1, AtomTag
  6082. IR::Instr* instr = IR::Instr::New(Js::OpCode::TEST, this->m_func);
  6083. instr->SetSrc1(opndSrc);
  6084. instr->SetSrc2(IR::IntConstOpnd::New(Js::AtomTag, TyInt8, this->m_func));
  6085. insertInstr->InsertBefore(instr);
  6086. if (instrFirst)
  6087. {
  6088. *instrFirst = instr;
  6089. }
  6090. if(fContinueLabel)
  6091. {
  6092. // JNE $labelHelper
  6093. instr = IR::BranchInstr::New(Js::OpCode::JNE, labelHelper, this->m_func);
  6094. }
  6095. else
  6096. {
  6097. // JEQ $labelHelper
  6098. instr = IR::BranchInstr::New(Js::OpCode::JEQ, labelHelper, this->m_func);
  6099. }
  6100. insertInstr->InsertBefore(instr);
  6101. }
  6102. //
  6103. // If value is zero in tagged int representation, jump to $labelHelper.
  6104. //
  6105. void LowererMD::GenerateTaggedZeroTest( IR::Opnd * opndSrc, IR::Instr * insertInstr, IR::LabelInstr * labelHelper )
  6106. {
  6107. if (opndSrc->IsNotTaggedValue())
  6108. {
  6109. return;
  6110. }
  6111. // CMP src1, AtomTag
  6112. IR::Instr* instr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  6113. instr->SetSrc1(opndSrc);
  6114. instr->SetSrc2(IR::IntConstOpnd::New(Js::AtomTag, TyInt32, this->m_func));
  6115. insertInstr->InsertBefore(instr);
  6116. // JEQ $helper
  6117. if(labelHelper != nullptr)
  6118. {
  6119. // JEQ $labelHelper
  6120. instr = IR::BranchInstr::New(Js::OpCode::JEQ, labelHelper, this->m_func);
  6121. insertInstr->InsertBefore(instr);
  6122. }
  6123. }
  6124. //
  6125. // If not object, jump to $labelHelper.
  6126. //
  6127. bool LowererMD::GenerateObjectTest(IR::Opnd * opndSrc, IR::Instr * insertInstr, IR::LabelInstr * labelTarget, bool fContinueLabel)
  6128. {
  6129. if (opndSrc->IsTaggedInt() && fContinueLabel)
  6130. {
  6131. // Insert delete branch opcode to tell the dbChecks not to assert on this helper label
  6132. IR::Instr *fakeBr = IR::PragmaInstr::New(Js::OpCode::DeletedNonHelperBranch, 0, this->m_func);
  6133. insertInstr->InsertBefore(fakeBr);
  6134. return false;
  6135. }
  6136. else if (opndSrc->IsNotTaggedValue() && !fContinueLabel)
  6137. {
  6138. return false;
  6139. }
  6140. // TEST src1, AtomTag
  6141. IR::Instr* instr = IR::Instr::New(Js::OpCode::TEST, this->m_func);
  6142. instr->SetSrc1(opndSrc);
  6143. instr->SetSrc2(IR::IntConstOpnd::New(Js::AtomTag, TyInt8, this->m_func));
  6144. insertInstr->InsertBefore(instr);
  6145. if (fContinueLabel)
  6146. {
  6147. // JEQ $labelHelper
  6148. instr = IR::BranchInstr::New(Js::OpCode::JEQ, labelTarget, this->m_func);
  6149. insertInstr->InsertBefore(instr);
  6150. IR::LabelInstr *labelHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
  6151. insertInstr->InsertBefore(labelHelper);
  6152. }
  6153. else
  6154. {
  6155. // JNE $labelHelper
  6156. instr = IR::BranchInstr::New(Js::OpCode::JNE, labelTarget, this->m_func);
  6157. insertInstr->InsertBefore(instr);
  6158. }
  6159. return true;
  6160. }
  6161. #endif
  6162. bool LowererMD::GenerateJSBooleanTest(IR::RegOpnd * regSrc, IR::Instr * insertInstr, IR::LabelInstr * labelTarget, bool fContinueLabel)
  6163. {
  6164. IR::Instr* instr;
  6165. if (regSrc->GetValueType().IsBoolean())
  6166. {
  6167. if (fContinueLabel)
  6168. {
  6169. // JMP $labelTarget
  6170. instr = IR::BranchInstr::New(Js::OpCode::JMP, labelTarget, this->m_func);
  6171. insertInstr->InsertBefore(instr);
  6172. #if DBG
  6173. if (labelTarget->isOpHelper)
  6174. {
  6175. labelTarget->m_noHelperAssert = true;
  6176. }
  6177. #endif
  6178. }
  6179. return false;
  6180. }
  6181. // CMP src1, vtable<JavaScriptBoolean>
  6182. instr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  6183. IR::IndirOpnd *vtablePtrOpnd = IR::IndirOpnd::New(regSrc, 0, TyMachPtr, this->m_func);
  6184. instr->SetSrc1(vtablePtrOpnd);
  6185. IR::Opnd *jsBooleanVTable = m_lowerer->LoadVTableValueOpnd(insertInstr, VTableValue::VtableJavascriptBoolean);
  6186. instr->SetSrc2(jsBooleanVTable);
  6187. insertInstr->InsertBefore(instr);
  6188. Legalize(instr);
  6189. if (fContinueLabel)
  6190. {
  6191. // JEQ $labelTarget
  6192. instr = IR::BranchInstr::New(Js::OpCode::JEQ, labelTarget, this->m_func);
  6193. insertInstr->InsertBefore(instr);
  6194. IR::LabelInstr *labelHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
  6195. insertInstr->InsertBefore(labelHelper);
  6196. }
  6197. else
  6198. {
  6199. // JNE $labelTarget
  6200. instr = IR::BranchInstr::New(Js::OpCode::JNE, labelTarget, this->m_func);
  6201. insertInstr->InsertBefore(instr);
  6202. }
  6203. return true;
  6204. }
  6205. #if FLOATVAR
  6206. //
  6207. // If any of the top 14 bits are not set, then the var is not a float value and hence, jump to $labelHelper.
  6208. //
  6209. void LowererMD::GenerateFloatTest(IR::RegOpnd * opndSrc, IR::Instr * insertInstr, IR::LabelInstr* labelHelper, const bool checkForNullInLoopBody)
  6210. {
  6211. if (opndSrc->GetValueType().IsFloat())
  6212. {
  6213. return;
  6214. }
  6215. AssertMsg(opndSrc->GetSize() == MachPtr, "64-bit register required");
  6216. // s1 = MOV src1 - Move to a temporary
  6217. IR::Opnd * opndReg = IR::RegOpnd::New(TyMachReg, this->m_func);
  6218. IR::Instr * instr = IR::Instr::New(Js::OpCode::MOV, opndReg, opndSrc, this->m_func);
  6219. insertInstr->InsertBefore(instr);
  6220. // s1 = SHR s1, 50
  6221. instr = IR::Instr::New(Js::OpCode::SHR, opndReg, opndReg, IR::IntConstOpnd::New(50, TyInt8, this->m_func), this->m_func);
  6222. insertInstr->InsertBefore(instr);
  6223. // JZ $helper
  6224. instr = IR::BranchInstr::New(Js::OpCode::JEQ /* JZ */, labelHelper, this->m_func);
  6225. insertInstr->InsertBefore(instr);
  6226. }
  6227. IR::RegOpnd* LowererMD::CheckFloatAndUntag(IR::RegOpnd * opndSrc, IR::Instr * insertInstr, IR::LabelInstr* labelHelper)
  6228. {
  6229. IR::Opnd* floatTag = IR::AddrOpnd::New((Js::Var)Js::FloatTag_Value, IR::AddrOpndKindConstantVar, this->m_func, /* dontEncode = */ true);
  6230. IR::RegOpnd* regOpndFloatTag = IR::RegOpnd::New(TyUint64, this->m_func);
  6231. // MOV floatTagReg, FloatTag_Value
  6232. IR::Instr* instr = IR::Instr::New(Js::OpCode::MOV, regOpndFloatTag, floatTag, this->m_func);
  6233. insertInstr->InsertBefore(instr);
  6234. if (!opndSrc->GetValueType().IsFloat())
  6235. {
  6236. // TEST s1, floatTagReg
  6237. instr = IR::Instr::New(Js::OpCode::TEST, this->m_func);
  6238. instr->SetSrc1(opndSrc);
  6239. instr->SetSrc2(regOpndFloatTag);
  6240. insertInstr->InsertBefore(instr);
  6241. // JZ $helper
  6242. instr = IR::BranchInstr::New(Js::OpCode::JEQ /* JZ */, labelHelper, this->m_func);
  6243. insertInstr->InsertBefore(instr);
  6244. }
  6245. // untaggedFloat = XOR floatTagReg, s1 // where untaggedFloat == floatTagReg; use floatTagReg temporarily for the untagged float
  6246. IR::RegOpnd* untaggedFloat = regOpndFloatTag;
  6247. instr = IR::Instr::New(Js::OpCode::XOR, untaggedFloat, regOpndFloatTag, opndSrc, this->m_func);
  6248. insertInstr->InsertBefore(instr);
  6249. IR::RegOpnd *floatReg = IR::RegOpnd::New(TyMachDouble, this->m_func);
  6250. instr = IR::Instr::New(Js::OpCode::MOVD, floatReg, untaggedFloat, this->m_func);
  6251. insertInstr->InsertBefore(instr);
  6252. return floatReg;
  6253. }
  6254. #else
  6255. void LowererMD::GenerateFloatTest(IR::RegOpnd * opndSrc, IR::Instr * insertInstr, IR::LabelInstr* labelHelper, const bool checkForNullInLoopBody)
  6256. {
  6257. if (opndSrc->GetValueType().IsFloat())
  6258. {
  6259. return;
  6260. }
  6261. AssertMsg(opndSrc->GetSize() == MachPtr, "64-bit register required");
  6262. if(checkForNullInLoopBody && m_func->IsLoopBody())
  6263. {
  6264. // It's possible that the value was determined dead by the jitted function and was not restored. The jitted loop
  6265. // body may not realize that it's dead and may try to use it. Check for null in loop bodies.
  6266. // test src1, src1
  6267. // jz $helper (bail out)
  6268. m_lowerer->InsertCompareBranch(
  6269. opndSrc,
  6270. IR::AddrOpnd::NewNull(m_func),
  6271. Js::OpCode::BrEq_A,
  6272. labelHelper,
  6273. insertInstr);
  6274. }
  6275. IR::Instr* instr = IR::Instr::New(Js::OpCode::CMP, insertInstr->m_func);
  6276. instr->SetSrc1(IR::IndirOpnd::New(opndSrc, 0, TyMachPtr, insertInstr->m_func));
  6277. instr->SetSrc2(m_lowerer->LoadVTableValueOpnd(insertInstr, VTableValue::VtableJavascriptNumber));
  6278. insertInstr->InsertBefore(instr);
  6279. // JNZ $helper
  6280. instr = IR::BranchInstr::New(Js::OpCode::JNE /* JZ */, labelHelper, this->m_func);
  6281. insertInstr->InsertBefore(instr);
  6282. }
  6283. #endif
  6284. #if DBG
  6285. //
  6286. // Helps in debugging of fast paths.
  6287. //
  6288. void LowererMD::GenerateDebugBreak( IR::Instr * insertInstr )
  6289. {
  6290. // int 3
  6291. IR::Instr *int3 = IR::Instr::New(Js::OpCode::INT, insertInstr->m_func);
  6292. int3->SetSrc1(IR::IntConstOpnd::New(3, TyInt32, insertInstr->m_func));
  6293. insertInstr->InsertBefore(int3);
  6294. }
  6295. #endif
  6296. IR::Instr *
  6297. LowererMD::LoadStackAddress(StackSym *sym, IR::RegOpnd *optionalDstOpnd /* = nullptr */)
  6298. {
  6299. IR::RegOpnd * regDst = optionalDstOpnd != nullptr ? optionalDstOpnd : IR::RegOpnd::New(TyMachReg, this->m_func);
  6300. IR::SymOpnd * symSrc = IR::SymOpnd::New(sym, TyMachPtr, this->m_func);
  6301. IR::Instr * lea = IR::Instr::New(Js::OpCode::LEA, regDst, symSrc, this->m_func);
  6302. return lea;
  6303. }
  6304. template <bool verify>
  6305. void
  6306. LowererMD::MakeDstEquSrc1(IR::Instr *const instr)
  6307. {
  6308. Assert(instr);
  6309. Assert(instr->IsLowered());
  6310. Assert(instr->GetDst());
  6311. Assert(instr->GetSrc1());
  6312. if(instr->GetDst()->IsEqual(instr->GetSrc1()))
  6313. {
  6314. return;
  6315. }
  6316. if (verify)
  6317. {
  6318. AssertMsg(false, "Missing legalization");
  6319. return;
  6320. }
  6321. if(instr->GetSrc2() && instr->GetDst()->IsEqual(instr->GetSrc2()))
  6322. {
  6323. switch(instr->m_opcode)
  6324. {
  6325. case Js::OpCode::Add_I4:
  6326. case Js::OpCode::Mul_I4:
  6327. case Js::OpCode::Or_I4:
  6328. case Js::OpCode::Xor_I4:
  6329. case Js::OpCode::And_I4:
  6330. case Js::OpCode::Add_Ptr:
  6331. case Js::OpCode::ADD:
  6332. case Js::OpCode::IMUL2:
  6333. case Js::OpCode::OR:
  6334. case Js::OpCode::XOR:
  6335. case Js::OpCode::AND:
  6336. case Js::OpCode::ADDSD:
  6337. case Js::OpCode::MULSD:
  6338. case Js::OpCode::ADDSS:
  6339. case Js::OpCode::MULSS:
  6340. case Js::OpCode::ADDPS:
  6341. // For (a = b & a), generate (a = a & b)
  6342. instr->SwapOpnds();
  6343. return;
  6344. }
  6345. // For (a = b - a), generate (c = a; a = b - c) and fall through
  6346. ChangeToAssign(instr->HoistSrc2(Js::OpCode::Ld_A));
  6347. }
  6348. // For (a = b - c), generate (a = b; a = a - c)
  6349. IR::Instr *const mov = IR::Instr::New(Js::OpCode::Ld_A, instr->GetDst(), instr->UnlinkSrc1(), instr->m_func);
  6350. instr->InsertBefore(mov);
  6351. ChangeToAssign(mov);
  6352. instr->SetSrc1(instr->GetDst());
  6353. }
  6354. void
  6355. LowererMD::EmitPtrInstr(IR::Instr *instr)
  6356. {
  6357. LowererMDArch::EmitPtrInstr(instr);
  6358. }
  6359. void
  6360. LowererMD::EmitInt4Instr(IR::Instr *instr)
  6361. {
  6362. LowererMDArch::EmitInt4Instr(instr);
  6363. }
  6364. void
  6365. LowererMD::EmitLoadVar(IR::Instr *instrLoad, bool isFromUint32, bool isHelper)
  6366. {
  6367. lowererMDArch.EmitLoadVar(instrLoad, isFromUint32, isHelper);
  6368. }
  6369. bool
  6370. LowererMD::EmitLoadInt32(IR::Instr *instrLoad)
  6371. {
  6372. return lowererMDArch.EmitLoadInt32(instrLoad);
  6373. }
  6374. void
  6375. LowererMD::EmitIntToFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert)
  6376. {
  6377. this->lowererMDArch.EmitIntToFloat(dst, src, instrInsert);
  6378. }
  6379. void
  6380. LowererMD::EmitUIntToFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert)
  6381. {
  6382. this->lowererMDArch.EmitUIntToFloat(dst, src, instrInsert);
  6383. }
  6384. void
  6385. LowererMD::EmitFloat32ToFloat64(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert)
  6386. {
  6387. // We should only generate this if sse2 is available
  6388. Assert(AutoSystemInfo::Data.SSE2Available());
  6389. Assert(dst->IsRegOpnd() && dst->IsFloat64());
  6390. Assert(src->IsRegOpnd() && src->GetType() == TyFloat32);
  6391. instrInsert->InsertBefore(IR::Instr::New(Js::OpCode::CVTSS2SD, dst, src, this->m_func));
  6392. }
  6393. void
  6394. LowererMD::EmitNon32BitOvfCheck(IR::Instr *instr, IR::Instr *insertInstr, IR::LabelInstr* bailOutLabel)
  6395. {
  6396. AssertMsg(instr->m_opcode == Js::OpCode::IMUL, "IMUL should be used to check for non-32 bit overflow check on x86.");
  6397. IR::RegOpnd *edxSym = IR::RegOpnd::New(TyInt32, instr->m_func);
  6398. #ifdef _M_IX86
  6399. edxSym->SetReg(RegEDX);
  6400. #else
  6401. edxSym->SetReg(RegRDX);
  6402. #endif
  6403. // dummy def for edx to force RegAlloc to generate a lifetime. This is removed later by the Peeps phase.
  6404. IR::Instr *newInstr = IR::Instr::New(Js::OpCode::NOP, edxSym, instr->m_func);
  6405. insertInstr->InsertBefore(newInstr);
  6406. IR::RegOpnd *temp = IR::RegOpnd::New(TyInt32, instr->m_func);
  6407. Assert(instr->ignoreOverflowBitCount > 32);
  6408. uint8 shamt = 64 - instr->ignoreOverflowBitCount;
  6409. // MOV temp, edx
  6410. newInstr = IR::Instr::New(Js::OpCode::MOV, temp, edxSym, instr->m_func);
  6411. insertInstr->InsertBefore(newInstr);
  6412. // SHL temp, shamt
  6413. newInstr = IR::Instr::New(Js::OpCode::SHL, temp, temp, IR::IntConstOpnd::New(shamt, TyInt8, instr->m_func, true), instr->m_func);
  6414. insertInstr->InsertBefore(newInstr);
  6415. // SAR temp, shamt
  6416. newInstr = IR::Instr::New(Js::OpCode::SAR, temp, temp, IR::IntConstOpnd::New(shamt, TyInt8, instr->m_func, true), instr->m_func);
  6417. insertInstr->InsertBefore(newInstr);
  6418. // CMP temp, edx
  6419. newInstr = IR::Instr::New(Js::OpCode::CMP, instr->m_func);
  6420. newInstr->SetSrc1(temp);
  6421. newInstr->SetSrc2(edxSym);
  6422. insertInstr->InsertBefore(newInstr);
  6423. // JNE
  6424. Lowerer::InsertBranch(Js::OpCode::JNE, false, bailOutLabel, insertInstr);
  6425. }
  6426. void LowererMD::ConvertFloatToInt32(IR::Opnd* intOpnd, IR::Opnd* floatOpnd, IR::LabelInstr * labelHelper, IR::LabelInstr * labelDone, IR::Instr * instInsert)
  6427. {
  6428. UNREFERENCED_PARAMETER(labelHelper); // used on ARM
  6429. #if defined(_M_IX86)
  6430. // We should only generate this if sse2 is available
  6431. Assert(AutoSystemInfo::Data.SSE2Available());
  6432. #endif
  6433. Assert((floatOpnd->IsRegOpnd() && floatOpnd->IsFloat()) || (floatOpnd->IsIndirOpnd() && floatOpnd->GetType() == TyMachDouble));
  6434. Assert(intOpnd->GetType() == TyInt32);
  6435. IR::Instr* instr;
  6436. {
  6437. #ifdef _M_X64
  6438. IR::Opnd* dstOpnd = IR::RegOpnd::New(TyInt64, m_func);
  6439. #else
  6440. IR::Opnd* dstOpnd = intOpnd;
  6441. #endif
  6442. // CVTTSD2SI dst, floatOpnd
  6443. IR::Instr* instr = IR::Instr::New(floatOpnd->IsFloat64() ? Js::OpCode::CVTTSD2SI : Js::OpCode::CVTTSS2SI, dstOpnd, floatOpnd, this->m_func);
  6444. instInsert->InsertBefore(instr);
  6445. // CMP dst, 0x80000000 {0x8000000000000000 on x64} -- Check for overflow
  6446. instr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  6447. instr->SetSrc1(dstOpnd);
  6448. instr->SetSrc2(IR::AddrOpnd::New((Js::Var)MachSignBit, IR::AddrOpndKindConstant, this->m_func, true));
  6449. instInsert->InsertBefore(instr);
  6450. Legalize(instr);
  6451. #ifdef _M_X64
  6452. // Truncate to int32 for x64. We still need to go to helper though if we have int64 overflow.
  6453. // MOV_TRUNC intOpnd, tmpOpnd
  6454. instr = IR::Instr::New(Js::OpCode::MOV_TRUNC, intOpnd, dstOpnd, this->m_func);
  6455. instInsert->InsertBefore(instr);
  6456. #endif
  6457. }
  6458. // JNE $done
  6459. instr = IR::BranchInstr::New(Js::OpCode::JNE, labelDone, this->m_func);
  6460. instInsert->InsertBefore(instr);
  6461. // It does overflow - Let's try using FISTTP which uses 64 bits and is relevant only for x86
  6462. // but requires going to memory and should only be used in overflow scenarios
  6463. #ifdef _M_IX86
  6464. if (AutoSystemInfo::Data.SSE3Available())
  6465. {
  6466. IR::Opnd* floatStackOpnd;
  6467. StackSym* tempSymDouble = this->m_func->tempSymDouble;
  6468. if (!tempSymDouble)
  6469. {
  6470. this->m_func->tempSymDouble = StackSym::New(TyFloat64, this->m_func);
  6471. this->m_func->StackAllocate(this->m_func->tempSymDouble, MachDouble);
  6472. tempSymDouble = this->m_func->tempSymDouble;
  6473. }
  6474. IR::Opnd * float64Opnd;
  6475. if (floatOpnd->IsFloat32())
  6476. {
  6477. float64Opnd = IR::RegOpnd::New(TyFloat64, m_func);
  6478. IR::Instr* instr = IR::Instr::New(Js::OpCode::CVTSS2SD, float64Opnd, floatOpnd, m_func);
  6479. instInsert->InsertBefore(instr);
  6480. }
  6481. else
  6482. {
  6483. float64Opnd = floatOpnd;
  6484. }
  6485. if (float64Opnd->IsRegOpnd())
  6486. {
  6487. floatStackOpnd = IR::SymOpnd::New(tempSymDouble, TyMachDouble, m_func);
  6488. IR::Instr* instr = IR::Instr::New(Js::OpCode::MOVSD, floatStackOpnd, float64Opnd, m_func);
  6489. instInsert->InsertBefore(instr);
  6490. }
  6491. else
  6492. {
  6493. floatStackOpnd = float64Opnd;
  6494. }
  6495. // FLD [tmpDouble]
  6496. instr = IR::Instr::New(Js::OpCode::FLD, floatStackOpnd, floatStackOpnd, m_func);
  6497. instInsert->InsertBefore(instr);
  6498. if (!float64Opnd->IsRegOpnd())
  6499. {
  6500. floatStackOpnd = IR::SymOpnd::New(tempSymDouble, TyMachDouble, m_func);
  6501. }
  6502. // FISTTP qword ptr [tmpDouble]
  6503. instr = IR::Instr::New(Js::OpCode::FISTTP, floatStackOpnd, m_func);
  6504. instInsert->InsertBefore(instr);
  6505. StackSym *intSym = StackSym::New(TyInt32, m_func);
  6506. intSym->m_offset = tempSymDouble->m_offset;
  6507. intSym->m_allocated = true;
  6508. IR::Opnd* lowerBitsOpnd = IR::SymOpnd::New(intSym, TyInt32, m_func);
  6509. // MOV dst, dword ptr [tmpDouble]
  6510. instr = IR::Instr::New(Js::OpCode::MOV, intOpnd, lowerBitsOpnd, m_func);
  6511. instInsert->InsertBefore(instr);
  6512. // TEST dst, dst -- Check for overflow
  6513. instr = IR::Instr::New(Js::OpCode::TEST, this->m_func);
  6514. instr->SetSrc1(intOpnd);
  6515. instr->SetSrc2(intOpnd);
  6516. instInsert->InsertBefore(instr);
  6517. instr = IR::BranchInstr::New(Js::OpCode::JNE, labelDone, this->m_func);
  6518. instInsert->InsertBefore(instr);
  6519. // CMP [tmpDouble - 4], 0x80000000
  6520. StackSym* higherBitsSym = StackSym::New(TyInt32, m_func);
  6521. higherBitsSym->m_offset = tempSymDouble->m_offset + 4;
  6522. higherBitsSym->m_allocated = true;
  6523. instr = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  6524. instr->SetSrc1(IR::SymOpnd::New(higherBitsSym, TyInt32, m_func));
  6525. instr->SetSrc2(IR::IntConstOpnd::New(0x80000000, TyInt32, this->m_func, true));
  6526. instInsert->InsertBefore(instr);
  6527. instr = IR::BranchInstr::New(Js::OpCode::JNE, labelDone, this->m_func);
  6528. instInsert->InsertBefore(instr);
  6529. }
  6530. #endif
  6531. }
  6532. IR::Instr *
  6533. LowererMD::InsertConvertFloat64ToInt32(const RoundMode roundMode, IR::Opnd *const dst, IR::Opnd *const src, IR::Instr *const insertBeforeInstr)
  6534. {
  6535. Assert(dst);
  6536. Assert(dst->IsInt32());
  6537. Assert(src);
  6538. Assert(src->IsFloat64());
  6539. Assert(insertBeforeInstr);
  6540. // The caller is expected to check for overflow. To have that work be done automatically, use LowererMD::EmitFloatToInt.
  6541. Func *const func = insertBeforeInstr->m_func;
  6542. IR::AutoReuseOpnd autoReuseSrcPlusHalf;
  6543. IR::Instr *instr = nullptr;
  6544. switch (roundMode)
  6545. {
  6546. case RoundModeTowardInteger:
  6547. {
  6548. // Conversion with rounding towards nearest integer is not supported by the architecture. Add 0.5 and do a
  6549. // round-toward-zero conversion instead.
  6550. IR::RegOpnd *const srcPlusHalf = IR::RegOpnd::New(TyFloat64, func);
  6551. autoReuseSrcPlusHalf.Initialize(srcPlusHalf, func);
  6552. Lowerer::InsertAdd(
  6553. false /* needFlags */,
  6554. srcPlusHalf,
  6555. src,
  6556. IR::MemRefOpnd::New((double*)&(Js::JavascriptNumber::k_PointFive), TyFloat64, func,
  6557. IR::AddrOpndKindDynamicDoubleRef),
  6558. insertBeforeInstr);
  6559. instr = IR::Instr::New(LowererMD::MDConvertFloat64ToInt32Opcode(RoundModeTowardZero), dst, srcPlusHalf, func);
  6560. insertBeforeInstr->InsertBefore(instr);
  6561. LowererMD::Legalize(instr);
  6562. return instr;
  6563. }
  6564. case RoundModeHalfToEven:
  6565. {
  6566. instr = IR::Instr::New(LowererMD::MDConvertFloat64ToInt32Opcode(RoundModeHalfToEven), dst, src, func);
  6567. insertBeforeInstr->InsertBefore(instr);
  6568. LowererMD::Legalize(instr);
  6569. return instr;
  6570. }
  6571. default:
  6572. AssertMsg(0, "RoundMode not supported.");
  6573. return nullptr;
  6574. }
  6575. }
  6576. void
  6577. LowererMD::EmitFloatToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert)
  6578. {
  6579. #ifdef _M_IX86
  6580. // We should only generate this if sse2 is available
  6581. Assert(AutoSystemInfo::Data.SSE2Available());
  6582. #endif
  6583. IR::LabelInstr *labelDone = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  6584. IR::LabelInstr *labelHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
  6585. IR::Instr *instr;
  6586. ConvertFloatToInt32(dst, src, labelHelper, labelDone, instrInsert);
  6587. // $Helper
  6588. instrInsert->InsertBefore(labelHelper);
  6589. IR::Opnd * arg = src;
  6590. if (src->IsFloat32())
  6591. {
  6592. arg = IR::RegOpnd::New(TyFloat64, m_func);
  6593. EmitFloat32ToFloat64(arg, src, instrInsert);
  6594. }
  6595. // dst = ToInt32Core(src);
  6596. LoadDoubleHelperArgument(instrInsert, arg);
  6597. instr = IR::Instr::New(Js::OpCode::CALL, dst, this->m_func);
  6598. instrInsert->InsertBefore(instr);
  6599. this->ChangeToHelperCall(instr, IR::HelperConv_ToInt32Core);
  6600. // $Done
  6601. instrInsert->InsertBefore(labelDone);
  6602. }
  6603. void
  6604. LowererMD::EmitLoadVarNoCheck(IR::RegOpnd * dst, IR::RegOpnd * src, IR::Instr *instrLoad, bool isFromUint32, bool isHelper)
  6605. {
  6606. #ifdef _M_IX86
  6607. if (!AutoSystemInfo::Data.SSE2Available())
  6608. {
  6609. IR::JnHelperMethod helperMethod;
  6610. // PUSH &floatTemp
  6611. IR::Opnd *tempOpnd;
  6612. if (instrLoad->dstIsTempNumber)
  6613. {
  6614. helperMethod = isFromUint32 ? IR::HelperOp_UInt32ToAtomInPlace : IR::HelperOp_Int32ToAtomInPlace;
  6615. // Use the original dst to get the temp number sym
  6616. StackSym * tempNumberSym = this->m_lowerer->GetTempNumberSym(instrLoad->GetDst(), instrLoad->dstIsTempNumberTransferred);
  6617. IR::Instr *load = this->LoadStackAddress(tempNumberSym);
  6618. instrLoad->InsertBefore(load);
  6619. tempOpnd = load->GetDst();
  6620. this->LoadHelperArgument(instrLoad, tempOpnd);
  6621. }
  6622. else
  6623. {
  6624. helperMethod = isFromUint32 ? IR::HelperOp_UInt32ToAtom : IR::HelperOp_Int32ToAtom;
  6625. }
  6626. // PUSH memContext
  6627. this->m_lowerer->LoadScriptContext(instrLoad);
  6628. // PUSH s1
  6629. this->LoadHelperArgument(instrLoad, src);
  6630. // dst = ToVar()
  6631. IR::Instr * instr = IR::Instr::New(Js::OpCode::Call, dst,
  6632. IR::HelperCallOpnd::New(helperMethod, this->m_func), this->m_func);
  6633. instrLoad->InsertBefore(instr);
  6634. this->LowerCall(instr, 0);
  6635. return;
  6636. }
  6637. #endif
  6638. IR::RegOpnd * floatReg = IR::RegOpnd::New(TyFloat64, this->m_func);
  6639. if (isFromUint32)
  6640. {
  6641. this->EmitUIntToFloat(floatReg, src, instrLoad);
  6642. }
  6643. else
  6644. {
  6645. this->EmitIntToFloat(floatReg, src, instrLoad);
  6646. }
  6647. this->SaveDoubleToVar(dst, floatReg, instrLoad, instrLoad, isHelper);
  6648. }
  6649. IR::Instr *
  6650. LowererMD::LowerGetCachedFunc(IR::Instr *instr)
  6651. {
  6652. // src1 is an ActivationObjectEx, and we want to get the function object identified by the index (src2)
  6653. // dst = MOV (src1)->GetFuncCacheEntry(src2)->func
  6654. //
  6655. // => [src1 + (offsetof(src1, cache) + (src2 * sizeof(FuncCacheEntry)) + offsetof(FuncCacheEntry, func))]
  6656. IR::IntConstOpnd *src2Opnd = instr->UnlinkSrc2()->AsIntConstOpnd();
  6657. IR::RegOpnd *src1Opnd = instr->UnlinkSrc1()->AsRegOpnd();
  6658. instr->m_opcode = Js::OpCode::MOV;
  6659. IntConstType offset = (src2Opnd->GetValue() * sizeof(Js::FuncCacheEntry)) + Js::ActivationObjectEx::GetOffsetOfCache() + offsetof(Js::FuncCacheEntry, func);
  6660. Assert(Math::FitsInDWord(offset));
  6661. instr->SetSrc1(IR::IndirOpnd::New(src1Opnd, (int32)offset, TyVar, this->m_func));
  6662. src2Opnd->Free(this->m_func);
  6663. return instr->m_prev;
  6664. }
  6665. IR::Instr *
  6666. LowererMD::LowerCommitScope(IR::Instr *instrCommit)
  6667. {
  6668. IR::Instr *instrPrev = instrCommit->m_prev;
  6669. IR::RegOpnd *baseOpnd = instrCommit->UnlinkSrc1()->AsRegOpnd();
  6670. IR::Opnd *opnd;
  6671. IR::Instr * insertInstr = instrCommit->m_next;
  6672. // Write undef to all the local var slots.
  6673. opnd = IR::IndirOpnd::New(baseOpnd, Js::ActivationObjectEx::GetOffsetOfCommitFlag(), TyInt8, this->m_func);
  6674. instrCommit->SetDst(opnd);
  6675. instrCommit->SetSrc1(IR::IntConstOpnd::New(1, TyInt8, this->m_func));
  6676. IR::IntConstOpnd *intConstOpnd = instrCommit->UnlinkSrc2()->AsIntConstOpnd();
  6677. LowererMD::ChangeToAssign(instrCommit);
  6678. const Js::PropertyIdArray *propIds = Js::ByteCodeReader::ReadPropertyIdArray(intConstOpnd->AsUint32(), instrCommit->m_func->GetJnFunction());
  6679. intConstOpnd->Free(this->m_func);
  6680. uint firstVarSlot = (uint)Js::ActivationObjectEx::GetFirstVarSlot(propIds);
  6681. if (firstVarSlot < propIds->count)
  6682. {
  6683. IR::RegOpnd *undefOpnd = IR::RegOpnd::New(TyMachReg, this->m_func);
  6684. LowererMD::CreateAssign(undefOpnd, m_lowerer->LoadLibraryValueOpnd(insertInstr, LibraryValue::ValueUndefined), insertInstr);
  6685. IR::RegOpnd *slotBaseOpnd = IR::RegOpnd::New(TyMachReg, this->m_func);
  6686. // Load a pointer to the aux slots. We assume that all ActivationObject's have only aux slots.
  6687. opnd = IR::IndirOpnd::New(baseOpnd, Js::DynamicObject::GetOffsetOfAuxSlots(), TyMachReg, this->m_func);
  6688. this->CreateAssign(slotBaseOpnd, opnd, insertInstr);
  6689. for (uint i = firstVarSlot; i < propIds->count; i++)
  6690. {
  6691. opnd = IR::IndirOpnd::New(slotBaseOpnd, i << this->GetDefaultIndirScale(), TyMachReg, this->m_func);
  6692. this->CreateAssign(opnd, undefOpnd, insertInstr);
  6693. }
  6694. }
  6695. return instrPrev;
  6696. }
  6697. void
  6698. LowererMD::ImmedSrcToReg(IR::Instr * instr, IR::Opnd * newOpnd, int srcNum)
  6699. {
  6700. if (srcNum == 2)
  6701. {
  6702. instr->SetSrc2(newOpnd);
  6703. }
  6704. else
  6705. {
  6706. Assert(srcNum == 1);
  6707. instr->SetSrc1(newOpnd);
  6708. }
  6709. }
  6710. IR::LabelInstr *
  6711. LowererMD::GetBailOutStackRestoreLabel(BailOutInfo * bailOutInfo, IR::LabelInstr * exitTargetInstr)
  6712. {
  6713. return lowererMDArch.GetBailOutStackRestoreLabel(bailOutInfo, exitTargetInstr);
  6714. }
  6715. StackSym *
  6716. LowererMD::GetImplicitParamSlotSym(Js::ArgSlot argSlot)
  6717. {
  6718. return GetImplicitParamSlotSym(argSlot, this->m_func);
  6719. }
  6720. StackSym *
  6721. LowererMD::GetImplicitParamSlotSym(Js::ArgSlot argSlot, Func * func)
  6722. {
  6723. // Stack looks like (EBP chain)+0, (return addr)+4, (function object)+8, (arg count)+12, (this)+16, actual args
  6724. // Pass in the EBP+8 to start at the function object, the start of the implicit param slots
  6725. StackSym * stackSym = StackSym::NewParamSlotSym(argSlot, func);
  6726. func->SetArgOffset(stackSym, (2 + argSlot) * MachPtr);
  6727. return stackSym;
  6728. }
  6729. bool LowererMD::GenerateFastAnd(IR::Instr * instrAnd)
  6730. {
  6731. return this->lowererMDArch.GenerateFastAnd(instrAnd);
  6732. }
  6733. bool LowererMD::GenerateFastXor(IR::Instr * instrXor)
  6734. {
  6735. return this->lowererMDArch.GenerateFastXor(instrXor);
  6736. }
  6737. bool LowererMD::GenerateFastOr(IR::Instr * instrOr)
  6738. {
  6739. return this->lowererMDArch.GenerateFastOr(instrOr);
  6740. }
  6741. bool LowererMD::GenerateFastNot(IR::Instr * instrNot)
  6742. {
  6743. return this->lowererMDArch.GenerateFastNot(instrNot);
  6744. }
  6745. bool LowererMD::GenerateFastShiftLeft(IR::Instr * instrShift)
  6746. {
  6747. return this->lowererMDArch.GenerateFastShiftLeft(instrShift);
  6748. }
  6749. bool LowererMD::GenerateFastShiftRight(IR::Instr * instrShift)
  6750. {
  6751. return this->lowererMDArch.GenerateFastShiftRight(instrShift);
  6752. }
  6753. void LowererMD::GenerateIsDynamicObject(IR::RegOpnd *regOpnd, IR::Instr *insertInstr, IR::LabelInstr *labelHelper, bool fContinueLabel)
  6754. {
  6755. // CMP [srcReg], Js::DynamicObject::`vtable'
  6756. {
  6757. IR::Instr *cmp = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  6758. cmp->SetSrc1(IR::IndirOpnd::New(regOpnd, 0, TyMachPtr, m_func));
  6759. cmp->SetSrc2(m_lowerer->LoadVTableValueOpnd(insertInstr, VTableValue::VtableDynamicObject));
  6760. insertInstr->InsertBefore(cmp);
  6761. Legalize(cmp);
  6762. }
  6763. if (fContinueLabel)
  6764. {
  6765. // JEQ $fallThough
  6766. IR::Instr * jne = IR::BranchInstr::New(Js::OpCode::JEQ, labelHelper, this->m_func);
  6767. insertInstr->InsertBefore(jne);
  6768. }
  6769. else
  6770. {
  6771. // JNE $helper
  6772. IR::Instr * jne = IR::BranchInstr::New(Js::OpCode::JNE, labelHelper, this->m_func);
  6773. insertInstr->InsertBefore(jne);
  6774. }
  6775. }
  6776. void LowererMD::GenerateIsRecyclableObject(IR::RegOpnd *regOpnd, IR::Instr *insertInstr, IR::LabelInstr *labelHelper, bool checkObjectAndDynamicObject)
  6777. {
  6778. // CMP [srcReg], Js::DynamicObject::`vtable'
  6779. // JEQ $fallThough
  6780. // MOV r1, [src1 + offset(type)] -- get the type id
  6781. // MOV r1, [r1 + offset(typeId)]
  6782. // ADD r1, ~TypeIds_LastJavascriptPrimitiveType -- if (typeId > TypeIds_LastJavascriptPrimitiveType && typeId <= TypeIds_LastTrueJavascriptObjectType)
  6783. // CMP r1, (TypeIds_LastTrueJavascriptObjectType - TypeIds_LastJavascriptPrimitiveType - 1)
  6784. // JA $helper
  6785. //fallThrough:
  6786. IR::LabelInstr *labelFallthrough = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  6787. if (checkObjectAndDynamicObject)
  6788. {
  6789. if (!regOpnd->IsNotTaggedValue())
  6790. {
  6791. GenerateObjectTest(regOpnd, insertInstr, labelHelper);
  6792. }
  6793. this->GenerateIsDynamicObject(regOpnd, insertInstr, labelFallthrough, true);
  6794. }
  6795. IR::RegOpnd * typeRegOpnd = IR::RegOpnd::New(TyMachReg, this->m_func);
  6796. IR::RegOpnd * typeIdRegOpnd = IR::RegOpnd::New(TyInt32, this->m_func);
  6797. // MOV r1, [src1 + offset(type)]
  6798. {
  6799. IR::IndirOpnd * indirOpnd = IR::IndirOpnd::New(regOpnd, Js::RecyclableObject::GetOffsetOfType(), TyMachReg, this->m_func);
  6800. IR::Instr * mov = IR::Instr::New(Js::OpCode::MOV, typeRegOpnd, indirOpnd, this->m_func);
  6801. insertInstr->InsertBefore(mov);
  6802. }
  6803. // MOV r1, [r1 + offset(typeId)]
  6804. {
  6805. IR::IndirOpnd * indirOpnd = IR::IndirOpnd::New(typeRegOpnd, Js::Type::GetOffsetOfTypeId(), TyInt32, this->m_func);
  6806. IR::Instr * mov = IR::Instr::New(Js::OpCode::MOV, typeIdRegOpnd, indirOpnd, this->m_func);
  6807. insertInstr->InsertBefore(mov);
  6808. }
  6809. // ADD r1, ~TypeIds_LastJavascriptPrimitiveType
  6810. {
  6811. IR::Instr * add = IR::Instr::New(Js::OpCode::ADD, typeIdRegOpnd, typeIdRegOpnd, IR::IntConstOpnd::New(~Js::TypeIds_LastJavascriptPrimitiveType, TyInt32, this->m_func, true), this->m_func);
  6812. insertInstr->InsertBefore(add);
  6813. }
  6814. // CMP r1, (TypeIds_LastTrueJavascriptObjectType - TypeIds_LastJavascriptPrimitiveType - 1)
  6815. {
  6816. IR::Instr * cmp = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  6817. cmp->SetSrc1(typeIdRegOpnd);
  6818. cmp->SetSrc2(IR::IntConstOpnd::New(Js::TypeIds_LastTrueJavascriptObjectType - Js::TypeIds_LastJavascriptPrimitiveType - 1, TyInt32, this->m_func));
  6819. insertInstr->InsertBefore(cmp);
  6820. }
  6821. // JA $helper
  6822. {
  6823. IR::Instr * jbe = IR::BranchInstr::New(Js::OpCode::JA, labelHelper, this->m_func);
  6824. insertInstr->InsertBefore(jbe);
  6825. }
  6826. // $fallThrough
  6827. insertInstr->InsertBefore(labelFallthrough);
  6828. }
  6829. bool
  6830. LowererMD::GenerateLdThisCheck(IR::Instr * instr)
  6831. {
  6832. //
  6833. // If not an recyclable object, jump to $helper
  6834. // MOV dst, src1 -- return the object itself
  6835. // JMP $fallthrough
  6836. // $helper:
  6837. // (caller generates helper call)
  6838. // $fallthrough:
  6839. //
  6840. IR::RegOpnd * src1 = instr->GetSrc1()->AsRegOpnd();
  6841. IR::LabelInstr * helper = IR::LabelInstr::New(Js::OpCode::Label, m_func, true);
  6842. IR::LabelInstr * fallthrough = IR::LabelInstr::New(Js::OpCode::Label, m_func);
  6843. this->GenerateIsRecyclableObject(src1, instr, helper);
  6844. // MOV dst, src1
  6845. if (instr->GetDst() && !instr->GetDst()->IsEqual(src1))
  6846. {
  6847. IR::Instr * mov = IR::Instr::New(Js::OpCode::MOV, instr->GetDst(), src1, this->m_func);
  6848. instr->InsertBefore(mov);
  6849. }
  6850. // JMP $fallthrough
  6851. {
  6852. IR::Instr * jmp = IR::BranchInstr::New(Js::OpCode::JMP, fallthrough, this->m_func);
  6853. instr->InsertBefore(jmp);
  6854. }
  6855. // $helper:
  6856. // (caller generates helper call)
  6857. // $fallthrough:
  6858. instr->InsertBefore(helper);
  6859. instr->InsertAfter(fallthrough);
  6860. return true;
  6861. }
  6862. //
  6863. // TEST src, Js::AtomTag
  6864. // JNE $done
  6865. // MOV typeReg, objectSrc + offsetof(RecyclableObject::type)
  6866. // CMP [typeReg + offsetof(Type::typeid)], TypeIds_ActivationObject
  6867. // JEQ $helper
  6868. // $done:
  6869. // MOV dst, src
  6870. // JMP $fallthru
  6871. // helper:
  6872. // MOV dst, undefined
  6873. // $fallthru:
  6874. bool
  6875. LowererMD::GenerateLdThisStrict(IR::Instr* instr)
  6876. {
  6877. IR::RegOpnd * src1 = instr->GetSrc1()->AsRegOpnd();
  6878. IR::RegOpnd * typeReg = IR::RegOpnd::New(TyMachReg, this->m_func);
  6879. IR::LabelInstr * done = IR::LabelInstr::New(Js::OpCode::Label, m_func);
  6880. IR::LabelInstr * fallthru = IR::LabelInstr::New(Js::OpCode::Label, m_func);
  6881. IR::LabelInstr * helper = IR::LabelInstr::New(Js::OpCode::Label, m_func, /*helper*/true);
  6882. bool assign = instr->GetDst() && !instr->GetDst()->IsEqual(src1);
  6883. // TEST src1, Js::AtomTag
  6884. // JNE $done
  6885. if(!src1->IsNotTaggedValue())
  6886. {
  6887. GenerateObjectTest(src1, instr, assign ? done : fallthru);
  6888. }
  6889. // MOV typeReg, objectSrc + offsetof(RecyclableObject::type)
  6890. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, typeReg,
  6891. IR::IndirOpnd::New(src1, Js::RecyclableObject::GetOffsetOfType(), TyMachReg, m_func),
  6892. m_func));
  6893. // CMP [typeReg + offsetof(Type::typeid)], TypeIds_ActivationObject
  6894. {
  6895. IR::Instr * cmp = IR::Instr::New(Js::OpCode::CMP, m_func);
  6896. cmp->SetSrc1(IR::IndirOpnd::New(typeReg, Js::Type::GetOffsetOfTypeId(), TyInt32, m_func));
  6897. cmp->SetSrc2(IR::IntConstOpnd::New(Js::TypeId::TypeIds_ActivationObject, TyInt32, m_func));
  6898. instr->InsertBefore(cmp);
  6899. }
  6900. // JEQ $helper
  6901. instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JEQ, helper, m_func));
  6902. if (assign)
  6903. {
  6904. // $done:
  6905. // MOV dst, src
  6906. instr->InsertBefore(done);
  6907. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, instr->GetDst(), src1, m_func));
  6908. }
  6909. // JMP $fallthru
  6910. instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JMP, fallthru, m_func));
  6911. instr->InsertBefore(helper);
  6912. if (instr->GetDst())
  6913. {
  6914. // MOV dst, undefined
  6915. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, instr->GetDst(),
  6916. m_lowerer->LoadLibraryValueOpnd(instr, LibraryValue::ValueUndefined), m_func));
  6917. }
  6918. // $fallthru:
  6919. instr->InsertAfter(fallthru);
  6920. return true;
  6921. }
  6922. // given object instanceof function, functionReg is a register with function,
  6923. // objectReg is a register with instance and inlineCache is an InstIsInlineCache.
  6924. // We want to generate:
  6925. //
  6926. // fallback on helper (will patch the inline cache) if function does not match the cache
  6927. // MOV dst, Js::false
  6928. // CMP functionReg, [&(inlineCache->function)]
  6929. // JNE helper
  6930. //
  6931. // fallback if object is a tagged int
  6932. // TEST objectReg, Js::AtomTag
  6933. // JNE done
  6934. //
  6935. // fallback if object's type is not the cached type
  6936. // MOV typeReg, objectSrc + offsetof(RecyclableObject::type)
  6937. // CMP typeReg, [&(inlineCache->type]
  6938. // JNE checkPrimType
  6939. // use the cached result and fallthrough
  6940. // MOV dst, [&(inlineCache->result)]
  6941. // JMP done
  6942. // return false if object is a primitive
  6943. // $checkPrimType
  6944. // CMP [typeReg + offsetof(Type::typeid)], TypeIds_LastJavascriptPrimitiveType
  6945. // JLE done
  6946. //
  6947. //
  6948. // $helper
  6949. // $done
  6950. bool
  6951. LowererMD::GenerateFastIsInst(IR::Instr * instr)
  6952. {
  6953. IR::LabelInstr * helper = IR::LabelInstr::New(Js::OpCode::Label, m_func, true);
  6954. IR::LabelInstr * checkPrimType = IR::LabelInstr::New(Js::OpCode::Label, m_func, true);
  6955. IR::LabelInstr * done = IR::LabelInstr::New(Js::OpCode::Label, m_func);
  6956. IR::RegOpnd * typeReg = IR::RegOpnd::New(TyMachReg, this->m_func);
  6957. IR::Opnd * objectSrc;
  6958. IR::RegOpnd * objectReg;
  6959. IR::Opnd * functionSrc;
  6960. IR::RegOpnd * functionReg;
  6961. Js::IsInstInlineCache * inlineCache;
  6962. IR::Instr * instrArg;
  6963. // We are going to use the extra ArgOut_A instructions to lower the helper call later,
  6964. // so we leave them alone here and clean them up then.
  6965. inlineCache = instr->m_func->GetJnFunction()->GetIsInstInlineCache(instr->GetSrc1()->AsIntConstOpnd()->AsUint32());
  6966. Assert(instr->GetSrc2()->AsRegOpnd()->m_sym->m_isSingleDef);
  6967. instrArg = instr->GetSrc2()->AsRegOpnd()->m_sym->m_instrDef;
  6968. objectSrc = instrArg->GetSrc1();
  6969. Assert(instrArg->GetSrc2()->AsRegOpnd()->m_sym->m_isSingleDef);
  6970. instrArg = instrArg->GetSrc2()->AsRegOpnd()->m_sym->m_instrDef;
  6971. functionSrc = instrArg->GetSrc1();
  6972. Assert(instrArg->GetSrc2() == nullptr);
  6973. // MOV dst, Js::false
  6974. Lowerer::InsertMove(instr->GetDst(), m_lowerer->LoadLibraryValueOpnd(instr, LibraryValue::ValueFalse), instr);
  6975. if (functionSrc->IsRegOpnd())
  6976. {
  6977. functionReg = functionSrc->AsRegOpnd();
  6978. }
  6979. else
  6980. {
  6981. functionReg = IR::RegOpnd::New(TyMachReg, this->m_func);
  6982. // MOV functionReg, functionSrc
  6983. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, functionReg, functionSrc, m_func));
  6984. }
  6985. // CMP functionReg, [&(inlineCache->function)]
  6986. {
  6987. IR::Instr * cmp = IR::Instr::New(Js::OpCode::CMP, m_func);
  6988. cmp->SetSrc1(functionReg);
  6989. cmp->SetSrc2(IR::MemRefOpnd::New((void*)&(inlineCache->function), TyMachReg, m_func,
  6990. IR::AddrOpndKindDynamicIsInstInlineCacheFunctionRef));
  6991. instr->InsertBefore(cmp);
  6992. Legalize(cmp);
  6993. }
  6994. // JNE helper
  6995. instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JNE, helper, m_func));
  6996. if (objectSrc->IsRegOpnd())
  6997. {
  6998. objectReg = objectSrc->AsRegOpnd();
  6999. }
  7000. else
  7001. {
  7002. objectReg = IR::RegOpnd::New(TyMachReg, this->m_func);
  7003. // MOV objectReg, objectSrc
  7004. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, objectReg, objectSrc, m_func));
  7005. }
  7006. // TEST objectReg, Js::AtomTag
  7007. // JNE done
  7008. GenerateObjectTest(objectReg, instr, done);
  7009. // MOV typeReg, objectSrc + offsetof(RecyclableObject::type)
  7010. instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, typeReg,
  7011. IR::IndirOpnd::New(objectReg, Js::RecyclableObject::GetOffsetOfType(), TyMachReg, m_func),
  7012. m_func));
  7013. // CMP typeReg, [&(inlineCache->type]
  7014. {
  7015. IR::Instr * cmp = IR::Instr::New(Js::OpCode::CMP, m_func);
  7016. cmp->SetSrc1(typeReg);
  7017. cmp->SetSrc2(IR::MemRefOpnd::New((void*)&(inlineCache->type), TyMachReg, m_func,
  7018. IR::AddrOpndKindDynamicIsInstInlineCacheTypeRef));
  7019. instr->InsertBefore(cmp);
  7020. Legalize(cmp);
  7021. }
  7022. // JNE checkPrimType
  7023. instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JNE, checkPrimType, m_func));
  7024. // MOV dst, [&(inlineCache->result)]
  7025. Lowerer::InsertMove(instr->GetDst(), IR::MemRefOpnd::New((void*)&(inlineCache->result), TyMachReg, m_func,
  7026. IR::AddrOpndKindDynamicIsInstInlineCacheResultRef), instr);
  7027. // JMP done
  7028. instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JMP, done, m_func));
  7029. // LABEL checkPrimType
  7030. instr->InsertBefore(checkPrimType);
  7031. // CMP [typeReg + offsetof(Type::typeid)], TypeIds_LastJavascriptPrimitiveType
  7032. {
  7033. IR::Instr * cmp = IR::Instr::New(Js::OpCode::CMP, m_func);
  7034. cmp->SetSrc1(IR::IndirOpnd::New(typeReg, Js::Type::GetOffsetOfTypeId(), TyInt32, m_func));
  7035. cmp->SetSrc2(IR::IntConstOpnd::New(Js::TypeId::TypeIds_LastJavascriptPrimitiveType, TyInt32, m_func));
  7036. instr->InsertBefore(cmp);
  7037. }
  7038. // JLE done
  7039. instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JLE, done, m_func));
  7040. // LABEL helper
  7041. instr->InsertBefore(helper);
  7042. instr->InsertAfter(done);
  7043. return true;
  7044. }
  7045. void LowererMD::GenerateIsJsObjectTest(IR::RegOpnd* instanceReg, IR::Instr* insertInstr, IR::LabelInstr* labelHelper)
  7046. {
  7047. // TEST instanceReg, (Js::AtomTag_IntPtr | Js::FloatTag_Value )
  7048. GenerateObjectTest(instanceReg, insertInstr, labelHelper);
  7049. IR::RegOpnd * typeReg = IR::RegOpnd::New(TyMachReg, this->m_func);
  7050. // MOV typeReg, instanceReg + offsetof(RecyclableObject::type)
  7051. insertInstr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, typeReg,
  7052. IR::IndirOpnd::New(instanceReg, Js::RecyclableObject::GetOffsetOfType(), TyMachReg, m_func),
  7053. m_func));
  7054. // CMP [typeReg + offsetof(Type::typeid)], TypeIds_LastJavascriptPrimitiveType
  7055. IR::Instr * cmp = IR::Instr::New(Js::OpCode::CMP, this->m_func);
  7056. cmp->SetSrc1(IR::IndirOpnd::New(typeReg, Js::Type::GetOffsetOfTypeId(), TyInt32, this->m_func));
  7057. cmp->SetSrc2(IR::IntConstOpnd::New(Js::TypeId::TypeIds_LastJavascriptPrimitiveType, TyInt32, this->m_func));
  7058. insertInstr->InsertBefore(cmp);
  7059. // JLE labelHelper
  7060. insertInstr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JLE, labelHelper, this->m_func));
  7061. }
  7062. IR::Instr *
  7063. LowererMD::LowerToFloat(IR::Instr *instr)
  7064. {
  7065. switch (instr->m_opcode)
  7066. {
  7067. case Js::OpCode::Add_A:
  7068. Assert(instr->GetDst()->GetType() == instr->GetSrc1()->GetType());
  7069. Assert(instr->GetSrc1()->GetType() == instr->GetSrc2()->GetType());
  7070. instr->m_opcode = instr->GetSrc1()->IsFloat64() ? Js::OpCode::ADDSD : Js::OpCode::ADDSS;
  7071. break;
  7072. case Js::OpCode::Sub_A:
  7073. Assert(instr->GetDst()->GetType() == instr->GetSrc1()->GetType());
  7074. Assert(instr->GetSrc1()->GetType() == instr->GetSrc2()->GetType());
  7075. instr->m_opcode = instr->GetSrc1()->IsFloat64() ? Js::OpCode::SUBSD : Js::OpCode::SUBSS;
  7076. break;
  7077. case Js::OpCode::Mul_A:
  7078. Assert(instr->GetDst()->GetType() == instr->GetSrc1()->GetType());
  7079. Assert(instr->GetSrc1()->GetType() == instr->GetSrc2()->GetType());
  7080. instr->m_opcode = instr->GetSrc1()->IsFloat64() ? Js::OpCode::MULSD : Js::OpCode::MULSS;
  7081. break;
  7082. case Js::OpCode::Div_A:
  7083. Assert(instr->GetDst()->GetType() == instr->GetSrc1()->GetType());
  7084. Assert(instr->GetSrc1()->GetType() == instr->GetSrc2()->GetType());
  7085. instr->m_opcode = instr->GetSrc1()->IsFloat64() ? Js::OpCode::DIVSD : Js::OpCode::DIVSS;
  7086. break;
  7087. case Js::OpCode::Neg_A:
  7088. {
  7089. IR::Opnd *opnd;
  7090. instr->m_opcode = Js::OpCode::XORPS;
  7091. if (instr->GetDst()->IsFloat32())
  7092. {
  7093. opnd = IR::MemRefOpnd::New((void*)&Js::JavascriptNumber::MaskNegFloat, TyMachDouble, this->m_func, IR::AddrOpndKindDynamicFloatRef);
  7094. }
  7095. else
  7096. {
  7097. Assert(instr->GetDst()->IsFloat64());
  7098. opnd = IR::MemRefOpnd::New((void*)&Js::JavascriptNumber::MaskNegDouble, TyMachDouble, this->m_func, IR::AddrOpndKindDynamicDoubleRef);
  7099. }
  7100. instr->SetSrc2(opnd);
  7101. Legalize(instr);
  7102. break;
  7103. }
  7104. case Js::OpCode::BrEq_A:
  7105. case Js::OpCode::BrNeq_A:
  7106. case Js::OpCode::BrSrEq_A:
  7107. case Js::OpCode::BrSrNeq_A:
  7108. case Js::OpCode::BrGt_A:
  7109. case Js::OpCode::BrGe_A:
  7110. case Js::OpCode::BrLt_A:
  7111. case Js::OpCode::BrLe_A:
  7112. case Js::OpCode::BrNotEq_A:
  7113. case Js::OpCode::BrNotNeq_A:
  7114. case Js::OpCode::BrSrNotEq_A:
  7115. case Js::OpCode::BrSrNotNeq_A:
  7116. case Js::OpCode::BrNotGt_A:
  7117. case Js::OpCode::BrNotGe_A:
  7118. case Js::OpCode::BrNotLt_A:
  7119. case Js::OpCode::BrNotLe_A:
  7120. return this->LowerFloatCondBranch(instr->AsBranchInstr());
  7121. default:
  7122. Assume(UNREACHED);
  7123. }
  7124. this->MakeDstEquSrc1(instr);
  7125. return instr;
  7126. }
  7127. IR::BranchInstr *
  7128. LowererMD::LowerFloatCondBranch(IR::BranchInstr *instrBranch, bool ignoreNan)
  7129. {
  7130. Js::OpCode brOpcode = Js::OpCode::InvalidOpCode;
  7131. Js::OpCode cmpOpcode = Js::OpCode::InvalidOpCode;
  7132. IR::Instr *instr;
  7133. bool swapCmpOpnds = false;
  7134. bool addJP = false;
  7135. IR::LabelInstr *labelNaN = nullptr;
  7136. // Generate float compare that behave correctly for NaN's.
  7137. // These branch on unordered:
  7138. // JB
  7139. // JBE
  7140. // JE
  7141. // These don't branch on unordered:
  7142. // JA
  7143. // JAE
  7144. // JNE
  7145. // Unfortunately, only JA and JAE do what we'd like....
  7146. Func * func = instrBranch->m_func;
  7147. IR::Opnd *src1 = instrBranch->UnlinkSrc1();
  7148. IR::Opnd *src2 = instrBranch->UnlinkSrc2();
  7149. Assert(src1->GetType() == src2->GetType());
  7150. switch (instrBranch->m_opcode)
  7151. {
  7152. case Js::OpCode::BrSrEq_A:
  7153. case Js::OpCode::BrEq_A:
  7154. case Js::OpCode::BrSrNotNeq_A:
  7155. case Js::OpCode::BrNotNeq_A:
  7156. cmpOpcode = src1->IsFloat64() ? Js::OpCode::UCOMISD : Js::OpCode::UCOMISS;
  7157. brOpcode = Js::OpCode::JEQ;
  7158. if (!ignoreNan)
  7159. {
  7160. // Don't jump on NaN's
  7161. labelNaN = instrBranch->GetOrCreateContinueLabel();
  7162. addJP = true;
  7163. }
  7164. break;
  7165. case Js::OpCode::BrNeq_A:
  7166. case Js::OpCode::BrSrNeq_A:
  7167. case Js::OpCode::BrSrNotEq_A:
  7168. case Js::OpCode::BrNotEq_A:
  7169. cmpOpcode = src1->IsFloat64() ? Js::OpCode::UCOMISD : Js::OpCode::UCOMISS;
  7170. brOpcode = Js::OpCode::JNE;
  7171. if (!ignoreNan)
  7172. {
  7173. // Jump on NaN's
  7174. labelNaN = instrBranch->GetTarget();
  7175. addJP = true;
  7176. }
  7177. break;
  7178. case Js::OpCode::BrLe_A:
  7179. swapCmpOpnds = true;
  7180. brOpcode = Js::OpCode::JAE;
  7181. break;
  7182. case Js::OpCode::BrLt_A:
  7183. swapCmpOpnds = true;
  7184. brOpcode = Js::OpCode::JA;
  7185. break;
  7186. case Js::OpCode::BrGe_A:
  7187. brOpcode = Js::OpCode::JAE;
  7188. break;
  7189. case Js::OpCode::BrGt_A:
  7190. brOpcode = Js::OpCode::JA;
  7191. break;
  7192. case Js::OpCode::BrNotLe_A:
  7193. swapCmpOpnds = true;
  7194. brOpcode = Js::OpCode::JB;
  7195. break;
  7196. case Js::OpCode::BrNotLt_A:
  7197. swapCmpOpnds = true;
  7198. brOpcode = Js::OpCode::JBE;
  7199. break;
  7200. case Js::OpCode::BrNotGe_A:
  7201. brOpcode = Js::OpCode::JB;
  7202. break;
  7203. case Js::OpCode::BrNotGt_A:
  7204. brOpcode = Js::OpCode::JBE;
  7205. break;
  7206. default:
  7207. Assume(UNREACHED);
  7208. }
  7209. // if we haven't set cmpOpcode, then we are using COMISD/COMISS
  7210. if (cmpOpcode == Js::OpCode::InvalidOpCode)
  7211. {
  7212. cmpOpcode = src1->IsFloat64() ? Js::OpCode::COMISD : Js::OpCode::COMISS;
  7213. }
  7214. if (swapCmpOpnds)
  7215. {
  7216. IR::Opnd *tmp = src1;
  7217. src1 = src2;
  7218. src2 = tmp;
  7219. }
  7220. // VC generates UCOMISD for BrEq/BrNeq, and COMISD for all others, accordingly to IEEE 754.
  7221. // We'll do the same.
  7222. // COMISD / UCOMISD src1, src2
  7223. IR::Instr *instrCmp = IR::Instr::New(cmpOpcode, func);
  7224. instrCmp->SetSrc1(src1);
  7225. instrCmp->SetSrc2(src2);
  7226. instrBranch->InsertBefore(instrCmp);
  7227. Legalize(instrCmp);
  7228. if (addJP)
  7229. {
  7230. // JP $LabelNaN
  7231. instr = IR::BranchInstr::New(Js::OpCode::JP, labelNaN, func);
  7232. instrBranch->InsertBefore(instr);
  7233. }
  7234. // Jcc $L
  7235. instr = IR::BranchInstr::New(brOpcode, instrBranch->GetTarget(), func);
  7236. instrBranch->InsertBefore(instr);
  7237. instrBranch->Remove();
  7238. return instr->AsBranchInstr();
  7239. }
  7240. void LowererMD::HelperCallForAsmMathBuiltin(IR::Instr* instr, IR::JnHelperMethod helperMethodFloat, IR::JnHelperMethod helperMethodDouble)
  7241. {
  7242. bool isFloat32 = (instr->GetSrc1()->GetType() == TyFloat32) ? true : false;
  7243. switch (instr->m_opcode)
  7244. {
  7245. case Js::OpCode::InlineMathFloor:
  7246. case Js::OpCode::InlineMathCeil:
  7247. {
  7248. AssertMsg(instr->GetDst()->IsFloat(), "dst must be float.");
  7249. AssertMsg(instr->GetSrc1()->IsFloat(), "src1 must be float.");
  7250. AssertMsg(!instr->GetSrc2() || instr->GetSrc2()->IsFloat(), "src2 must be float.");
  7251. // Before:
  7252. // dst = <Built-in call> src1, src2
  7253. // After:
  7254. // I386:
  7255. // XMM0 = MOVSD src1
  7256. // CALL helperMethod
  7257. // dst = MOVSD call->dst
  7258. // AMD64:
  7259. // XMM0 = MOVSD src1
  7260. // RAX = MOV helperMethod
  7261. // CALL RAX
  7262. // dst = MOVSD call->dst
  7263. // Src1
  7264. IR::Instr* argOut = nullptr;
  7265. IR::RegOpnd* dst1 = nullptr;
  7266. if (isFloat32)
  7267. {
  7268. argOut = IR::Instr::New(Js::OpCode::MOVSS, this->m_func);
  7269. dst1 = IR::RegOpnd::New(nullptr, (RegNum)FIRST_FLOAT_ARG_REG, TyFloat32, this->m_func);
  7270. }
  7271. else
  7272. {
  7273. argOut = IR::Instr::New(Js::OpCode::MOVSD, this->m_func);
  7274. dst1 = IR::RegOpnd::New(nullptr, (RegNum)FIRST_FLOAT_ARG_REG, TyMachDouble, this->m_func);
  7275. }
  7276. dst1->m_isCallArg = true; // This is to make sure that lifetime of opnd is virtually extended until next CALL instr.
  7277. argOut->SetDst(dst1);
  7278. argOut->SetSrc1(instr->UnlinkSrc1());
  7279. instr->InsertBefore(argOut);
  7280. // Call CRT.
  7281. IR::RegOpnd* floatCallDst = IR::RegOpnd::New(nullptr, (RegNum)(FIRST_FLOAT_REG), (isFloat32)?TyFloat32:TyMachDouble, this->m_func); // Dst in XMM0.
  7282. // s1 = MOV helperAddr
  7283. IR::RegOpnd* s1 = IR::RegOpnd::New(TyMachReg, this->m_func);
  7284. IR::AddrOpnd* helperAddr = IR::AddrOpnd::New((Js::Var)IR::GetMethodOriginalAddress((isFloat32)?helperMethodFloat:helperMethodDouble), IR::AddrOpndKind::AddrOpndKindDynamicMisc, this->m_func);
  7285. IR::Instr* mov = IR::Instr::New(Js::OpCode::MOV, s1, helperAddr, this->m_func);
  7286. instr->InsertBefore(mov);
  7287. // dst(XMM0) = CALL s1
  7288. IR::Instr *floatCall = IR::Instr::New(Js::OpCode::CALL, floatCallDst, s1, this->m_func);
  7289. instr->InsertBefore(floatCall);
  7290. // Save the result.
  7291. instr->m_opcode = (isFloat32) ? Js::OpCode::MOVSS:Js::OpCode::MOVSD;
  7292. instr->SetSrc1(floatCall->GetDst());
  7293. break;
  7294. }
  7295. default:
  7296. Assume(false);
  7297. break;
  7298. }
  7299. }
  7300. void LowererMD::GenerateFastInlineBuiltInCall(IR::Instr* instr, IR::JnHelperMethod helperMethod)
  7301. {
  7302. switch (instr->m_opcode)
  7303. {
  7304. case Js::OpCode::InlineMathSqrt:
  7305. // Sqrt maps directly to the SSE2 instruction.
  7306. // src and dst should already be XMM registers, all we need is just change the opcode.
  7307. Assert(helperMethod == (IR::JnHelperMethod)0);
  7308. Assert(instr->GetSrc2() == nullptr);
  7309. instr->m_opcode = instr->GetSrc1()->IsFloat64() ? Js::OpCode::SQRTSD : Js::OpCode::SQRTSS;
  7310. break;
  7311. case Js::OpCode::InlineMathAbs:
  7312. Assert(helperMethod == (IR::JnHelperMethod)0);
  7313. return GenerateFastInlineBuiltInMathAbs(instr);
  7314. case Js::OpCode::InlineMathAcos:
  7315. case Js::OpCode::InlineMathAsin:
  7316. case Js::OpCode::InlineMathAtan:
  7317. case Js::OpCode::InlineMathAtan2:
  7318. case Js::OpCode::InlineMathCos:
  7319. case Js::OpCode::InlineMathExp:
  7320. case Js::OpCode::InlineMathLog:
  7321. case Js::OpCode::InlineMathPow:
  7322. case Js::OpCode::Expo_A: //** operator reuses InlineMathPow fastpath
  7323. case Js::OpCode::InlineMathSin:
  7324. case Js::OpCode::InlineMathTan:
  7325. {
  7326. AssertMsg(instr->GetDst()->IsFloat(), "dst must be float.");
  7327. AssertMsg(instr->GetSrc1()->IsFloat(), "src1 must be float.");
  7328. AssertMsg(!instr->GetSrc2() || instr->GetSrc2()->IsFloat(), "src2 must be float.");
  7329. // Before:
  7330. // dst = <Built-in call> src1, src2
  7331. // After:
  7332. // I386:
  7333. // XMM0 = MOVSD src1
  7334. // CALL helperMethod
  7335. // dst = MOVSD call->dst
  7336. // AMD64:
  7337. // XMM0 = MOVSD src1
  7338. // RAX = MOV helperMethod
  7339. // CALL RAX
  7340. // dst = MOVSD call->dst
  7341. // Src1
  7342. IR::Instr* argOut = IR::Instr::New(Js::OpCode::MOVSD, this->m_func);
  7343. IR::RegOpnd* dst1 = IR::RegOpnd::New(nullptr, (RegNum)FIRST_FLOAT_ARG_REG, TyMachDouble, this->m_func);
  7344. dst1->m_isCallArg = true; // This is to make sure that lifetime of opnd is virtually extended until next CALL instr.
  7345. argOut->SetDst(dst1);
  7346. argOut->SetSrc1(instr->UnlinkSrc1());
  7347. instr->InsertBefore(argOut);
  7348. // Src2
  7349. if (instr->GetSrc2() != nullptr)
  7350. {
  7351. IR::Instr* argOut2 = IR::Instr::New(Js::OpCode::MOVSD, this->m_func);
  7352. IR::RegOpnd* dst2 = IR::RegOpnd::New(nullptr, (RegNum)(FIRST_FLOAT_ARG_REG + 1), TyMachDouble, this->m_func);
  7353. dst2->m_isCallArg = true; // This is to make sure that lifetime of opnd is virtually extended until next CALL instr.
  7354. argOut2->SetDst(dst2);
  7355. argOut2->SetSrc1(instr->UnlinkSrc2());
  7356. instr->InsertBefore(argOut2);
  7357. }
  7358. // Call CRT.
  7359. IR::RegOpnd* floatCallDst = IR::RegOpnd::New(nullptr, (RegNum)(FIRST_FLOAT_REG), TyMachDouble, this->m_func); // Dst in XMM0.
  7360. #ifdef _M_IX86
  7361. IR::Instr* floatCall = IR::Instr::New(Js::OpCode::CALL, floatCallDst, this->m_func);
  7362. floatCall->SetSrc1(IR::HelperCallOpnd::New(helperMethod, this->m_func));
  7363. instr->InsertBefore(floatCall);
  7364. #else
  7365. // s1 = MOV helperAddr
  7366. IR::RegOpnd* s1 = IR::RegOpnd::New(TyMachReg, this->m_func);
  7367. IR::AddrOpnd* helperAddr = IR::AddrOpnd::New((Js::Var)IR::GetMethodOriginalAddress(helperMethod), IR::AddrOpndKind::AddrOpndKindDynamicMisc, this->m_func);
  7368. IR::Instr* mov = IR::Instr::New(Js::OpCode::MOV, s1, helperAddr, this->m_func);
  7369. instr->InsertBefore(mov);
  7370. // dst(XMM0) = CALL s1
  7371. IR::Instr *floatCall = IR::Instr::New(Js::OpCode::CALL, floatCallDst, s1, this->m_func);
  7372. instr->InsertBefore(floatCall);
  7373. #endif
  7374. // Save the result.
  7375. instr->m_opcode = Js::OpCode::MOVSD;
  7376. instr->SetSrc1(floatCall->GetDst());
  7377. break;
  7378. }
  7379. case Js::OpCode::InlineMathFloor:
  7380. case Js::OpCode::InlineMathCeil:
  7381. case Js::OpCode::InlineMathRound:
  7382. {
  7383. Assert(instr->GetDst()->IsInt32() || instr->GetDst()->IsFloat());
  7384. // MOVSD roundedFloat, src
  7385. //
  7386. // if(round)
  7387. // {
  7388. // CMP roundedFloat. -0.5
  7389. // JL $addHalfToRoundSrc
  7390. // CMP roundedFloat, 0
  7391. // JL $bailoutLabel
  7392. // }
  7393. //
  7394. // $addHalfToRoundSrc:
  7395. // ADDSD roundedFloat, 0.5
  7396. //
  7397. // if(isNotCeil)
  7398. // {
  7399. // CMP roundedFloat, 0
  7400. // JGE $skipRoundSd
  7401. // }
  7402. // ROUNDSD roundedFloat, roundedFloat, round_mode
  7403. //
  7404. // $skipRoundSd:
  7405. // if(isNotCeil)
  7406. // MOVSD checkNegZeroOpnd, roundedFloat
  7407. // else if (ceil)
  7408. // MOVSD checkNegZeroOpnd, src
  7409. //
  7410. // CMP checkNegZeroOpnd, 0
  7411. // JNE $convertToInt
  7412. //
  7413. // if(instr->ShouldCheckForNegativeZero())
  7414. // {
  7415. // isNegZero CALL IsNegZero(checkNegZeroOpnd)
  7416. // CMP isNegZero, 0
  7417. // JNE $bailoutLabel
  7418. // }
  7419. //
  7420. // $convertToInt:
  7421. // CVT(T)SD2SI dst, roundedFloat //CVTTSD2SI for floor/round and CVTSD2SI for ceil
  7422. // CMP dst 0x80000000
  7423. // JNE $fallthrough
  7424. //
  7425. // if(!sharedBailout)
  7426. // {
  7427. // $bailoutLabel:
  7428. // }
  7429. // GenerateBailout(instr)
  7430. //
  7431. // $fallthrough:
  7432. bool isNotCeil = instr->m_opcode != Js::OpCode::InlineMathCeil;
  7433. // MOVSD roundedFloat, src
  7434. IR::Opnd * src = instr->UnlinkSrc1();
  7435. IR::RegOpnd* roundedFloat = IR::RegOpnd::New(src->GetType(), this->m_func);
  7436. IR::Instr* argOut = IR::Instr::New(LowererMDArch::GetAssignOp(src->GetType()), roundedFloat, src, this->m_func);
  7437. instr->InsertBefore(argOut);
  7438. bool negZeroCheckDone = false;
  7439. IR::LabelInstr * bailoutLabel = nullptr;
  7440. bool sharedBailout = false;
  7441. if (instr->GetDst()->IsInt32())
  7442. {
  7443. sharedBailout = (instr->GetBailOutInfo()->bailOutInstr != instr) ? true : false;
  7444. if (sharedBailout)
  7445. {
  7446. bailoutLabel = instr->GetBailOutInfo()->bailOutInstr->AsLabelInstr();
  7447. }
  7448. else
  7449. {
  7450. bailoutLabel = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, /*helperLabel*/true);
  7451. }
  7452. }
  7453. IR::Opnd * zero;
  7454. if (src->IsFloat64())
  7455. {
  7456. zero = IR::MemRefOpnd::New((double*)&(Js::JavascriptNumber::k_Zero), TyFloat64, this->m_func, IR::AddrOpndKindDynamicDoubleRef);
  7457. }
  7458. else
  7459. {
  7460. Assert(src->IsFloat32());
  7461. zero = IR::MemRefOpnd::New((float*)&Js::JavascriptNumber::k_Float32Zero, TyFloat32, this->m_func, IR::AddrOpndKindDynamicFloatRef);
  7462. }
  7463. if(instr->m_opcode == Js::OpCode::InlineMathRound)
  7464. {
  7465. if(instr->ShouldCheckForNegativeZero())
  7466. {
  7467. IR::LabelInstr * addHalfToRoundSrcLabel = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  7468. IR::LabelInstr* negativeCheckLabel = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, /*helperLabel*/ true);
  7469. IR::LabelInstr* negZeroTest = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, /*helperLabel*/ true);
  7470. this->m_lowerer->InsertCompareBranch(roundedFloat, zero, Js::OpCode::BrGt_A, addHalfToRoundSrcLabel, instr);
  7471. instr->InsertBefore(negativeCheckLabel);
  7472. this->m_lowerer->InsertBranch(Js::OpCode::BrEq_A, negZeroTest, instr);
  7473. IR::Opnd * negPointFive;
  7474. if (src->IsFloat64())
  7475. {
  7476. negPointFive = IR::MemRefOpnd::New((double*)&Js::JavascriptNumber::k_NegPointFive, IRType::TyFloat64, this->m_func, IR::AddrOpndKindDynamicDoubleRef);
  7477. }
  7478. else
  7479. {
  7480. Assert(src->IsFloat32());
  7481. negPointFive = IR::MemRefOpnd::New((float*)&Js::JavascriptNumber::k_Float32NegPointFive, TyFloat32, this->m_func, IR::AddrOpndKindDynamicFloatRef);
  7482. }
  7483. this->m_lowerer->InsertCompareBranch(roundedFloat, negPointFive, Js::OpCode::BrGe_A, bailoutLabel, instr);
  7484. this->m_lowerer->InsertBranch(Js::OpCode::Br, addHalfToRoundSrcLabel, instr);
  7485. instr->InsertBefore(negZeroTest);
  7486. IR::Opnd* isNegZero = IsOpndNegZero(src, instr);
  7487. this->m_lowerer->InsertTestBranch(isNegZero, isNegZero, Js::OpCode::BrNeq_A, bailoutLabel, instr);
  7488. this->m_lowerer->InsertBranch(Js::OpCode::Br, addHalfToRoundSrcLabel, instr);
  7489. negZeroCheckDone = true;
  7490. instr->InsertBefore(addHalfToRoundSrcLabel);
  7491. }
  7492. IR::Opnd * pointFive;
  7493. if (src->IsFloat64())
  7494. {
  7495. pointFive = IR::MemRefOpnd::New((double*)&(Js::JavascriptNumber::k_PointFive), TyFloat64, this->m_func,
  7496. IR::AddrOpndKindDynamicDoubleRef);
  7497. }
  7498. else
  7499. {
  7500. Assert(src->IsFloat32());
  7501. pointFive = IR::MemRefOpnd::New((float*)&Js::JavascriptNumber::k_Float32PointFive, TyFloat32, this->m_func, IR::AddrOpndKindDynamicFloatRef);
  7502. }
  7503. IR::Instr * addInstr = IR::Instr::New(src->IsFloat64() ? Js::OpCode::ADDSD : Js::OpCode::ADDSS, roundedFloat, roundedFloat, pointFive, this->m_func);
  7504. instr->InsertBefore(addInstr);
  7505. Legalize(addInstr);
  7506. }
  7507. IR::LabelInstr * skipRoundSd = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  7508. if (instr->m_opcode == Js::OpCode::InlineMathFloor && instr->GetDst()->IsInt32())
  7509. {
  7510. this->m_lowerer->InsertCompareBranch(roundedFloat, zero, Js::OpCode::BrGe_A, skipRoundSd, instr);
  7511. }
  7512. // ROUNDSD srcCopy, srcCopy, round_mode
  7513. IR::Opnd * roundMode;
  7514. if(isNotCeil)
  7515. {
  7516. roundMode = IR::IntConstOpnd::New(0x01, TyInt32, this->m_func);
  7517. }
  7518. else if (instr->GetDst()->IsInt32() || instr->m_opcode != Js::OpCode::InlineMathFloor)
  7519. {
  7520. roundMode = IR::IntConstOpnd::New(0x02, TyInt32, this->m_func);
  7521. }
  7522. else
  7523. {
  7524. roundMode = IR::IntConstOpnd::New(0x03, TyInt32, this->m_func);
  7525. }
  7526. if (!skipRoundSd)
  7527. {
  7528. Assert(AutoSystemInfo::Data.SSE4_1Available());
  7529. }
  7530. IR::Instr* roundInstr = IR::Instr::New(src->IsFloat64() ? Js::OpCode::ROUNDSD : Js::OpCode::ROUNDSS, roundedFloat, roundedFloat, roundMode, this->m_func);
  7531. instr->InsertBefore(roundInstr);
  7532. if (instr->GetDst()->IsInt32())
  7533. {
  7534. if (instr->m_opcode == Js::OpCode::InlineMathFloor)
  7535. {
  7536. instr->InsertBefore(skipRoundSd);
  7537. }
  7538. //negZero bailout
  7539. if(instr->ShouldCheckForNegativeZero() && !negZeroCheckDone)
  7540. {
  7541. IR::LabelInstr * convertToInt = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  7542. IR::Opnd * checkNegZeroOpnd;
  7543. if(isNotCeil)
  7544. {
  7545. checkNegZeroOpnd = src;
  7546. }
  7547. else
  7548. {
  7549. checkNegZeroOpnd = roundedFloat;
  7550. }
  7551. this->m_lowerer->InsertCompareBranch(checkNegZeroOpnd, zero, Js::OpCode::BrNeq_A, convertToInt, instr);
  7552. IR::Opnd* isNegZero = IsOpndNegZero(checkNegZeroOpnd, instr);
  7553. this->m_lowerer->InsertCompareBranch(isNegZero, IR::IntConstOpnd::New(0x00000000, IRType::TyInt32, this->m_func), Js::OpCode::BrNeq_A, bailoutLabel, instr);
  7554. instr->InsertBefore(convertToInt);
  7555. }
  7556. IR::Opnd * originalDst = instr->UnlinkDst();
  7557. // CVT(T)SD2SI dst, srcCopy
  7558. IR::Instr* convertToIntInstr;
  7559. if (isNotCeil)
  7560. {
  7561. convertToIntInstr = IR::Instr::New(src->IsFloat64() ? Js::OpCode::CVTTSD2SI : Js::OpCode::CVTTSS2SI, originalDst, roundedFloat, this->m_func);
  7562. }
  7563. else
  7564. {
  7565. convertToIntInstr = IR::Instr::New(src->IsFloat64() ? Js::OpCode::CVTSD2SI : Js::OpCode::CVTSS2SI, originalDst, roundedFloat, this->m_func);
  7566. }
  7567. instr->InsertBefore(convertToIntInstr);
  7568. IR::LabelInstr * fallthrough = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  7569. IR::Opnd * intOverflowValue = IR::IntConstOpnd::New(INT32_MIN, IRType::TyInt32, this->m_func, true);
  7570. this->m_lowerer->InsertCompareBranch(originalDst, intOverflowValue, Js::OpCode::BrNeq_A, fallthrough, instr);
  7571. instr->InsertAfter(fallthrough);
  7572. if (!sharedBailout)
  7573. {
  7574. instr->InsertBefore(bailoutLabel);
  7575. }
  7576. this->m_lowerer->GenerateBailOut(instr);
  7577. }
  7578. else
  7579. {
  7580. IR::Opnd * originalDst = instr->UnlinkDst();
  7581. Assert(originalDst->IsFloat());
  7582. Assert(originalDst->GetType() == roundedFloat->GetType());
  7583. IR::Instr * movInstr = IR::Instr::New(originalDst->IsFloat64() ? Js::OpCode::MOVSD : Js::OpCode::MOVSS, originalDst, roundedFloat, this->m_func);
  7584. instr->InsertBefore(movInstr);
  7585. instr->Remove();
  7586. }
  7587. break;
  7588. }
  7589. case Js::OpCode::InlineMathMin:
  7590. case Js::OpCode::InlineMathMax:
  7591. {
  7592. IR::Opnd* src1 = instr->GetSrc1();
  7593. IR::Opnd* src2 = instr->GetSrc2();
  7594. IR::Opnd* dst = instr->GetDst();
  7595. IR::LabelInstr* doneLabel = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
  7596. IR::LabelInstr* labelNaNHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
  7597. IR::LabelInstr* labelNegZeroAndNaNCheckHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
  7598. IR::Instr* branchInstr;
  7599. bool min = instr->m_opcode == Js::OpCode::InlineMathMin ? true : false;
  7600. // CMP src1, src2
  7601. if(dst->IsInt32())
  7602. {
  7603. //MOV dst, src2;
  7604. Assert(!dst->IsEqual(src2));
  7605. this->m_lowerer->InsertMove(dst, src2, instr);
  7606. if(min)
  7607. {
  7608. // JLT $continueLabel
  7609. branchInstr = IR::BranchInstr::New(Js::OpCode::BrGt_I4, doneLabel, src1, src2, instr->m_func);
  7610. instr->InsertBefore(branchInstr);
  7611. LowererMDArch::EmitInt4Instr(branchInstr);
  7612. }
  7613. else
  7614. {
  7615. // JGT $continueLabel
  7616. branchInstr = IR::BranchInstr::New(Js::OpCode::BrLt_I4, doneLabel, src1, src2, instr->m_func);
  7617. instr->InsertBefore(branchInstr);
  7618. LowererMDArch::EmitInt4Instr(branchInstr);
  7619. }
  7620. // MOV dst, src1
  7621. this->m_lowerer->InsertMove(dst, src1, instr);
  7622. }
  7623. else if(dst->IsFloat64())
  7624. {
  7625. // COMISD src1 (src2), src2 (src1)
  7626. // JA $doneLabel
  7627. // JEQ $labelNegZeroAndNaNCheckHelper
  7628. // MOVSD dst, src2
  7629. // JMP $doneLabel
  7630. //
  7631. // $labelNegZeroAndNaNCheckHelper
  7632. // JP $labelNaNHelper
  7633. // if(min)
  7634. // {
  7635. // if(src2 == -0.0)
  7636. // MOVSD dst, src2
  7637. // }
  7638. // else
  7639. // {
  7640. // if(src1 == -0.0)
  7641. // MOVSD dst, src2
  7642. // }
  7643. // JMP $doneLabel
  7644. //
  7645. // $labelNaNHelper
  7646. // MOVSD dst, NaN
  7647. //
  7648. // $doneLabel
  7649. //MOVSD dst, src1;
  7650. Assert(!dst->IsEqual(src1));
  7651. this->m_lowerer->InsertMove(dst, src1, instr);
  7652. if(min)
  7653. {
  7654. this->m_lowerer->InsertCompareBranch(src1, src2, Js::OpCode::BrLt_A, doneLabel, instr); // Lowering of BrLt_A for floats is done to JA with operands swapped
  7655. }
  7656. else
  7657. {
  7658. this->m_lowerer->InsertCompareBranch(src1, src2, Js::OpCode::BrGt_A, doneLabel, instr);
  7659. }
  7660. instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JEQ, labelNegZeroAndNaNCheckHelper, instr->m_func));
  7661. this->m_lowerer->InsertMove(dst, src2, instr);
  7662. instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JMP, doneLabel, instr->m_func));
  7663. instr->InsertBefore(labelNegZeroAndNaNCheckHelper);
  7664. instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JP, labelNaNHelper, instr->m_func));
  7665. IR::Opnd* isNegZero;
  7666. if(min)
  7667. {
  7668. isNegZero = IsOpndNegZero(src2, instr);
  7669. }
  7670. else
  7671. {
  7672. isNegZero = IsOpndNegZero(src1, instr);
  7673. }
  7674. this->m_lowerer->InsertCompareBranch(isNegZero, IR::IntConstOpnd::New(0x00000000, IRType::TyInt32, this->m_func), Js::OpCode::BrEq_A, doneLabel, instr);
  7675. this->m_lowerer->InsertMove(dst, src2, instr);
  7676. instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JMP, doneLabel, instr->m_func));
  7677. instr->InsertBefore(labelNaNHelper);
  7678. IR::Opnd * opndNaN = IR::MemRefOpnd::New((double*)&(Js::JavascriptNumber::k_Nan), IRType::TyFloat64, this->m_func);
  7679. this->m_lowerer->InsertMove(dst, opndNaN, instr);
  7680. }
  7681. instr->InsertBefore(doneLabel);
  7682. instr->Remove();
  7683. break;
  7684. }
  7685. default:
  7686. AssertMsg(FALSE, "Unknown inline built-in opcode");
  7687. break;
  7688. }
  7689. }
  7690. IR::Opnd* LowererMD::IsOpndNegZero(IR::Opnd* opnd, IR::Instr* instr)
  7691. {
  7692. IR::Opnd * isNegZero = IR::RegOpnd::New(TyInt32, this->m_func);
  7693. LoadDoubleHelperArgument(instr, opnd);
  7694. IR::Instr * helperCallInstr = IR::Instr::New(Js::OpCode::CALL, isNegZero, this->m_func);
  7695. instr->InsertBefore(helperCallInstr);
  7696. this->ChangeToHelperCall(helperCallInstr, IR::HelperIsNegZero);
  7697. return isNegZero;
  7698. }
  7699. void LowererMD::GenerateFastInlineBuiltInMathAbs(IR::Instr* inlineInstr)
  7700. {
  7701. IR::Opnd* src = inlineInstr->GetSrc1();
  7702. IR::Opnd* dst = inlineInstr->UnlinkDst();
  7703. Assert(src);
  7704. IR::Instr* tmpInstr;
  7705. IR::Instr* nextInstr = IR::LabelInstr::New(Js::OpCode::Label, m_func);
  7706. IR::Instr* continueInstr = m_lowerer->LowerBailOnIntMin(inlineInstr);
  7707. continueInstr->InsertAfter(nextInstr);
  7708. IRType srcType = src->GetType();
  7709. if (srcType == IRType::TyInt32)
  7710. {
  7711. // Note: if execution gets so far, we always get (untagged) int32 here.
  7712. // Since -x = ~x + 1, abs(x) = x, abs(-x) = -x, sign-extend(x) = 0, sign_extend(-x) = -1, where 0 <= x.
  7713. // Then: abs(x) = sign-extend(x) XOR x - sign-extend(x)
  7714. // Expected input (otherwise bailout):
  7715. // - src1 is (untagged) int, not equal to int_min (abs(int_min) would produce overflow, as there's no corresponding positive int).
  7716. // MOV EAX, src
  7717. IR::RegOpnd *regEAX = IR::RegOpnd::New(TyInt32, this->m_func);
  7718. regEAX->SetReg(LowererMDArch::GetRegIMulDestLower());
  7719. tmpInstr = IR::Instr::New(Js::OpCode::MOV, regEAX, src, this->m_func);
  7720. nextInstr->InsertBefore(tmpInstr);
  7721. IR::RegOpnd *regEDX = IR::RegOpnd::New(TyInt32, this->m_func);
  7722. regEDX->SetReg(LowererMDArch::GetRegIMulHighDestLower());
  7723. // CDQ (sign-extend EAX into EDX, producing 64bit EDX:EAX value)
  7724. // Note: put EDX on dst to give of def to the EDX lifetime
  7725. tmpInstr = IR::Instr::New(Js::OpCode::CDQ, regEDX, this->m_func);
  7726. nextInstr->InsertBefore(tmpInstr);
  7727. // XOR EAX, EDX
  7728. tmpInstr = IR::Instr::New(Js::OpCode::XOR, regEAX, regEAX, regEDX, this->m_func);
  7729. nextInstr->InsertBefore(tmpInstr);
  7730. // SUB EAX, EDX
  7731. tmpInstr = IR::Instr::New(Js::OpCode::SUB, regEAX, regEAX, regEDX, this->m_func);
  7732. nextInstr->InsertBefore(tmpInstr);
  7733. // MOV dst, EAX
  7734. tmpInstr = IR::Instr::New(Js::OpCode::MOV, dst, regEAX, this->m_func);
  7735. nextInstr->InsertBefore(tmpInstr);
  7736. }
  7737. else if (srcType == IRType::TyFloat64)
  7738. {
  7739. if (!dst->IsRegOpnd())
  7740. {
  7741. // MOVSD tempRegOpnd, src
  7742. IR::RegOpnd* tempRegOpnd = IR::RegOpnd::New(nullptr, TyMachDouble, this->m_func);
  7743. tempRegOpnd->m_isCallArg = true; // This is to make sure that lifetime of opnd is virtually extended until next CALL instr.
  7744. tmpInstr = IR::Instr::New(Js::OpCode::MOVSD, tempRegOpnd, src, this->m_func);
  7745. nextInstr->InsertBefore(tmpInstr);
  7746. // This saves the result in the same register.
  7747. this->GenerateFloatAbs(static_cast<IR::RegOpnd*>(tempRegOpnd), nextInstr);
  7748. // MOVSD dst, tempRegOpnd
  7749. tmpInstr = IR::Instr::New(Js::OpCode::MOVSD, dst, tempRegOpnd, this->m_func);
  7750. nextInstr->InsertBefore(tmpInstr);
  7751. }
  7752. else
  7753. {
  7754. // MOVSD dst, src
  7755. tmpInstr = IR::Instr::New(Js::OpCode::MOVSD, dst, src, this->m_func);
  7756. nextInstr->InsertBefore(tmpInstr);
  7757. // This saves the result in the same register.
  7758. this->GenerateFloatAbs(static_cast<IR::RegOpnd*>(dst), nextInstr);
  7759. }
  7760. }
  7761. else if (srcType == IRType::TyFloat32)
  7762. {
  7763. if (!dst->IsRegOpnd())
  7764. {
  7765. // MOVSS tempRegOpnd, src
  7766. IR::RegOpnd* tempRegOpnd = IR::RegOpnd::New(nullptr, TyFloat32, this->m_func);
  7767. tempRegOpnd->m_isCallArg = true; // This is to make sure that lifetime of opnd is virtually extended until next CALL instr.
  7768. tmpInstr = IR::Instr::New(Js::OpCode::MOVSS, tempRegOpnd, src, this->m_func);
  7769. nextInstr->InsertBefore(tmpInstr);
  7770. // This saves the result in the same register.
  7771. this->GenerateFloatAbs(static_cast<IR::RegOpnd*>(tempRegOpnd), nextInstr);
  7772. // MOVSS dst, tempRegOpnd
  7773. tmpInstr = IR::Instr::New(Js::OpCode::MOVSS, dst, tempRegOpnd, this->m_func);
  7774. nextInstr->InsertBefore(tmpInstr);
  7775. }
  7776. else
  7777. {
  7778. // MOVSS dst, src
  7779. tmpInstr = IR::Instr::New(Js::OpCode::MOVSS, dst, src, this->m_func);
  7780. nextInstr->InsertBefore(tmpInstr);
  7781. // This saves the result in the same register.
  7782. this->GenerateFloatAbs(static_cast<IR::RegOpnd*>(dst), nextInstr);
  7783. }
  7784. }
  7785. else
  7786. {
  7787. AssertMsg(FALSE, "GenerateFastInlineBuiltInMathAbs: unexpected type of the src!");
  7788. }
  7789. }
  7790. void
  7791. LowererMD::FinalLower()
  7792. {
  7793. this->lowererMDArch.FinalLower();
  7794. }
  7795. IR::Instr *
  7796. LowererMD::LowerDivI4AndBailOnReminder(IR::Instr * instr, IR::LabelInstr * bailOutLabel)
  7797. {
  7798. // Don't have save the operand for bailout because the lowering of IDIV don't overwrite their values
  7799. // (EDX) = CDQ
  7800. // EAX = numerator
  7801. // (EDX:EAX)= IDIV (EAX), denominator
  7802. // TEST EDX, EDX
  7803. // JNE bailout
  7804. // <Caller insert more checks here>
  7805. // dst = MOV EAX <-- insertBeforeInstr
  7806. Assert(instr);
  7807. Assert(instr->m_opcode == Js::OpCode::Div_I4);
  7808. Assert(!instr->HasBailOutInfo());
  7809. EmitInt4Instr(instr);
  7810. Assert(instr->m_opcode == Js::OpCode::IDIV);
  7811. IR::Instr * prev = instr->m_prev;
  7812. Assert(prev->m_opcode == Js::OpCode::CDQ);
  7813. #ifdef _M_IX86
  7814. Assert(prev->GetDst()->AsRegOpnd()->GetReg() == RegEDX);
  7815. #else
  7816. Assert(prev->GetDst()->AsRegOpnd()->GetReg() == RegRDX);
  7817. #endif
  7818. IR::Opnd * reminderOpnd = prev->GetDst();
  7819. // Insert all check before the assignment to the actual dst.
  7820. IR::Instr * insertBeforeInstr = instr->m_next;
  7821. Assert(insertBeforeInstr->m_opcode == Js::OpCode::MOV);
  7822. #ifdef _M_IX86
  7823. Assert(insertBeforeInstr->GetSrc1()->AsRegOpnd()->GetReg() == RegEAX);
  7824. #else
  7825. Assert(insertBeforeInstr->GetSrc1()->AsRegOpnd()->GetReg() == RegRAX);
  7826. #endif
  7827. // Jump to bailout if the reminder is not 0 (not int result)
  7828. this->m_lowerer->InsertTestBranch(reminderOpnd, reminderOpnd, Js::OpCode::BrNeq_A, bailOutLabel, insertBeforeInstr);
  7829. return insertBeforeInstr;
  7830. }