12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267 |
- #include "BfCompiler.h"
- #include "BfSystem.h"
- #include "BfParser.h"
- #include "BfCodeGen.h"
- #include "BfExprEvaluator.h"
- #include <fcntl.h>
- #include "BfConstResolver.h"
- #include "BfMangler.h"
- #include "BeefySysLib/util/PerfTimer.h"
- #include "BeefySysLib/util/BeefPerf.h"
- #include "BeefySysLib/util/StackHelper.h"
- #include "BfSourceClassifier.h"
- #include "BfAutoComplete.h"
- #include "BfDemangler.h"
- #include "BfResolvePass.h"
- #include "BfFixits.h"
- #include "BfIRCodeGen.h"
- #include "BfDefBuilder.h"
- #pragma warning(push)
- #pragma warning(disable:4141)
- #pragma warning(disable:4146)
- #pragma warning(disable:4291)
- #pragma warning(disable:4244)
- #pragma warning(disable:4267)
- #pragma warning(disable:4624)
- #pragma warning(disable:4800)
- #pragma warning(disable:4996)
- #include "llvm/IR/DIBuilder.h"
- #include "llvm/IR/Module.h"
- #include "llvm/IR/Constants.h"
- #include "llvm/IR/GlobalValue.h"
- #include "llvm/IR/GlobalVariable.h"
- #include "llvm/ADT/ArrayRef.h"
- #include "llvm/IR/InlineAsm.h"
- #include "llvm/Support/FileSystem.h"
- #include "BeefySysLib/util/AllocDebug.h"
- #pragma warning(pop)
- USING_NS_BF;
- bool BfModule::AddDeferredCallEntry(BfDeferredCallEntry* deferredCallEntry, BfScopeData* scopeData)
- {
- if ((((mCompiler->mIsResolveOnly) && (!mIsComptimeModule)) ||
- (mBfIRBuilder->mIgnoreWrites)) && (deferredCallEntry->mDeferredBlock == NULL))
- {
- // For resolve entries, we only keep deferred blocks because we need to process them later so we can
- // resolve inside of them. This is also required for lambda bind scan-pass
- delete deferredCallEntry;
- return false;
- }
- if (mBfIRBuilder->mIgnoreWrites)
- {
- deferredCallEntry->mIgnored = true;
- scopeData->mDeferredCallEntries.PushBack(deferredCallEntry);
- return true;
- }
- // We don't need to do a "clear handlers" if we're just adding another dyn to an existing dyn list
- bool isDyn = mCurMethodState->mCurScope->IsDyn(scopeData);
- if (mCurMethodState->mPendingNullConditional != NULL)
- isDyn = true;
- deferredCallEntry->mOrigScopeArgs = deferredCallEntry->mScopeArgs;
- if (!isDyn)
- {
- mCurMethodState->mCurScope->ClearHandlers(scopeData);
- if (!mBfIRBuilder->mIgnoreWrites)
- {
- if ((IsTargetingBeefBackend()) && (deferredCallEntry->mModuleMethodInstance.mMethodInstance != NULL) &&
- (!mContext->IsSentinelMethod(deferredCallEntry->mModuleMethodInstance.mMethodInstance)))
- {
- SizedArray<BfIRType, 8> origParamTypes;
- BfIRType origReturnType;
- deferredCallEntry->mModuleMethodInstance.mMethodInstance->GetIRFunctionInfo(this, origReturnType, origParamTypes);
- int sretIdx = deferredCallEntry->mModuleMethodInstance.mMethodInstance->GetStructRetIdx();
- BF_ASSERT(origParamTypes.size() == deferredCallEntry->mScopeArgs.size() + ((sretIdx != -1) ? 1 : 0));
- int argIdx = 0;
- int paramIdx = 0;
- for (int argIdx = 0; argIdx < (int)deferredCallEntry->mScopeArgs.size(); argIdx++, paramIdx++)
- {
- if (argIdx == sretIdx)
- paramIdx++;
- auto scopeArg = deferredCallEntry->mScopeArgs[argIdx];
- if ((scopeArg.IsConst()) || (scopeArg.IsFake()))
- continue;
- auto prevInsertBlock = mBfIRBuilder->GetInsertBlock();
- mBfIRBuilder->SetInsertPoint(mCurMethodState->mIRHeadBlock);
- auto allocaInst = mBfIRBuilder->CreateAlloca(origParamTypes[paramIdx]);
- mBfIRBuilder->ClearDebugLocation_Last();
- mBfIRBuilder->SetInsertPoint(prevInsertBlock);
- if (WantsLifetimes())
- {
- mBfIRBuilder->CreateLifetimeStart(allocaInst);
- mBfIRBuilder->ClearDebugLocation_Last();
- }
- mBfIRBuilder->CreateStore(scopeArg, allocaInst);
- mBfIRBuilder->ClearDebugLocation_Last();
- deferredCallEntry->mScopeArgs[argIdx] = allocaInst;
- if (WantsLifetimes())
- scopeData->mDeferredLifetimeEnds.push_back(allocaInst);
- }
- deferredCallEntry->mArgsNeedLoad = true;
- }
- }
- scopeData->mDeferredCallEntries.PushFront(deferredCallEntry);
- return true;
- }
- bool isLooped = mCurMethodState->mCurScope->IsLooped(scopeData);
- BfDeferredCallEntry* listEntry = NULL;
- if (!scopeData->mDeferredCallEntries.IsEmpty())
- {
- listEntry = scopeData->mDeferredCallEntries.mHead;
- if (!listEntry->IsDynList())
- listEntry = NULL;
- }
- auto deferredCallEntryType = ResolveTypeDef(mCompiler->mDeferredCallTypeDef);
- AddDependency(deferredCallEntryType, mCurTypeInstance, BfDependencyMap::DependencyFlag_Allocates);
- mBfIRBuilder->PopulateType(deferredCallEntryType);
- auto deferredCallEntryTypePtr = CreatePointerType(deferredCallEntryType);
- UpdateSrcPos(mCurMethodInstance->mMethodDef->GetRefNode(), BfSrcPosFlag_NoSetDebugLoc);
- if (listEntry == NULL)
- {
- listEntry = new BfDeferredCallEntry();
- if (!mBfIRBuilder->mIgnoreWrites)
- {
- listEntry->mDynCallTail = CreateAlloca(deferredCallEntryTypePtr, false, "deferredCallTail");
- if (WantsLifetimes())
- scopeData->mDeferredLifetimeEnds.push_back(listEntry->mDynCallTail);
- auto prevInsertBlock = mBfIRBuilder->GetInsertBlock();
- mBfIRBuilder->SaveDebugLocation();
- mBfIRBuilder->SetInsertPointAtStart(mCurMethodState->mIRInitBlock);
- auto scopeHead = &mCurMethodState->mHeadScope;
- if (scopeHead->mDIScope)
- mBfIRBuilder->SetCurrentDebugLocation(mCurFilePosition.mCurLine + 1, 0, scopeHead->mDIScope, BfIRMDNode());
- if (WantsLifetimes())
- mBfIRBuilder->CreateLifetimeStart(listEntry->mDynCallTail);
- auto storeInst = mBfIRBuilder->CreateStore(GetDefaultValue(deferredCallEntryTypePtr), listEntry->mDynCallTail);
- mBfIRBuilder->ClearDebugLocation(storeInst);
- if (WantsDebugInfo())
- {
- auto deferredCallEntryType = ResolveTypeDef(mCompiler->mDeferredCallTypeDef);
- auto deferredCallEntryTypePtr = CreatePointerType(deferredCallEntryType);
- String varName = StrFormat("__deferred%d", mCurMethodState->mDeferredLoopListCount);
- mBfIRBuilder->SetInsertPoint(mCurMethodState->mIRInitBlock);
- if (scopeHead->mDIScope)
- mBfIRBuilder->SetCurrentDebugLocation(mCurFilePosition.mCurLine + 1, 0, scopeHead->mDIScope, BfIRMDNode());
- mBfIRBuilder->CreateStatementStart();
- //TODO: Make this work for LLVM - we need a proper debug location
- //if (IsTargetingBeefBackend())
- {
- auto diVariable = mBfIRBuilder->DbgCreateAutoVariable(scopeHead->mDIScope, varName, mCurFilePosition.mFileInstance->mDIFile, mCurFilePosition.mCurLine, mBfIRBuilder->DbgGetType(deferredCallEntryTypePtr));
- mBfIRBuilder->DbgInsertDeclare(listEntry->mDynCallTail, diVariable);
- }
- mCurMethodState->mDeferredLoopListCount++;
- }
- mBfIRBuilder->SetInsertPoint(prevInsertBlock);
- mBfIRBuilder->RestoreDebugLocation();
- }
- mCurMethodState->mCurScope->ClearHandlers(scopeData);
- scopeData->mDeferredCallEntries.PushFront(listEntry);
- }
- BfIRValue deferredAlloca;
- SizedArray<BfType*, 4> types;
- SizedArray<String, 8> memberNames;
- int instAlign = 1;
- int dataPos = 0;
- int instSize = 0;
- Array<int> memberPositions;
- String typeName;
- BfDeferredMethodCallData* deferredMethodCallData = NULL;
- if (deferredCallEntry->mDeferredBlock != NULL)
- {
- HashContext hashCtx;
- hashCtx.Mixin(deferredCallEntry->mDeferredBlock->GetSrcStart());
- auto parserData = deferredCallEntry->mDeferredBlock->GetParserData();
- if (parserData != NULL)
- hashCtx.MixinStr(parserData->mFileName);
- int64 blockId = BfDeferredMethodCallData::GenerateMethodId(this, hashCtx.Finish64());
- deferredCallEntry->mBlockId = blockId;
- auto deferType = deferredCallEntryType;
- BfIRType deferIRType;
- auto int64Type = GetPrimitiveType(BfTypeCode_Int64);
- types.push_back(int64Type);
- memberNames.push_back("__methodId");
- types.push_back(deferredCallEntryTypePtr);
- memberNames.push_back("__next");
- for (auto& capture : deferredCallEntry->mCaptures)
- {
- BfType* type = capture.mValue.mType;
- types.push_back(type);
- memberNames.push_back(capture.mName);
- }
- SizedArray<BfIRType, 4> llvmTypes;
- SizedArray<BfIRMDNode, 8> diFieldTypes;
- typeName = StrFormat("_BF_DeferredData_%s", BfTypeUtils::HashEncode64(blockId).c_str());
- auto valueType = ResolveTypeDef(mCompiler->mValueTypeTypeDef);
- llvmTypes.push_back(mBfIRBuilder->MapType(valueType));
- //int dataPos = 0;
- for (int i = 0; i < (int)memberNames.size(); i++)
- {
- auto type = types[i];
- auto memberName = memberNames[i];
- if (!type->IsValuelessType())
- {
- llvmTypes.push_back(mBfIRBuilder->MapType(type));
- instAlign = BF_MAX(instAlign, (int)type->mAlign);
- int alignSize = (int)type->mAlign;
- int dataSize = type->mSize;
- if (alignSize > 1)
- dataPos = (dataPos + (alignSize - 1)) & ~(alignSize - 1);
- memberPositions.push_back(dataPos);
- dataPos += type->mSize;
- }
- }
- instSize = dataPos;
- deferIRType = mBfIRBuilder->CreateStructType(typeName);
- mBfIRBuilder->StructSetBody(deferIRType, llvmTypes, instSize, instAlign, false);
- auto prevInsertPoint = mBfIRBuilder->GetInsertBlock();
- if (!isLooped)
- mBfIRBuilder->SetInsertPoint(mCurMethodState->mIRHeadBlock);
- deferredAlloca = mBfIRBuilder->CreateAlloca(deferIRType);
- mBfIRBuilder->SetAllocaAlignment(deferredAlloca, instAlign);
- mBfIRBuilder->SetAllocaNoChkStkHint(deferredAlloca);
- if (!isLooped)
- mBfIRBuilder->SetInsertPoint(prevInsertPoint);
- auto gepInstance = mBfIRBuilder->CreateInBoundsGEP(deferredAlloca, 0, 2); // mNext
- auto prevVal = mBfIRBuilder->CreateLoad(listEntry->mDynCallTail);
- mBfIRBuilder->CreateStore(prevVal, gepInstance);
- gepInstance = mBfIRBuilder->CreateInBoundsGEP(deferredAlloca, 0, 1); // mMethodId
- mBfIRBuilder->CreateStore(GetConstValue64(blockId), gepInstance);
- if (!deferredCallEntry->mCaptures.empty())
- {
- int dataIdx = 3;
- for (int captureIdx = 0; captureIdx < (int)deferredCallEntry->mCaptures.size(); captureIdx++)
- {
- auto& capture = deferredCallEntry->mCaptures[captureIdx];
- if (!capture.mValue.mType->IsValuelessType())
- {
- auto gepInstance = mBfIRBuilder->CreateInBoundsGEP(deferredAlloca, 0, dataIdx);
- mBfIRBuilder->CreateStore(capture.mValue.mValue, gepInstance);
- dataIdx++;
- }
- }
- }
- mBfIRBuilder->CreateStore(mBfIRBuilder->CreateBitCast(deferredAlloca, mBfIRBuilder->MapType(deferredCallEntryTypePtr)), listEntry->mDynCallTail);
- deferredCallEntry->mDeferredAlloca = deferredAlloca;
- listEntry->mDynList.PushFront(deferredCallEntry);
- }
- else
- {
- auto& llvmArgs = deferredCallEntry->mScopeArgs;
- auto moduleMethodInstance = deferredCallEntry->mModuleMethodInstance;
- auto methodInstance = moduleMethodInstance.mMethodInstance;
- auto methodDef = methodInstance->mMethodDef;
- auto owningType = methodInstance->mMethodInstanceGroup->mOwner;
- auto voidType = GetPrimitiveType(BfTypeCode_None);
- auto voidPtrType = CreatePointerType(voidType);
- BfDeferredMethodCallData** deferredMethodCallDataPtr = NULL;
- if (mDeferredMethodCallData.TryGetValue(methodInstance, &deferredMethodCallDataPtr))
- {
- deferredMethodCallData = *deferredMethodCallDataPtr;
- }
- else
- {
- deferredMethodCallData = new BfDeferredMethodCallData();
- mDeferredMethodCallData[methodInstance] = deferredMethodCallData;
- deferredMethodCallData->mMethodId = BfDeferredMethodCallData::GenerateMethodId(this, methodInstance->mIdHash);
- auto int64Type = GetPrimitiveType(BfTypeCode_Int64);
- auto methodDef = moduleMethodInstance.mMethodInstance->mMethodDef;
- auto thisType = moduleMethodInstance.mMethodInstance->mMethodInstanceGroup->mOwner;
- types.push_back(int64Type);
- memberNames.push_back("__methodId");
- types.push_back(deferredCallEntryTypePtr);
- memberNames.push_back("__next");
- if (!methodDef->mIsStatic)
- {
- types.push_back(thisType);
- memberNames.push_back("__this");
- }
- for (int paramIdx = 0; paramIdx < (int)methodInstance->GetParamCount(); paramIdx++)
- {
- if (methodInstance->IsParamSkipped(paramIdx))
- paramIdx++;
- types.push_back(methodInstance->GetParamType(paramIdx));
- memberNames.push_back(methodInstance->GetParamName(paramIdx));
- }
- SizedArray<BfIRType, 4> llvmTypes;
- //String typeName;
- typeName += StrFormat("_BF_DeferredData_%s", BfTypeUtils::HashEncode64(deferredMethodCallData->mMethodId).c_str());
- BfLogSysM("Building type: %s from methodInstance:%p\n", typeName.c_str(), methodInstance);
- //Array<int> memberPositions;
- //int instAlign = 1;
- //int dataPos = 0;
- BF_ASSERT(types.size() == memberNames.size());
- for (int i = 0; i < (int)types.size(); i++)
- {
- auto type = types[i];
- auto memberName = memberNames[i];
- if (!type->IsValuelessType())
- {
- llvmTypes.push_back(mBfIRBuilder->MapType(type));
- instAlign = BF_MAX(instAlign, (int)type->mAlign);
- int alignSize = (int)type->mAlign;
- int dataSize = type->mSize;
- if (alignSize > 1)
- dataPos = (dataPos + (alignSize - 1)) & ~(alignSize - 1);
- memberPositions.push_back(dataPos);
- dataPos += type->mSize;
- }
- }
- instSize = dataPos;
- deferredMethodCallData->mAlign = instAlign;
- deferredMethodCallData->mSize = instSize;
- deferredMethodCallData->mDeferType = mBfIRBuilder->CreateStructType(typeName);
- mBfIRBuilder->StructSetBody(deferredMethodCallData->mDeferType, llvmTypes, instSize, instAlign, false);
- deferredMethodCallData->mDeferTypePtr = mBfIRBuilder->GetPointerTo(deferredMethodCallData->mDeferType);
- }
- auto deferType = deferredMethodCallData->mDeferType;
- auto prevInsertPoint = mBfIRBuilder->GetInsertBlock();
- if (!isLooped)
- mBfIRBuilder->SetInsertPoint(mCurMethodState->mIRHeadBlock);
- deferredAlloca = mBfIRBuilder->CreateAlloca(BfIRType(deferredMethodCallData->mDeferType));
- mBfIRBuilder->ClearDebugLocation(deferredAlloca);
- mBfIRBuilder->SetAllocaAlignment(deferredAlloca, deferredMethodCallData->mAlign);
- mBfIRBuilder->SetAllocaNoChkStkHint(deferredAlloca);
- if (!isLooped)
- mBfIRBuilder->SetInsertPoint(prevInsertPoint);
- auto gepInstance = mBfIRBuilder->CreateInBoundsGEP(deferredAlloca, 0, 1);
- auto prevVal = mBfIRBuilder->CreateLoad(listEntry->mDynCallTail);
- mBfIRBuilder->CreateStore(prevVal, gepInstance);
- gepInstance = mBfIRBuilder->CreateInBoundsGEP(deferredAlloca, 0, 0);
- mBfIRBuilder->CreateStore(GetConstValue64(deferredMethodCallData->mMethodId), gepInstance);
- int dataIdx = 2;
- int argIdx = 0;
- if ((!methodDef->mIsStatic) && (!owningType->IsValuelessType()))
- {
- gepInstance = mBfIRBuilder->CreateInBoundsGEP(deferredAlloca, 0, 2);
- if (owningType->IsValueType())
- {
- if ((!methodDef->mIsMutating) && (owningType->IsSplattable()))
- {
- BfTypedValue splatVal(llvmArgs[0], owningType, BfTypedValueKind_ThisSplatHead);
- BfTypedValue aggVal = AggregateSplat(splatVal, &llvmArgs[0]);
- aggVal = LoadValue(aggVal);
- mBfIRBuilder->CreateStore(aggVal.mValue, gepInstance);
- BfTypeUtils::SplatIterate([&](BfType* checkType) { argIdx++; }, owningType);
- }
- else
- {
- auto thisArg = mBfIRBuilder->CreateLoad(llvmArgs[0]);
- mBfIRBuilder->CreateStore(thisArg, gepInstance);
- argIdx++;
- }
- }
- else
- {
- mBfIRBuilder->CreateStore(llvmArgs[0], gepInstance);
- argIdx++;
- }
- dataIdx++;
- }
- for (int paramIdx = 0; paramIdx < (int)methodInstance->GetParamCount(); paramIdx++, dataIdx++)
- {
- if (methodInstance->IsParamSkipped(paramIdx))
- paramIdx++;
- auto paramType = methodInstance->GetParamType(paramIdx);
- bool paramIsSplat = methodInstance->GetParamIsSplat(paramIdx);
- gepInstance = mBfIRBuilder->CreateInBoundsGEP(deferredAlloca, 0, dataIdx/*, methodDef->mParams[paramIdx]->mName*/);
- if (paramType->IsStruct())
- {
- if (paramIsSplat)
- {
- BfTypedValue splatVal(llvmArgs[argIdx], paramType, BfTypedValueKind_SplatHead);
- BfTypedValue aggVal = AggregateSplat(splatVal, &llvmArgs[argIdx]);
- aggVal = LoadValue(aggVal);
- mBfIRBuilder->CreateStore(aggVal.mValue, gepInstance);
- BfTypeUtils::SplatIterate([&](BfType* checkType) { argIdx++; }, paramType);
- }
- else
- {
- auto val = mBfIRBuilder->CreateLoad(llvmArgs[argIdx]);
- mBfIRBuilder->CreateStore(val, gepInstance);
- argIdx++;
- }
- }
- else
- {
- mBfIRBuilder->CreateStore(llvmArgs[argIdx], gepInstance);
- argIdx++;
- }
- }
- mBfIRBuilder->CreateStore(mBfIRBuilder->CreateBitCast(deferredAlloca, mBfIRBuilder->MapType(deferredCallEntryTypePtr)), listEntry->mDynCallTail);
- deferredCallEntry->mDeferredAlloca = deferredAlloca;
- listEntry->mDynList.PushFront(deferredCallEntry);
- }
- if ((mBfIRBuilder->DbgHasInfo()) && (mHasFullDebugInfo) && (mCompiler->mOptions.mEmitDebugInfo) && (mCurMethodState->mCurScope->mDIScope))
- {
- auto int64Type = GetPrimitiveType(BfTypeCode_Int64);
- auto moduleMethodInstance = deferredCallEntry->mModuleMethodInstance;
- auto methodInstance = moduleMethodInstance.mMethodInstance;
- BfIRMDNode deferDIType;
- if ((deferredMethodCallData != NULL) && (deferredMethodCallData->mDeferDIType))
- {
- deferDIType = deferredMethodCallData->mDeferDIType;
- }
- else
- {
- BfIRMDNode diForwardDecl;
- SizedArray<BfIRMDNode, 8> diFieldTypes;
- if ((mBfIRBuilder->DbgHasInfo()) && (mHasFullDebugInfo))
- {
- String dbgTypeName;
- if (mCompiler->mOptions.IsCodeView())
- dbgTypeName += "_bf::";
- dbgTypeName += typeName;
- diForwardDecl = mBfIRBuilder->DbgCreateReplaceableCompositeType(llvm::dwarf::DW_TAG_structure_type, dbgTypeName, mCurFilePosition.mFileInstance->mDIFile, mCurFilePosition.mFileInstance->mDIFile,
- mCurFilePosition.mCurLine, instSize * 8, instAlign * 8);
- if (methodInstance != NULL)
- {
- // We make a fake member to get inserted into the DbgModule data so we can show what method this deferred call goes to
- StringT<128> mangledName;
- BfMangler::Mangle(mangledName, mCompiler->GetMangleKind(), methodInstance);
- auto memberType = mBfIRBuilder->DbgCreateMemberType(diForwardDecl, mangledName, mCurFilePosition.mFileInstance->mDIFile, mCurFilePosition.mCurLine,
- 0, 0, -1, 0, mBfIRBuilder->DbgGetType(int64Type));
- diFieldTypes.push_back(memberType);
- }
- }
- for (int i = 0; i < (int)types.size(); i++)
- {
- auto type = types[i];
- auto memberName = memberNames[i];
- if ((mBfIRBuilder->DbgHasInfo()) && (mHasFullDebugInfo))
- {
- int memberFlags = 0;
- auto memberType = mBfIRBuilder->DbgCreateMemberType(diForwardDecl, memberName, mCurFilePosition.mFileInstance->mDIFile, mCurFilePosition.mCurLine,
- type->mSize * 8, type->mAlign * 8, memberPositions[i] * 8, memberFlags, mBfIRBuilder->DbgGetType(type));
- diFieldTypes.push_back(memberType);
- }
- }
- int diFlags = 0;
- mBfIRBuilder->DbgMakePermanent(diForwardDecl, BfIRMDNode(), diFieldTypes);
- deferDIType = mBfIRBuilder->DbgCreatePointerType(diForwardDecl);
- if (deferredMethodCallData != NULL)
- deferredMethodCallData->mDeferDIType = deferDIType;
- }
- // We don't actually want to see this, and it doesn't emit properly in LLVM CodeView anyway - it only accepts static allocs,
- // not dynamic allocas
- String varName = StrFormat("$__deferredCall_%d", mCurMethodState->mDeferredLoopListEntryCount);
- mCurMethodState->mDeferredLoopListEntryCount++;
- auto diVariable = mBfIRBuilder->DbgCreateAutoVariable(mCurMethodState->mCurScope->mDIScope,
- varName, mCurFilePosition.mFileInstance->mDIFile, mCurFilePosition.mCurLine, deferDIType);
- mBfIRBuilder->DbgInsertDeclare(deferredAlloca, diVariable);
- }
- return true;
- }
- BfDeferredCallEntry* BfModule::AddDeferredBlock(BfBlock* block, BfScopeData* scopeData, Array<BfDeferredCapture>* captures)
- {
- BfDeferredCallEntry* deferredCallEntry = new BfDeferredCallEntry();
- deferredCallEntry->mDeferredBlock = block;
- if (captures != NULL)
- deferredCallEntry->mCaptures = *captures;
- AddDeferredCallEntry(deferredCallEntry, scopeData);
- return deferredCallEntry;
- }
- BfDeferredCallEntry* BfModule::AddDeferredCall(const BfModuleMethodInstance& moduleMethodInstance, SizedArrayImpl<BfIRValue>& llvmArgs, BfScopeData* scopeData, BfAstNode* srcNode, bool bypassVirtual, bool doNullCheck, bool isAllocaFunc)
- {
- BfDeferredCallEntry* deferredCallEntry = new BfDeferredCallEntry();
- BF_ASSERT(moduleMethodInstance);
- deferredCallEntry->mModuleMethodInstance = moduleMethodInstance;
- deferredCallEntry->mIsAllocaFunc = isAllocaFunc;
- for (auto arg : llvmArgs)
- {
- deferredCallEntry->mScopeArgs.push_back(arg);
- }
- deferredCallEntry->mSrcNode = srcNode;
- deferredCallEntry->mBypassVirtual = bypassVirtual;
- deferredCallEntry->mDoNullCheck = doNullCheck;
- if (!AddDeferredCallEntry(deferredCallEntry, scopeData))
- return NULL;
- return deferredCallEntry;
- }
- void BfModule::EmitDeferredCall(BfModuleMethodInstance moduleMethodInstance, SizedArrayImpl<BfIRValue>& llvmArgs, BfDeferredBlockFlags flags)
- {
- if (moduleMethodInstance.mMethodInstance->GetOwner()->IsInstanceOf(mCompiler->mInternalTypeDef))
- {
- if (moduleMethodInstance.mMethodInstance->mMethodDef->mName.StartsWith("SetDeleted"))
- {
- intptr typeSize = 0;
- intptr typeAlign = 1;
- intptr clearSize = 0;
- bool isDynSize = false;
- bool mayBeZero = false;
- auto ptrValue = llvmArgs[0];
- BfIRValue arraySize;
- if ((moduleMethodInstance.mMethodInstance->mMethodDef->mName == "SetDeleted") ||
- (moduleMethodInstance.mMethodInstance->mMethodDef->mName == "SetDeletedArray"))
- {
- auto constant = mBfIRBuilder->GetConstant(llvmArgs[1]);
- if (constant != NULL)
- typeSize = constant->mInt64;
- constant = mBfIRBuilder->GetConstant(llvmArgs[2]);
- if (constant != NULL)
- typeAlign = constant->mInt64;
- if (llvmArgs.size() >= 4)
- arraySize = llvmArgs[3];
- intptr allocSize = typeSize;
- if (arraySize)
- {
- allocSize = BF_ALIGN(typeSize, typeAlign);
- auto constant = mBfIRBuilder->GetConstant(arraySize);
- if (constant != NULL)
- allocSize = allocSize * (intptr)constant->mInt64;
- else
- {
- isDynSize = true;
- mayBeZero = true;
- }
- }
- clearSize = BF_MIN(allocSize, mSystem->mPtrSize);
- }
- else if (moduleMethodInstance.mMethodInstance->mMethodDef->mName == "SetDeletedX")
- {
- // Note: this infers that mayBeZero is false still, because the deferred call would not have
- // been added if the array size was zero
- typeSize = 1;
- clearSize = typeSize;
- arraySize = llvmArgs[1];
- isDynSize = true;
- }
- else if (moduleMethodInstance.mMethodInstance->mMethodDef->mName == "SetDeleted1")
- {
- clearSize = 1;
- }
- else if (moduleMethodInstance.mMethodInstance->mMethodDef->mName == "SetDeleted2")
- {
- clearSize = 2;
- }
- else if (moduleMethodInstance.mMethodInstance->mMethodDef->mName == "SetDeleted4")
- {
- clearSize = 4;
- }
- else if (moduleMethodInstance.mMethodInstance->mMethodDef->mName == "SetDeleted8")
- {
- clearSize = 8;
- }
- else if (moduleMethodInstance.mMethodInstance->mMethodDef->mName == "SetDeleted16")
- {
- clearSize = 16;
- }
- if (clearSize > 0)
- {
- BfTypeCode clearTypeCode = BfTypeCode_Int8;
- if (clearSize >= mSystem->mPtrSize)
- clearTypeCode = BfTypeCode_IntPtr;
- else if (clearSize >= 4)
- clearTypeCode = BfTypeCode_Int32;
- else if (clearSize >= 2)
- clearTypeCode = BfTypeCode_Int16;
- auto intType = GetPrimitiveType(clearTypeCode);
- auto intPtrType = CreatePointerType(intType);
- if (isDynSize)
- {
- if (clearSize >= mSystem->mPtrSize)
- {
- auto ddSize1Block = mBfIRBuilder->CreateBlock("DDSize1");
- auto ddDoneBlock = mBfIRBuilder->CreateBlock("DDDone");
- auto cmp = mBfIRBuilder->CreateCmpGT(arraySize, mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 0), true);
- mBfIRBuilder->CreateCondBr(cmp, ddSize1Block, ddDoneBlock);
- mBfIRBuilder->AddBlock(ddSize1Block);
- mBfIRBuilder->SetInsertPoint(ddSize1Block);
- auto intPtrVal = mBfIRBuilder->CreateBitCast(ptrValue, mBfIRBuilder->MapType(intPtrType));
- mBfIRBuilder->CreateStore(mBfIRBuilder->CreateConst(clearTypeCode, (uint64)0xDDDDDDDDDDDDDDDDULL), intPtrVal);
- mBfIRBuilder->CreateBr(ddDoneBlock);
- mBfIRBuilder->AddBlock(ddDoneBlock);
- mBfIRBuilder->SetInsertPoint(ddDoneBlock);
- if ((flags & BfDeferredBlockFlag_MoveNewBlocksToEnd) != 0)
- {
- mCurMethodState->mCurScope->mAtEndBlocks.push_back(ddSize1Block);
- mCurMethodState->mCurScope->mAtEndBlocks.push_back(ddDoneBlock);
- }
- }
- else
- {
- // If we allocate at least this many then we can do an IntPtr-sized marking, otherwise just one element's worth
- int intPtrCount = (int)((mSystem->mPtrSize + typeSize - 1) / typeSize);
- BfIRBlock ddSizePtrBlock = mBfIRBuilder->CreateBlock("DDSizePtr");
- BfIRBlock ddCheck1Block = mBfIRBuilder->CreateBlock("DDCheck1");
- BfIRBlock ddSize1Block;
- if (mayBeZero)
- ddSize1Block = mBfIRBuilder->CreateBlock("DDSize1");
- BfIRBlock ddDoneBlock = mBfIRBuilder->CreateBlock("DDDone");
- auto intptrType = GetPrimitiveType(BfTypeCode_IntPtr);
- auto intptrPtrType = CreatePointerType(intptrType);
- auto cmpPtr = mBfIRBuilder->CreateCmpGTE(arraySize, mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, intPtrCount), true);
- mBfIRBuilder->CreateCondBr(cmpPtr, ddSizePtrBlock, ddCheck1Block);
- mBfIRBuilder->AddBlock(ddSizePtrBlock);
- mBfIRBuilder->SetInsertPoint(ddSizePtrBlock);
- auto intptrPtrVal = mBfIRBuilder->CreateBitCast(ptrValue, mBfIRBuilder->MapType(intptrPtrType));
- mBfIRBuilder->CreateStore(mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, (uint64)0xDDDDDDDDDDDDDDDDULL), intptrPtrVal);
- mBfIRBuilder->CreateBr(ddDoneBlock);
- mBfIRBuilder->AddBlock(ddCheck1Block);
- mBfIRBuilder->SetInsertPoint(ddCheck1Block);
- if (mayBeZero)
- {
- auto cmp1 = mBfIRBuilder->CreateCmpGT(arraySize, mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 0), true);
- mBfIRBuilder->CreateCondBr(cmp1, ddSize1Block, ddDoneBlock);
- mBfIRBuilder->AddBlock(ddSize1Block);
- mBfIRBuilder->SetInsertPoint(ddSize1Block);
- }
- auto intPtrVal = mBfIRBuilder->CreateBitCast(ptrValue, mBfIRBuilder->MapType(intPtrType));
- mBfIRBuilder->CreateStore(mBfIRBuilder->CreateConst(clearTypeCode, (uint64)0xDDDDDDDDDDDDDDDDULL), intPtrVal);
- mBfIRBuilder->CreateBr(ddDoneBlock);
- mBfIRBuilder->AddBlock(ddDoneBlock);
- mBfIRBuilder->SetInsertPoint(ddDoneBlock);
- if ((flags & BfDeferredBlockFlag_MoveNewBlocksToEnd) != 0)
- {
- mCurMethodState->mCurScope->mAtEndBlocks.push_back(ddSizePtrBlock);
- mCurMethodState->mCurScope->mAtEndBlocks.push_back(ddCheck1Block);
- if (mayBeZero)
- mCurMethodState->mCurScope->mAtEndBlocks.push_back(ddSize1Block);
- mCurMethodState->mCurScope->mAtEndBlocks.push_back(ddDoneBlock);
- }
- }
- }
- else
- {
- auto intPtrVal = mBfIRBuilder->CreateBitCast(ptrValue, mBfIRBuilder->MapType(intPtrType));
- mBfIRBuilder->CreateStore(mBfIRBuilder->CreateConst(clearTypeCode, (uint64)0xDDDDDDDDDDDDDDDDULL), intPtrVal);
- }
- }
- return;
- }
- }
- if (moduleMethodInstance.mMethodInstance == mContext->mValueTypeDeinitSentinel)
- {
- BF_ASSERT(llvmArgs.size() == 3);
- auto sizeConstant = mBfIRBuilder->GetConstant(llvmArgs[1]);
- int clearSize = BF_MIN(sizeConstant->mInt32, 32);
- auto alignConstant = mBfIRBuilder->GetConstant(llvmArgs[2]);
- int clearAlign = alignConstant->mInt32;
- mBfIRBuilder->CreateMemSet(llvmArgs[0], GetConstValue8(0xDD), GetConstValue(clearSize), clearAlign);
- return;
- }
- auto methodInstance = moduleMethodInstance.mMethodInstance;
- auto methodOwner = methodInstance->mMethodInstanceGroup->mOwner;
- bool isDtor = methodInstance->mMethodDef->mMethodType == BfMethodType_Dtor;
- bool isScopeDtor = isDtor && ((flags & BfDeferredBlockFlag_BypassVirtual) != 0);
- if ((isDtor) && (methodInstance->GetParamCount() != 0))
- {
- // Dtor declared with params
- AssertErrorState();
- return;
- }
- BfIRBlock nullLabel;
- BfIRBlock notNullLabel;
- if ((flags & BfDeferredBlockFlag_DoNullChecks) != 0)
- {
- nullLabel = mBfIRBuilder->CreateBlock("deferred.isNull");
- notNullLabel = mBfIRBuilder->CreateBlock("deferred.notNull");
- auto notNullVal = mBfIRBuilder->CreateIsNotNull(llvmArgs[0]);
- mBfIRBuilder->CreateCondBr(notNullVal, notNullLabel, nullLabel);
- mBfIRBuilder->AddBlock(notNullLabel);
- mBfIRBuilder->SetInsertPoint(notNullLabel);
- }
- bool skipAccessCheck = false;
- if ((flags & BfDeferredBlockFlag_SkipObjectAccessCheck) != 0)
- skipAccessCheck = true;
- if ((!methodInstance->mMethodDef->mIsStatic) && (methodOwner->IsObjectOrInterface()) && (!isScopeDtor) &&
- (!skipAccessCheck))
- {
- EmitObjectAccessCheck(BfTypedValue(llvmArgs[0], methodOwner));
- }
- BfExprEvaluator expressionEvaluator(this);
- auto func = moduleMethodInstance.mFunc;
- if ((flags & BfDeferredBlockFlag_IsAllocaFunc) != 0)
- func = mBfIRBuilder->CreateLoad(func);
- expressionEvaluator.CreateCall(NULL, moduleMethodInstance.mMethodInstance, func, ((flags & BfDeferredBlockFlag_BypassVirtual) != 0), llvmArgs);
- if ((flags & BfDeferredBlockFlag_DoNullChecks) != 0)
- {
- mBfIRBuilder->CreateBr(nullLabel);
- mBfIRBuilder->AddBlock(nullLabel);
- mBfIRBuilder->SetInsertPoint(nullLabel);
- if (!mBfIRBuilder->mIgnoreWrites)
- {
- if ((flags & BfDeferredBlockFlag_MoveNewBlocksToEnd) != 0)
- {
- mCurMethodState->mCurScope->mAtEndBlocks.push_back(notNullLabel);
- mCurMethodState->mCurScope->mAtEndBlocks.push_back(nullLabel);
- }
- }
- }
- }
- void BfModule::EmitDeferredCallProcessorInstances(BfScopeData* scopeData)
- {
- BF_ASSERT(scopeData->mDone);
- for (auto& deferredProcessor : scopeData->mDeferredCallProcessorInstances)
- {
- SetAndRestoreValue<bool> prevHadReturn(mCurMethodState->mHadReturn, false);
- SetAndRestoreValue<bool> prevInPostReturn(mCurMethodState->mInPostReturn, false);
- SetAndRestoreValue<bool> prevLeftBlockUncond(mCurMethodState->mLeftBlockUncond, false);
- auto prevBlock = mBfIRBuilder->GetInsertBlock();
- mBfIRBuilder->AddBlock(deferredProcessor.mProcessorBlock);
- mBfIRBuilder->SetInsertPoint(deferredProcessor.mProcessorBlock);
- EmitDeferredCallProcessor(scopeData, deferredProcessor.mDeferredCallEntry->mDynList, deferredProcessor.mDeferredCallEntry->mDynCallTail);
- mBfIRBuilder->CreateBr(deferredProcessor.mContinueBlock);
- mBfIRBuilder->SetInsertPoint(prevBlock);
- }
- }
- void BfModule::EmitDeferredCall(BfScopeData* scopeData, BfDeferredCallEntry& deferredCallEntry, bool moveBlocks)
- {
- if ((mCompiler->mIsResolveOnly) && (!mIsComptimeModule) && (deferredCallEntry.mHandlerCount > 0))
- {
- // We only want to process deferred blocks once, otherwise it could significantly slow down autocompletion
- return;
- }
- deferredCallEntry.mHandlerCount++;
- if (deferredCallEntry.IsDynList())
- {
- if (scopeData->mDone)
- {
- EmitDeferredCallProcessor(scopeData, deferredCallEntry.mDynList, deferredCallEntry.mDynCallTail);
- }
- else
- {
- BfDeferredCallProcessorInstance deferredProcessor;
- deferredProcessor.mProcessorBlock = mBfIRBuilder->CreateBlock("dyn.processor");
- deferredProcessor.mContinueBlock = mBfIRBuilder->CreateBlock("dyn.continue");
- deferredProcessor.mDeferredCallEntry = &deferredCallEntry;
- scopeData->mDeferredCallProcessorInstances.Add(deferredProcessor);
- mBfIRBuilder->CreateBr(deferredProcessor.mProcessorBlock);
- mBfIRBuilder->AddBlock(deferredProcessor.mContinueBlock);
- mBfIRBuilder->SetInsertPoint(deferredProcessor.mContinueBlock);
- SetIllegalSrcPos();
- EmitEnsureInstructionAt();
- }
- return;
- }
- if (deferredCallEntry.mDeferredBlock != NULL)
- {
- // Only show warnings on the first pass
- // For errors, show on the first pass OR as long as we haven't gotten any errors within this method. I'm not sure if there's a case
- // where the first emission succeeds but a subsequent one would fail, but we leave this logic to handle that possibility
- SetAndRestoreValue<bool> prevIgnoreErrors(mIgnoreErrors, (deferredCallEntry.mHandlerCount > 1) && (mCurMethodInstance->mHasFailed));
- SetAndRestoreValue<bool> prevIgnoreWarnings(mIgnoreWarnings, (deferredCallEntry.mHandlerCount > 1));
- BfScopeData scopeData;
- mCurMethodState->AddScope(&scopeData);
- NewScopeState();
- for (auto& capture : deferredCallEntry.mCaptures)
- {
- BfLocalVariable* localVar = new BfLocalVariable();
- localVar->mIsReadOnly = true;
- localVar->mAssignedKind = BfLocalVarAssignKind_Unconditional;
- localVar->mReadFromId = 0;
- localVar->mName = capture.mName;
- localVar->mValue = capture.mValue.mValue;
- localVar->mResolvedType = capture.mValue.mType;
- if ((mBfIRBuilder->DbgHasInfo()) && (!localVar->mResolvedType->IsValuelessType()))
- {
- auto addr = CreateAlloca(localVar->mResolvedType);
- mBfIRBuilder->CreateAlignedStore(localVar->mValue, addr, localVar->mResolvedType->mAlign);
- localVar->mAddr = addr;
- }
- AddLocalVariableDef(localVar, true);
- }
- SetAndRestoreValue<BfAstNode*> prevCustomAttribute(mCurMethodState->mEmitRefNode, deferredCallEntry.mEmitRefNode);
- VisitEmbeddedStatement(deferredCallEntry.mDeferredBlock, NULL, BfEmbeddedStatementFlags_IsDeferredBlock);
- RestoreScopeState();
- return;
- }
- auto args = deferredCallEntry.mScopeArgs;
- if (deferredCallEntry.mArgsNeedLoad)
- {
- for (auto& arg : args)
- {
- if (!arg.IsConst())
- arg = mBfIRBuilder->CreateLoad(arg);
- }
- }
- if (deferredCallEntry.mCastThis)
- {
- args[0] = mBfIRBuilder->CreateBitCast(args[0], mBfIRBuilder->MapTypeInstPtr(deferredCallEntry.mModuleMethodInstance.mMethodInstance->GetOwner()));
- }
- BfDeferredBlockFlags flags = BfDeferredBlockFlag_None;
- if (deferredCallEntry.mBypassVirtual)
- flags = (BfDeferredBlockFlags)(flags | BfDeferredBlockFlag_BypassVirtual);
- if (deferredCallEntry.mDoNullCheck)
- flags = (BfDeferredBlockFlags)(flags | BfDeferredBlockFlag_DoNullChecks | BfDeferredBlockFlag_SkipObjectAccessCheck | BfDeferredBlockFlag_MoveNewBlocksToEnd);
- if (moveBlocks)
- flags = (BfDeferredBlockFlags)(flags | BfDeferredBlockFlag_MoveNewBlocksToEnd);
- if (deferredCallEntry.mIsAllocaFunc)
- flags = (BfDeferredBlockFlags)(flags | BfDeferredBlockFlag_IsAllocaFunc);
- EmitDeferredCall(deferredCallEntry.mModuleMethodInstance, args, flags);
- }
- void BfModule::EmitDeferredCallProcessor(BfScopeData* scopeData, SLIList<BfDeferredCallEntry*>& callEntries, BfIRValue callTail)
- {
- int64 collisionId = 0;
- struct _CallInfo
- {
- BfModuleMethodInstance mModuleMethodInstance;
- bool mBypassVirtual;
- bool mIsAllocaFunc;
- };
- //typedef std::map<int64, _CallInfo> MapType;
- //MapType methodInstanceMap;
- Dictionary<int64, _CallInfo> methodInstanceMap;
- int blockCount = 0;
- HashSet<BfMethodInstance*> nullCheckMethodSet;
- BfDeferredCallEntry* deferredCallEntry = callEntries.mHead;
- while (deferredCallEntry != NULL)
- {
- BfModuleMethodInstance moduleMethodInstance = deferredCallEntry->mModuleMethodInstance;
- int64 methodId = 0;
- if (moduleMethodInstance.mMethodInstance != NULL)
- {
- int64 idHash = moduleMethodInstance.mMethodInstance->mIdHash;
- auto deferredMethodCallData = mDeferredMethodCallData[moduleMethodInstance.mMethodInstance];
- BF_ASSERT(deferredMethodCallData->mMethodId != 0);
- //methodInstanceMap[deferredMethodCallData->mMethodId] = moduleMethodInstance;
- _CallInfo* callInfo = NULL;
- if (methodInstanceMap.TryAdd(deferredMethodCallData->mMethodId, NULL, &callInfo))
- {
- callInfo->mModuleMethodInstance = moduleMethodInstance;
- callInfo->mBypassVirtual = deferredCallEntry->mBypassVirtual;
- callInfo->mIsAllocaFunc = deferredCallEntry->mIsAllocaFunc;
- }
- else
- {
- // Only bypass virtual if ALL these calls are devirtualized
- callInfo->mBypassVirtual &= deferredCallEntry->mBypassVirtual;
- }
- }
- else
- blockCount++;
- if (deferredCallEntry->mDoNullCheck)
- nullCheckMethodSet.Add(deferredCallEntry->mModuleMethodInstance.mMethodInstance);
- deferredCallEntry = deferredCallEntry->mNext;
- }
- bool moveBlocks = mCurMethodState->mCurScope != mCurMethodState->mTailScope;
- auto valueScopeStart = ValueScopeStart();
- if (valueScopeStart)
- mBfIRBuilder->SetName(valueScopeStart, "deferredScopeVal");
- BfIRBlock condBB = mBfIRBuilder->CreateBlock("deferCall.cond", true);
- if (moveBlocks)
- mCurMethodState->mCurScope->mAtEndBlocks.push_back(condBB);
- mBfIRBuilder->CreateBr(condBB);
- auto deferredCallEntryType = ResolveTypeDef(mCompiler->mDeferredCallTypeDef);
- auto deferredCallEntryTypePtr = CreatePointerType(deferredCallEntryType);
- BfIRBlock bodyBB = mBfIRBuilder->CreateBlock("deferCall.body");
- if (moveBlocks)
- mCurMethodState->mCurScope->mAtEndBlocks.push_back(bodyBB);
- BfIRBlock endBB = mBfIRBuilder->CreateBlock("deferCall.end");
- if (moveBlocks)
- mCurMethodState->mCurScope->mAtEndBlocks.push_back(endBB);
- BfIRBlock exitBB = endBB;
- BfIRValue deferredCallTail;
- mBfIRBuilder->SetInsertPoint(condBB);
- deferredCallTail = mBfIRBuilder->CreateLoad(callTail);
- auto isNotNull = mBfIRBuilder->CreateIsNotNull(deferredCallTail);
- ValueScopeEnd(valueScopeStart);
- mBfIRBuilder->CreateCondBr(isNotNull, bodyBB, exitBB);
- mBfIRBuilder->AddBlock(bodyBB);
- mBfIRBuilder->SetInsertPoint(bodyBB);
- BfIRValue switchInst;
- bool wantsSwitch = ((int)methodInstanceMap.size() + blockCount) > 1;
- if (blockCount > 0)
- {
- // A block may embed a switch so we need a switch whenever we have blocks
- wantsSwitch = true;
- }
- if (mCurMethodState->mCancelledDeferredCall)
- wantsSwitch = true;
- if (wantsSwitch)
- {
- if (IsTargetingBeefBackend())
- deferredCallTail = mBfIRBuilder->CreateLoad(callTail);
- auto idPtr = mBfIRBuilder->CreateInBoundsGEP(deferredCallTail, 0, 1); // mMethodId
- auto id = mBfIRBuilder->CreateLoad(idPtr);
- switchInst = mBfIRBuilder->CreateSwitch(id, exitBB, (int)methodInstanceMap.size());
- ValueScopeEnd(valueScopeStart);
- }
- BfDeferredCallEntry* prevHead = callEntries.mHead;
- BfDeferredCallEntry* prevCallEntry = NULL;
- HashSet<BfDeferredCallEntry*> handledSet;
- deferredCallEntry = callEntries.mHead;
- while (deferredCallEntry != NULL)
- {
- auto block = deferredCallEntry->mDeferredBlock;
- if (block == NULL)
- {
- deferredCallEntry = deferredCallEntry->mNext;
- continue;
- }
- int64 blockId = deferredCallEntry->mBlockId;
- //auto itr = handledSet.insert(deferredCallEntry);
- //if (!itr.second)
- if (!handledSet.Add(deferredCallEntry))
- {
- // Already handled, can happen if we defer again within the block
- deferredCallEntry = deferredCallEntry->mNext;
- continue;
- }
- if (switchInst)
- {
- String caseName = StrFormat("deferCall.%s", BfTypeUtils::HashEncode64(blockId).c_str());
- auto caseBB = mBfIRBuilder->CreateBlock(caseName, true);
- if (moveBlocks)
- mCurMethodState->mCurScope->mAtEndBlocks.push_back(caseBB);
- mBfIRBuilder->AddSwitchCase(switchInst, GetConstValue64(blockId), caseBB);
- mBfIRBuilder->SetInsertPoint(caseBB);
- }
- // Update .mDeferredAlloca to use the deferredCallTail
- if (IsTargetingBeefBackend())
- deferredCallTail = mBfIRBuilder->CreateLoad(callTail);
- auto nextPtr = mBfIRBuilder->CreateInBoundsGEP(deferredCallTail, 0, 2); // mNext
- auto next = mBfIRBuilder->CreateLoad(nextPtr);
- mBfIRBuilder->CreateStore(next, callTail);
- deferredCallEntry->mDeferredAlloca = mBfIRBuilder->CreateBitCast(deferredCallTail, mBfIRBuilder->GetType(deferredCallEntry->mDeferredAlloca));
- int dataIdx = 3;
- // Update .mCaptures to contain the stored values at the time the defer occurred
- for (int captureIdx = 0; captureIdx < (int)deferredCallEntry->mCaptures.size(); captureIdx++)
- {
- auto& capture = deferredCallEntry->mCaptures[captureIdx];
- if (!capture.mValue.mType->IsValuelessType())
- {
- auto gepInstance = mBfIRBuilder->CreateInBoundsGEP(deferredCallEntry->mDeferredAlloca, 0, dataIdx);
- capture.mValue.mValue = mBfIRBuilder->CreateLoad(gepInstance);
- dataIdx++;
- }
- }
- auto prevHead = callEntries.mHead;
- EmitDeferredCall(scopeData, *deferredCallEntry, moveBlocks);
- ValueScopeEnd(valueScopeStart);
- mBfIRBuilder->CreateBr(condBB);
- if (prevHead != callEntries.mHead)
- {
- // The list changed, start over and ignore anything we've already handled
- deferredCallEntry = callEntries.mHead;
- }
- else
- deferredCallEntry = deferredCallEntry->mNext;
- }
- // Blocks may have added new method types, so rebuild map
- if (blockCount > 0)
- {
- deferredCallEntry = callEntries.mHead;
- while (deferredCallEntry != NULL)
- {
- BfModuleMethodInstance moduleMethodInstance = deferredCallEntry->mModuleMethodInstance;
- if (moduleMethodInstance.mMethodInstance != NULL)
- {
- auto deferredMethodCallData = mDeferredMethodCallData[moduleMethodInstance.mMethodInstance];
- //methodInstanceMap.insert(MapType::value_type(deferredMethodCallData->mMethodId, moduleMethodInstance));
- _CallInfo* callInfo = NULL;
- if (methodInstanceMap.TryAdd(deferredMethodCallData->mMethodId, NULL, &callInfo))
- {
- callInfo->mModuleMethodInstance = moduleMethodInstance;
- callInfo->mBypassVirtual = deferredCallEntry->mBypassVirtual;
- }
- }
- deferredCallEntry = deferredCallEntry->mNext;
- }
- }
- BfExprEvaluator exprEvaluator(this);
- //for (auto itr = methodInstanceMap.begin(); itr != methodInstanceMap.end(); ++itr)
- for (auto& callInfoKV : methodInstanceMap)
- {
- auto moduleMethodInstance = callInfoKV.mValue.mModuleMethodInstance;
- bool bypassVirtual = callInfoKV.mValue.mBypassVirtual;
- bool isAllocaFunc = callInfoKV.mValue.mIsAllocaFunc;
- auto methodInstance = moduleMethodInstance.mMethodInstance;
- auto methodDef = methodInstance->mMethodDef;
- auto methodOwner = methodInstance->mMethodInstanceGroup->mOwner;
- BfIRValue deferredCallInst = deferredCallTail;
- auto deferredMethodCallData = mDeferredMethodCallData[methodInstance];
- int64 methodId = deferredMethodCallData->mMethodId;
- if (switchInst)
- {
- String caseName = StrFormat("deferCall.%s", BfTypeUtils::HashEncode64(methodId).c_str());
- auto caseBB = mBfIRBuilder->CreateBlock(caseName, true);
- if (moveBlocks)
- mCurMethodState->mCurScope->mAtEndBlocks.push_back(caseBB);
- mBfIRBuilder->AddSwitchCase(switchInst, GetConstValue64(methodId), caseBB);
- mBfIRBuilder->SetInsertPoint(caseBB);
- }
- if (IsTargetingBeefBackend())
- deferredCallTail = mBfIRBuilder->CreateLoad(callTail);
- auto nextPtr = mBfIRBuilder->CreateInBoundsGEP(deferredCallTail, 0, 2); // mNext
- auto next = mBfIRBuilder->CreateLoad(nextPtr);
- mBfIRBuilder->CreateStore(next, callTail);
- deferredCallInst = mBfIRBuilder->CreateBitCast(deferredCallTail, deferredMethodCallData->mDeferTypePtr);
- int paramIdx = 0;
- if (!methodDef->mIsStatic)
- paramIdx = -1;
- SizedArray<BfIRValue, 8> llvmArgs;
- for (int argIdx = 0; paramIdx < methodInstance->GetParamCount(); argIdx++, paramIdx++)
- {
- auto argPtr = mBfIRBuilder->CreateInBoundsGEP(deferredCallInst, 0, argIdx + 2);
- bool isStruct = false;
- bool doSplat = methodInstance->GetParamIsSplat(paramIdx);;
- BfTypedValue typedVal;
- if (paramIdx == -1)
- {
- typedVal = BfTypedValue(argPtr, methodOwner, true);
- }
- else
- {
- auto paramType = methodInstance->GetParamType(paramIdx);
- typedVal = BfTypedValue(argPtr, paramType, true);
- }
- if (doSplat)
- {
- exprEvaluator.SplatArgs(typedVal, llvmArgs);
- continue;
- }
- if ((argIdx == 0) && (!methodDef->mIsStatic))
- {
- // 'this'
- isStruct = methodOwner->IsValueType();
- }
- else
- {
- while (methodInstance->IsParamSkipped(paramIdx))
- paramIdx++;
- if (paramIdx >= methodInstance->GetParamCount())
- break;
- auto paramType = methodInstance->GetParamType(paramIdx);
- isStruct = paramType->IsStruct();
- }
- if (isStruct)
- {
- llvmArgs.push_back(argPtr);
- }
- else
- {
- auto arg = mBfIRBuilder->CreateLoad(argPtr);
- llvmArgs.push_back(arg);
- }
- }
- BfDeferredBlockFlags flags = BfDeferredBlockFlag_None;
- if (moveBlocks)
- flags = (BfDeferredBlockFlags)(flags | BfDeferredBlockFlag_MoveNewBlocksToEnd);
- if (nullCheckMethodSet.Contains(moduleMethodInstance.mMethodInstance))
- flags = (BfDeferredBlockFlags)(flags | BfDeferredBlockFlag_DoNullChecks | BfDeferredBlockFlag_SkipObjectAccessCheck);
- if (bypassVirtual)
- flags = (BfDeferredBlockFlags)(flags | BfDeferredBlockFlag_BypassVirtual);
- if (isAllocaFunc)
- flags = (BfDeferredBlockFlags)(flags | BfDeferredBlockFlag_IsAllocaFunc);
- EmitDeferredCall(moduleMethodInstance, llvmArgs, flags);
- ValueScopeEnd(valueScopeStart);
- mBfIRBuilder->CreateBr(condBB);
- }
- if (endBB)
- {
- mBfIRBuilder->AddBlock(endBB);
- mBfIRBuilder->SetInsertPoint(endBB);
- }
- }
- void BfModule::TryInitVar(BfAstNode* checkNode, BfLocalVariable* localVar, BfTypedValue initValue, BfTypedValue& checkResult)
- {
- BF_ASSERT(!localVar->mAddr);
- localVar->mAddr = AllocLocalVariable(localVar->mResolvedType, localVar->mName);
- auto boolType = GetPrimitiveType(BfTypeCode_Boolean);
- auto varType = localVar->mResolvedType;
- AddDependency(varType, mCurTypeInstance, BfDependencyMap::DependencyFlag_ExprTypeReference);
- if (!initValue)
- {
- AssertErrorState();
- checkResult = BfTypedValue(mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0), boolType);
- return;
- }
- auto initType = initValue.mType;
- bool isDynamicCast = false;
- if (varType->IsGenericParam())
- {
- int pass = 0;
- while (varType->IsGenericParam())
- {
- auto genericParamType = (BfGenericParamType*)varType;
- auto genericParam = GetGenericParamInstance(genericParamType);
- auto typeConstraint = genericParam->mTypeConstraint;
- if ((typeConstraint == NULL) && (genericParam->mGenericParamFlags & (BfGenericParamFlag_Class | BfGenericParamFlag_Interface)))
- typeConstraint = mContext->mBfObjectType;
- if (typeConstraint != NULL)
- varType = typeConstraint;
- else
- break;
- if (++pass >= 100) // Sanity - but we should have caught circular error before
- break;
- }
- initValue = GetDefaultTypedValue(varType, false, BfDefaultValueKind_Undef);
- }
- BfTypeInstance* srcTypeInstance = initValue.mType->ToTypeInstance();
- BfTypeInstance* varTypeInstance = varType->ToTypeInstance();
- if (CanCast(initValue, varType))
- {
- if ((!varType->IsPointer()) && (!varType->IsObjectOrInterface()) && (!varType->IsVar()))
- {
- if (!IsInSpecializedSection())
- {
- if (initValue.mType != varType)
- Warn(BfWarning_CS0472_ValueTypeNullCompare, StrFormat("Variable declaration is always 'true' because static cast cannot fail and a value of type '%s' can never be null",
- TypeToString(varType).c_str()), checkNode);
- else
- Warn(BfWarning_CS0472_ValueTypeNullCompare, StrFormat("Variable declaration is always 'true' because a value of type '%s' can never be null",
- TypeToString(varType).c_str()), checkNode);
- }
- }
- }
- // else if ((initType->IsInterface()) || (initType == mContext->mBfObjectType))
- // {
- // // Interface or System.Object -> *
- // isDynamicCast = true;
- // }
- // else if ((srcTypeInstance != NULL) && (varTypeInstance != NULL) &&
- // ((srcTypeInstance->IsObject()) && (TypeIsSubTypeOf(varTypeInstance, srcTypeInstance))))
- // {
- // // Class downcast
- // isDynamicCast = true;
- // }
- // else if ((!CanCast(GetFakeTypedValue(varType), initType)) && (!initType->IsGenericParam()))
- // {
- // if (!IsInSpecializedSection())
- // {
- // Fail(StrFormat("Cannot convert type '%s' to '%s' via any conversion",
- // TypeToString(initValue.mType).c_str(), TypeToString(varType).c_str()), checkNode);
- // }
- // }
- if (!isDynamicCast)
- {
- //initValue = Cast(checkNode, initValue, varType, (BfCastFlags)(BfCastFlags_Explicit | BfCastFlags_SilentFail));
- initValue = Cast(checkNode, initValue, varType);
- if (!initValue)
- {
- checkResult = BfTypedValue(GetConstValue(0, boolType), boolType);
- }
- else
- {
- if (localVar->mAddr)
- {
- initValue = LoadValue(initValue);
- if (!initValue.mType->IsVar())
- mBfIRBuilder->CreateAlignedStore(initValue.mValue, localVar->mAddr, initValue.mType->mAlign);
- }
- if (varType->IsVar())
- {
- checkResult = GetDefaultTypedValue(boolType, false, BfDefaultValueKind_Undef);
- }
- else if ((varType->IsPointer()) || (varType->IsObjectOrInterface()))
- {
- checkResult = BfTypedValue(mBfIRBuilder->CreateIsNotNull(initValue.mValue), boolType);
- }
- else
- {
- checkResult = BfTypedValue(GetConstValue(1, boolType), boolType);
- }
- }
- return;
- }
- if (mCompiler->IsAutocomplete())
- {
- auto allocaResult = mBfIRBuilder->CreateAlloca(mBfIRBuilder->MapType(boolType));
- auto val = mBfIRBuilder->CreateLoad(allocaResult);
- checkResult = BfTypedValue(val, boolType);
- return;
- }
- int wantTypeId = 0;
- if (!varType->IsGenericParam())
- wantTypeId = varType->mTypeId;
- auto objectType = mContext->mBfObjectType;
- PopulateType(objectType, BfPopulateType_Full);
- initValue = LoadValue(initValue);
- auto prevBB = mBfIRBuilder->GetInsertBlock();
- auto matchBB = mBfIRBuilder->CreateBlock("is.match");
- auto endBB = mBfIRBuilder->CreateBlock("is.done");
- BfIRValue boolResult = CreateAlloca(boolType);
- mBfIRBuilder->CreateStore(mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0), boolResult);
- EmitDynamicCastCheck(initValue, varType, matchBB, endBB);
- AddBasicBlock(matchBB);
- mBfIRBuilder->CreateStore(mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 1), boolResult);
- mBfIRBuilder->CreateBr(endBB);
- AddBasicBlock(endBB);
- checkResult = BfTypedValue(mBfIRBuilder->CreateLoad(boolResult), boolType);
- }
- BfLocalVariable* BfModule::HandleVariableDeclaration(BfVariableDeclaration* varDecl, BfExprEvaluator* exprEvaluator)
- {
- if (mCurMethodState == NULL)
- {
- Fail("Invalid variable declaration", varDecl);
- return NULL;
- }
- BfAutoComplete* bfAutocomplete = NULL;
- // Just a check
- mBfIRBuilder->GetInsertBlock();
- if (mCompiler->mResolvePassData != NULL)
- bfAutocomplete = mCompiler->mResolvePassData->mAutoComplete;
- if (bfAutocomplete != NULL)
- bfAutocomplete->CheckTypeRef(varDecl->mTypeRef, true, true);
- bool isConst = (varDecl->mModSpecifier != NULL) && (varDecl->mModSpecifier->GetToken() == BfToken_Const);
- bool isReadOnly = (varDecl->mModSpecifier != NULL) && (varDecl->mModSpecifier->GetToken() == BfToken_ReadOnly);
- bool isStatic = (varDecl->mModSpecifier != NULL) && (varDecl->mModSpecifier->GetToken() == BfToken_Static);
- BfLocalVariable* localDef = new BfLocalVariable();
- if (varDecl->mNameNode != NULL)
- {
- varDecl->mNameNode->ToString(localDef->mName);
- localDef->mNameNode = BfNodeDynCast<BfIdentifierNode>(varDecl->mNameNode);
- }
- else
- {
- localDef->mName = "val";
- }
- localDef->mIsStatic = isStatic;
- bool handledExprBoolResult = false;
- bool handledVarInit = false;
- bool handledVarStore = false;
- BfType* unresolvedType = NULL;
- BfType* resolvedType = NULL;
- BfTypedValue initValue;
- bool hadVarType = false;
- bool isLet = varDecl->mTypeRef->IsA<BfLetTypeReference>();
- bool initHandled = false;
- auto _DoConditionalInit = [&](BfType* expectedType)
- {
- auto boolType = GetPrimitiveType(BfTypeCode_Boolean);
- auto _EmitCond = [&](BfIRValue condVal, BfTypedValue initValue)
- {
- initValue = Cast(varDecl->mInitializer, initValue, expectedType);
- if (!initValue)
- return;
- initHandled = true;
- if (localDef->mIsReadOnly)
- {
- if ((initValue.IsReadOnly()) ||
- (initValue.mKind == BfTypedValueKind_TempAddr))
- {
- localDef->mAddr = initValue.mValue;
- exprEvaluator->mResult = BfTypedValue(condVal, boolType);
- return;
- }
- }
- localDef->mAddr = AllocLocalVariable(resolvedType, localDef->mName);
- auto doAssignBlock = mBfIRBuilder->CreateBlock("assign");
- auto skipAssignBlock = mBfIRBuilder->CreateBlock("skipAssign");
- auto insertBlock = mBfIRBuilder->GetInsertBlock();
- mBfIRBuilder->CreateCondBr(condVal, doAssignBlock, skipAssignBlock);
- mBfIRBuilder->AddBlock(doAssignBlock);
- mBfIRBuilder->SetInsertPoint(doAssignBlock);
- initValue = LoadValue(initValue);
- mBfIRBuilder->CreateStore(initValue.mValue, localDef->mAddr);
- mBfIRBuilder->CreateBr(skipAssignBlock);
- mBfIRBuilder->AddBlock(skipAssignBlock);
- mBfIRBuilder->SetInsertPoint(skipAssignBlock);
- auto phiVal = mBfIRBuilder->CreatePhi(mBfIRBuilder->MapType(boolType), 2);
- mBfIRBuilder->AddPhiIncoming(phiVal, mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0), insertBlock);
- mBfIRBuilder->AddPhiIncoming(phiVal, mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 1), doAssignBlock);
- exprEvaluator->mResult = BfTypedValue(phiVal, boolType);
- };
- bool handled = false;
- if ((initValue) && (initValue.mType->IsPayloadEnum()))
- {
- auto typeInst = initValue.mType->ToTypeInstance();
- PopulateType(typeInst);
- BfType* outType = NULL;
- int tagId = -1;
- if (typeInst->GetResultInfo(outType, tagId))
- {
- int dscDataIdx = -1;
- auto dscType = typeInst->GetDiscriminatorType(&dscDataIdx);
- BfIRValue dscVal = ExtractValue(initValue, dscDataIdx);
- auto eqVal = mBfIRBuilder->CreateCmpEQ(dscVal, GetConstValue(tagId, dscType));
- exprEvaluator->mResult = BfTypedValue(eqVal, boolType);
- PopulateType(outType);
- if (!outType->IsValuelessType())
- {
- auto outPtrType = CreatePointerType(outType);
- initValue = MakeAddressable(initValue);
- auto payloadVal = mBfIRBuilder->CreateBitCast(initValue.mValue, mBfIRBuilder->MapType(outPtrType));
- auto payload = BfTypedValue(payloadVal, outType, true);
- if ((initValue.mKind == BfTypedValueKind_ReadOnlyAddr) ||
- (initValue.mKind == BfTypedValueKind_TempAddr) ||
- (initValue.mKind == BfTypedValueKind_ReadOnlyTempAddr))
- payload.mKind = initValue.mKind;
- _EmitCond(eqVal, payload);
- }
- handled = true;
- }
- }
- if (handled)
- {
- handledExprBoolResult = true;
- handledVarInit = true;
- handledVarStore = true;
- }
- else if ((initValue) && (initValue.mType->IsNullable()))
- {
- auto underlyingType = initValue.mType->GetUnderlyingType();
- exprEvaluator->mResult = BfTypedValue(ExtractValue(initValue, 2), boolType);
- handledExprBoolResult = true;
- if (!resolvedType->IsNullable())
- {
- if (initValue.IsAddr())
- {
- initValue = BfTypedValue(mBfIRBuilder->CreateInBoundsGEP(initValue.mValue, 0, 1), initValue.mType->GetUnderlyingType(), true);
- }
- else
- {
- initValue = LoadOrAggregateValue(initValue);
- initValue = BfTypedValue(mBfIRBuilder->CreateExtractValue(initValue.mValue, 1), initValue.mType->GetUnderlyingType());
- }
- }
- if ((initValue) && (!initValue.mType->IsValuelessType()))
- {
- _EmitCond(exprEvaluator->mResult.mValue, initValue);
- handledVarStore = true;
- }
- handledVarInit = true;
- }
- else if (initValue)
- {
- BfAstNode* refNode = varDecl;
- if (varDecl->mInitializer != NULL)
- refNode = varDecl->mInitializer;
- TryInitVar(refNode, localDef, initValue, exprEvaluator->mResult);
- handledExprBoolResult = true;
- handledVarInit = true;
- handledVarStore = true;
- }
- };
- if ((varDecl->mTypeRef->IsA<BfVarTypeReference>()) || (isLet))
- {
- hadVarType = true;
- if (varDecl->mInitializer == NULL)
- {
- if (!isLet)
- {
- BfLocalVarEntry* shadowEntry;
- if (mCurMethodState->mLocalVarSet.TryGet(BfLocalVarEntry(localDef), &shadowEntry))
- {
- auto prevLocal = shadowEntry->mLocalVar;
- if (prevLocal->mLocalVarIdx >= mCurMethodState->GetLocalStartIdx())
- {
- BfExprEvaluator exprEvaluator(this);
- initValue = exprEvaluator.LoadLocal(prevLocal);
- resolvedType = initValue.mType;
- unresolvedType = resolvedType;
- localDef->mLocalVarId = prevLocal->mLocalVarId;
- localDef->mAssignedKind = BfLocalVarAssignKind_Unconditional;
- localDef->mIsShadow = true;
- exprEvaluator.mResultLocalVarRefNode = varDecl->mNameNode;
- exprEvaluator.mResultLocalVar = prevLocal;
- exprEvaluator.CheckResultForReading(initValue);
- if (bfAutocomplete != NULL)
- bfAutocomplete->CheckVarResolution(varDecl->mTypeRef, resolvedType);
- }
- }
- }
- if (!initValue)
- {
- Fail("Implicitly-typed variables must be initialized", varDecl);
- initValue = GetDefaultTypedValue(mContext->mBfObjectType);
- }
- }
- else
- {
- if (isConst)
- {
- BfConstResolver constResolver(this);
- initValue = constResolver.Resolve(varDecl->mInitializer);
- }
- else
- {
- BfExprEvaluator valExprEvaluator(this);
- valExprEvaluator.mAllowReadOnlyReference = isLet;
- initValue = CreateValueFromExpression(valExprEvaluator, varDecl->mInitializer, NULL, (BfEvalExprFlags)(BfEvalExprFlags_AllowSplat | BfEvalExprFlags_AllowRefExpr | BfEvalExprFlags_VariableDeclaration));
- if ((exprEvaluator != NULL) && (initValue))
- {
- if (initValue.mType->IsNullable())
- {
- auto nullableElementType = initValue.mType->GetUnderlyingType();
- auto boolType = GetPrimitiveType(BfTypeCode_Boolean);
- initValue = LoadOrAggregateValue(initValue);
- exprEvaluator->mResult = BfTypedValue(mBfIRBuilder->CreateExtractValue(initValue.mValue, nullableElementType->IsValuelessType() ? 1 : 2), boolType);
- handledExprBoolResult = true;
- if (!nullableElementType->IsValuelessType())
- initValue = BfTypedValue(mBfIRBuilder->CreateExtractValue(initValue.mValue, 1), initValue.mType->GetUnderlyingType());
- else
- initValue = BfTypedValue(mBfIRBuilder->GetFakeVal(), nullableElementType);
- }
- else
- {
- auto typeInst = initValue.mType->ToTypeInstance();
- if (typeInst != NULL)
- {
- PopulateType(typeInst);
- BfType* outType = NULL;
- int tagId = -1;
- if (typeInst->GetResultInfo(outType, tagId))
- {
- handledExprBoolResult = true;
- unresolvedType = outType;
- resolvedType = outType;
- isReadOnly = isLet;
- localDef->mIsReadOnly = isLet;
- _DoConditionalInit(outType);
- }
- }
- }
- }
- }
- }
- if (!initValue)
- {
- initValue = GetDefaultTypedValue(GetPrimitiveType(BfTypeCode_Var));
- }
- if (initValue.mType->IsNull())
- {
- Fail("Implicitly-typed variables cannot be initialized to 'null'", varDecl->mInitializer);
- initValue = GetDefaultTypedValue(mContext->mBfObjectType);
- }
- if (unresolvedType == NULL)
- unresolvedType = initValue.mType;
- resolvedType = unresolvedType;
- if ((initValue.IsTempAddr()) && (!localDef->mAddr) && (initValue.mType == resolvedType))
- {
- // Take over value
- localDef->mAddr = initValue.mValue;
- handledVarInit = true;
- if (isLet)
- {
- localDef->mValue = mBfIRBuilder->CreateLoad(localDef->mAddr);
- }
- }
- if (bfAutocomplete != NULL)
- bfAutocomplete->CheckVarResolution(varDecl->mTypeRef, resolvedType);
- }
- else
- {
- BfTypeState typeState;
- typeState.mCurVarInitializer = varDecl->mInitializer;
- SetAndRestoreValue<BfTypeState*> prevTypeState(mContext->mCurTypeState, &typeState);
- BfResolveTypeRefFlags flags = (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoResolveGenericParam | BfResolveTypeRefFlag_AllowRef);
- if (varDecl->mInitializer != NULL)
- flags = (BfResolveTypeRefFlags)(flags | BfResolveTypeRefFlag_AllowInferredSizedArray);
- unresolvedType = ResolveTypeRef(varDecl->mTypeRef, BfPopulateType_Data, flags);
- if (unresolvedType == NULL)
- unresolvedType = GetPrimitiveType(BfTypeCode_Var);
- resolvedType = unresolvedType;
- }
- auto _CheckConst = [&]
- {
- if (initValue.IsAddr())
- {
- isConst = false;
- }
- else if (initValue.mValue.IsConst())
- {
- auto constant = mBfIRBuilder->GetConstant(initValue.mValue);
- // NullPtr is stand-in for GlobalVar during autocomplete
- if ((constant->mConstType == BfConstType_GlobalVar) ||
- (constant->mTypeCode == BfTypeCode_NullPtr))
- {
- // Not really constant
- // localNeedsAddr = false;
- // isConst = false;
- // initHandled = true;
- // localDef->mValue = initValue.mValue;
- if (GetStringPoolIdx(initValue.mValue, mBfIRBuilder) == -1)
- isConst = false;
- }
- }
- };
- localDef->mResolvedType = resolvedType;
- localDef->mIsReadOnly = isReadOnly;
- if (!initHandled)
- {
- if (isLet)
- {
- localDef->mIsReadOnly = true;
- if (initValue)
- {
- if (mBfIRBuilder->IsConstValue(initValue.mValue))
- {
- isConst = true;
- }
- }
- }
- }
- _CheckConst();
- bool localNeedsAddr = false;
- bool allowValueAccess = true;
- if (mHasFullDebugInfo)
- {
- //if (!IsTargetingBeefBackend())
- if (!isConst)
- localNeedsAddr = true;
- /*if (mCurMethodInstance->mMethodDef->mName != "Boop2")
- dbgNeedsAddr = true;*/
- }
- // This is required because of lifetime and LLVM domination rules for certain instances of variable declarations in binary conditionals.
- // IE: if ((something) && (let a = somethingElse))
- if ((exprEvaluator != NULL) && (!isConst))
- {
- localNeedsAddr = true;
- allowValueAccess = false;
- }
- if ((varDecl->mEqualsNode != NULL) && (mCompiler->mResolvePassData != NULL) && (mCompiler->mResolvePassData->mAutoComplete != NULL) && (!initHandled))
- {
- mCompiler->mResolvePassData->mAutoComplete->CheckEmptyStart(varDecl->mEqualsNode, resolvedType);
- }
- BfIRInitType initType = BfIRInitType_NotSet;
- if (varDecl->mInitializer != NULL)
- {
- initType = BfIRInitType_NotNeeded_AliveOnDecl;
- if ((!initValue) && (!initHandled))
- {
- if ((isConst) || (isStatic))
- {
- BfConstResolver constResolver(this);
- initValue = constResolver.Resolve(varDecl->mInitializer, resolvedType, BfConstResolveFlag_ActualizeValues);
- if (!initValue)
- initValue = GetDefaultTypedValue(resolvedType);
- }
- else if (varDecl->mInitializer->IsA<BfUninitializedExpression>())
- {
- // Fake 'is assigned'
- }
- else
- { //
- auto expectedType = resolvedType;
- if (expectedType->IsRef())
- expectedType = expectedType->GetUnderlyingType();
- BfExprEvaluator valExprEvaluator(this);
- valExprEvaluator.mAllowReadOnlyReference = isReadOnly;
- initValue = CreateValueFromExpression(valExprEvaluator, varDecl->mInitializer, expectedType, (BfEvalExprFlags)(BfEvalExprFlags_NoCast | BfEvalExprFlags_AllowRefExpr | BfEvalExprFlags_VariableDeclaration));
- if ((initValue) && (resolvedType->IsUndefSizedArray()))
- {
- int stringId = GetStringPoolIdx(initValue.mValue, mBfIRBuilder);
- if (stringId >= 0)
- {
- BfStringPoolEntry* entry = NULL;
- if (mContext->mStringObjectIdMap.TryGetValue(stringId, &entry))
- resolvedType = CreateSizedArrayType(((BfSizedArrayType*)resolvedType)->mElementType, entry->mString.mLength);
- }
- }
- auto boolType = GetPrimitiveType(BfTypeCode_Boolean);
- if (exprEvaluator != NULL)
- _DoConditionalInit(expectedType);
- if ((!handledVarInit) && (initValue))
- initValue = Cast(varDecl->mInitializer, initValue, resolvedType, BfCastFlags_PreferAddr);
- }
- if ((initValue) && (resolvedType->IsUndefSizedArray()))
- {
- resolvedType = initValue.mType;
- unresolvedType = resolvedType;
- }
- if (auto autoComplete = mCompiler->GetAutoComplete())
- {
- autoComplete->CheckResult(varDecl->mInitializer, initValue);
- }
- }
- if ((!handledVarInit) && (!isConst))
- {
- if (initValue)
- {
- // Handled later
- }
- else if (varDecl->mInitializer->IsA<BfUninitializedExpression>())
- {
- // Fake 'is assigned'
- initType = BfIRInitType_Uninitialized;
- }
- else
- {
- AssertErrorState();
- }
- }
- localDef->mAssignedKind = BfLocalVarAssignKind_Unconditional;
- }
- else
- {
- if (isConst)
- {
- Fail("Const locals must be initialized", varDecl->mModSpecifier);
- initValue = GetDefaultTypedValue(resolvedType, true);
- }
- else if (isReadOnly)
- {
- Fail("Readonly locals must be initialized", varDecl->mModSpecifier);
- initValue = GetDefaultTypedValue(resolvedType, true);
- }
- else if (auto refTypeRef = BfNodeDynCast<BfRefTypeRef>(varDecl->mTypeRef))
- {
- Fail("Ref locals must be initialized", refTypeRef->mRefToken);
- }
- else
- {
- BF_ASSERT(!resolvedType->IsRef());
- }
- }
- PopulateType(resolvedType);
- AddDependency(resolvedType, mCurTypeInstance, BfDependencyMap::DependencyFlag_LocalUsage);
- localDef->mResolvedType = resolvedType;
- _CheckConst();
- if ((initValue.mKind == BfTypedValueKind_TempAddr) && (!initHandled))
- {
- BF_ASSERT(initValue.IsAddr());
- BF_ASSERT(initValue.mType->IsComposite());
- handledVarInit = true;
- handledVarStore = true;
- if (!localDef->mAddr)
- {
- localDef->mAddr = initValue.mValue;
- if (localDef->mIsReadOnly)
- localDef->mValue = mBfIRBuilder->CreateLoad(localDef->mAddr);
- }
- if (WantsLifetimes())
- mCurMethodState->mCurScope->mDeferredLifetimeEnds.push_back(localDef->mAddr);
- }
- if ((!localDef->mAddr) && (!isConst) && (!isStatic) && ((!localDef->mIsReadOnly) || (localNeedsAddr)))
- {
- if ((exprEvaluator != NULL) && (exprEvaluator->mResultIsTempComposite))
- {
- //TODO: Can we remove this one?
- BF_ASSERT(initValue.IsAddr());
- BF_ASSERT(initValue.mType->IsComposite());
- localDef->mAddr = initValue.mValue;
- }
- else
- localDef->mAddr = AllocLocalVariable(resolvedType, localDef->mName);
- }
- if (isStatic)
- {
- String name = mModuleName + "_" + mCurMethodInstance->mMethodDef->mName + "_" + localDef->mName;
- HashContext closureHashCtx;
- closureHashCtx.Mixin(varDecl->mSrcStart);
- uint64 closureHash = closureHashCtx.Finish64();
- name += "$";
- name += BfTypeUtils::HashEncode64(closureHash);
- initValue = LoadValue(initValue);
- if ((initValue) && (!initValue.mValue.IsConst()))
- {
- Fail("Static local variables can only be initialized with a const value", varDecl->mInitializer);
- initValue = BfTypedValue();
- }
- if (!initValue)
- initValue = GetDefaultTypedValue(localDef->mResolvedType);
- if ((!localDef->mResolvedType->IsValuelessType()) && (!localDef->mResolvedType->IsVar()))
- localDef->mAddr = mBfIRBuilder->CreateGlobalVariable(mBfIRBuilder->MapType(localDef->mResolvedType, BfIRPopulateType_Full), false, BfIRLinkageType_Internal, initValue.mValue, name);;
- initHandled = true;
- }
- bool wantsStore = false;
- if ((initValue) && (!handledVarStore) && (!isConst) && (!initHandled))
- {
- initValue = LoadValue(initValue);
- if (initValue.IsSplat())
- {
- BF_ASSERT(!mIsComptimeModule);
- if (!localDef->mAddr)
- localDef->mAddr = AllocLocalVariable(resolvedType, localDef->mName);
- AggregateSplatIntoAddr(initValue, localDef->mAddr);
- initHandled = true;
- }
- else
- {
- initValue = AggregateSplat(initValue);
- localDef->mValue = initValue.mValue;
- if ((localDef->mAddr) && (!localDef->mResolvedType->IsValuelessType()))
- {
- if ((!initValue.mType->IsVar()) && (!initValue.mType->IsValuelessType()))
- wantsStore = true;
- }
- else
- {
- BF_ASSERT(isReadOnly || isLet || initValue.mType->IsValuelessType() || (mBfIRBuilder->mIgnoreWrites));
- }
- }
- }
- if ((localDef->mIsReadOnly) && (!isConst) && (!localDef->mValue) && (!initHandled))
- {
- if (!resolvedType->IsValuelessType())
- {
- AssertErrorState();
- initValue = GetDefaultTypedValue(resolvedType, true, BfDefaultValueKind_Undef);
- localDef->mValue = initValue.mValue;
- }
- }
- if ((!localDef->mAddr) && (!isConst) && ((!localDef->mIsReadOnly) || (localNeedsAddr)))
- {
- localDef->mAddr = AllocLocalVariable(resolvedType, localDef->mName);
- }
- if ((exprEvaluator != NULL) && (!handledExprBoolResult))
- {
- auto boolType = GetPrimitiveType(BfTypeCode_Boolean);
- if (!initValue)
- {
- AssertErrorState();
- exprEvaluator->mResult = BfTypedValue(mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0), boolType);
- }
- else if ((resolvedType->IsPointer()) || (resolvedType->IsObjectOrInterface()))
- {
- exprEvaluator->mResult = BfTypedValue(mBfIRBuilder->CreateIsNotNull(initValue.mValue), boolType);
- }
- else if (resolvedType->IsVar())
- {
- exprEvaluator->mResult = GetDefaultTypedValue(GetPrimitiveType(BfTypeCode_Boolean), false, BfDefaultValueKind_Undef);
- }
- else
- {
- // Always true
- if ((!IsInSpecializedSection()) && (!resolvedType->IsGenericParam()))
- Warn(BfWarning_CS0472_ValueTypeNullCompare, StrFormat("Variable declaration is always 'true' since a value of type '%s' can never be null",
- TypeToString(initValue.mType).c_str()), varDecl);
- exprEvaluator->mResult = BfTypedValue(mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 1), boolType);
- }
- }
- if ((unresolvedType->IsGenericParam()) && (resolvedType->IsValuelessType()) && (mHasFullDebugInfo))
- {
- // We do this in order to be able to bind to lines that contain valueless variable declarations in some generics
- // We don't need to do this in non-generics because the breakpoint will just move to the next line that actually has instructions
- EmitEnsureInstructionAt();
- }
- if ((resolvedType->IsVoid()) && (!IsInSpecializedSection()))
- {
- Warn(0, StrFormat("Variable '%s' is declared as 'void'", localDef->mName.c_str()), varDecl->mTypeRef);
- }
- if ((!handledVarInit) && (isConst))
- localDef->mConstValue = initValue.mValue;
- if (!allowValueAccess)
- localDef->mValue = BfIRValue();
- if (!localDef->mIsShadow)
- CheckVariableDef(localDef);
- ValidateAllocation(localDef->mResolvedType, varDecl->mTypeRef);
- if ((exprEvaluator == NULL) && (varDecl->GetSourceData() != NULL))
- UpdateSrcPos(varDecl);
- localDef->Init();
- if (localDef->mConstValue)
- initType = BfIRInitType_NotNeeded;
- BfLocalVariable* localVar = AddLocalVariableDef(localDef, true, false, BfIRValue(), initType);
- if (wantsStore)
- mBfIRBuilder->CreateAlignedStore(initValue.mValue, localVar->mAddr, localVar->mResolvedType->mAlign);
- if ((mCurMethodState->mConstResolveState != NULL) && (mCurMethodState->mConstResolveState->mInCalcAppend))
- {
- if (localDef->mValue.IsConst())
- localDef->mConstValue = localDef->mValue;
- }
- return localVar;
- }
- BfLocalVariable* BfModule::HandleVariableDeclaration(BfType* type, BfAstNode* nameNode, BfTypedValue val, bool updateSrcLoc, bool forceAddr)
- {
- BfLocalVariable* localDef = new BfLocalVariable();
- nameNode->ToString(localDef->mName);
- localDef->mNameNode = BfNodeDynCast<BfIdentifierNode>(nameNode);
- localDef->mResolvedType = type;
- localDef->mAssignedKind = BfLocalVarAssignKind_Unconditional;
- localDef->mValue = val.mValue;
- if ((!localDef->mIsReadOnly) || (mHasFullDebugInfo))
- {
- localDef->mAddr = AllocLocalVariable(localDef->mResolvedType, localDef->mName);
- if ((val.mValue) && (!localDef->mResolvedType->IsValuelessType()) && (!localDef->mResolvedType->IsVar()))
- {
- if (localDef->mResolvedType->IsRef())
- val = MakeAddressable(val, true, true);
- if (val.IsSplat())
- {
- AggregateSplatIntoAddr(val, localDef->mAddr);
- }
- else
- mBfIRBuilder->CreateAlignedStore(val.mValue, localDef->mAddr, localDef->mResolvedType->mAlign);
- }
- }
- CheckVariableDef(localDef);
- if (nameNode->GetSourceData() != NULL)
- UpdateSrcPos(nameNode);
- localDef->Init();
- return AddLocalVariableDef(localDef, true);
- }
- BfLocalVariable* BfModule::HandleVariableDeclaration(BfVariableDeclaration* varDecl, BfTypedValue val, bool updateSrcLoc, bool forceAddr)
- {
- if (varDecl->mEqualsNode != NULL)
- Fail("Unexpected initialization", varDecl->mEqualsNode);
- if (varDecl->mInitializer != NULL)
- CreateValueFromExpression(varDecl->mInitializer);
- auto isLet = varDecl->mTypeRef->IsA<BfLetTypeReference>();
- auto isVar = varDecl->mTypeRef->IsA<BfVarTypeReference>();
- bool isRef = false;
- if (auto varRefTypeReference = BfNodeDynCast<BfVarRefTypeReference>(varDecl->mTypeRef))
- {
- isRef = true;
- isLet = varRefTypeReference->mVarToken->GetToken() == BfToken_Let;
- isVar = varRefTypeReference->mVarToken->GetToken() == BfToken_Var;
- }
- else
- {
- BF_ASSERT(!val.IsAddr());
- }
- auto autoComplete = mCompiler->GetAutoComplete();
- if ((autoComplete != NULL) && ((isLet) || (isVar)))
- autoComplete->CheckVarResolution(varDecl->mTypeRef, val.mType);
- // BfType* type = val.mType;
- // if (type == NULL)
- // {
- // type = ResolveTypeRef(varDecl->mTypeRef);
- // if (type == NULL)
- // type = mContext->mBfObjectType;
- // }
- BfType* type = NULL;
- if ((isLet) || (isVar))
- {
- type = val.mType;
- }
- else
- {
- type = ResolveTypeRef(varDecl->mTypeRef);
- }
- if (type == NULL)
- {
- type = GetPrimitiveType(BfTypeCode_Var);
- val = GetDefaultTypedValue(type);
- }
- if ((type->IsVar()) || (type->IsLet()))
- {
- }
- if (isRef)
- {
- type = CreateRefType(type);
- }
- BfLocalVariable* localDef = new BfLocalVariable();
- if (varDecl->mNameNode != NULL)
- varDecl->mNameNode->ToString(localDef->mName);
- localDef->mNameNode = BfNodeDynCast<BfIdentifierNode>(varDecl->mNameNode);
- localDef->mResolvedType = type;
- localDef->mAssignedKind = BfLocalVarAssignKind_Unconditional;
- localDef->mValue = val.mValue;
- if (isLet)
- {
- localDef->mIsReadOnly = true;
- }
- if ((!localDef->mIsReadOnly) || (mHasFullDebugInfo) || (forceAddr))
- {
- localDef->mAddr = AllocLocalVariable(localDef->mResolvedType, localDef->mName);
- if ((val.mValue) && (!localDef->mResolvedType->IsValuelessType()) && (!localDef->mResolvedType->IsVar()))
- {
- if (localDef->mResolvedType->IsRef())
- val = MakeAddressable(val, true, true);
- if (val.IsSplat())
- {
- AggregateSplatIntoAddr(val, localDef->mAddr);
- }
- else
- mBfIRBuilder->CreateAlignedStore(val.mValue, localDef->mAddr, localDef->mResolvedType->mAlign);
- }
- if (forceAddr)
- localDef->mValue = BfIRValue();
- }
- CheckVariableDef(localDef);
- if ((updateSrcLoc) && (varDecl->GetSourceData() != NULL))
- UpdateSrcPos(varDecl);
- localDef->Init();
- return AddLocalVariableDef(localDef, true);
- }
- void BfModule::CheckTupleVariableDeclaration(BfTupleExpression* tupleExpr, BfType* initType)
- {
- if (initType == NULL)
- return;
- BfTypeInstance* initTupleType = NULL;
- if ((initType != NULL) && (initType->IsTuple()))
- initTupleType = (BfTypeInstance*)initType;
- if (initTupleType != NULL)
- {
- mBfIRBuilder->PopulateType(initTupleType);
- AddDependency(initTupleType, mCurTypeInstance, BfDependencyMap::DependencyFlag_LocalUsage);
- int paramCountDiff = (int)tupleExpr->mValues.size() - (int)initTupleType->mFieldInstances.size();
- if (paramCountDiff > 0)
- {
- Fail(StrFormat("Too many variable names, expected %d fewer.", paramCountDiff), tupleExpr->mValues[(int)initTupleType->mFieldInstances.size()]);
- }
- else if (paramCountDiff < 0)
- {
- BfAstNode* refNode = tupleExpr->mCloseParen;
- if (refNode == NULL)
- refNode = tupleExpr;
- Fail(StrFormat("Too few variable names, expected %d more.", -paramCountDiff), refNode);
- }
- }
- else
- {
- Fail(StrFormat("Value result type '%s' must be a tuple type to be applicable for tuple decomposition", TypeToString(initType).c_str()), tupleExpr);
- }
- }
- void BfModule::HandleTupleVariableDeclaration(BfVariableDeclaration* varDecl, BfTupleExpression* tupleExpr, BfTypedValue initTupleValue, bool isReadOnly, bool isConst, bool forceAddr, BfIRBlock* declBlock)
- {
- BfTypeInstance* initTupleType = NULL;
- if ((initTupleValue) && (initTupleValue.mType->IsTuple()))
- initTupleType = (BfTypeInstance*)initTupleValue.mType;
- CheckTupleVariableDeclaration(tupleExpr, initTupleValue.mType);
- mBfIRBuilder->PopulateType(initTupleValue.mType);
- for (int varIdx = 0; varIdx < (int)tupleExpr->mValues.size(); varIdx++)
- {
- BfType* resolvedType = NULL;
- BfTypedValue initValue;
- if ((initTupleType != NULL) && (varIdx < (int)initTupleType->mFieldInstances.size()))
- {
- auto fieldInstance = &initTupleType->mFieldInstances[varIdx];
- auto fieldDef = fieldInstance->GetFieldDef();
- resolvedType = fieldInstance->GetResolvedType();
- if (fieldInstance->mDataIdx != -1)
- {
- if (initTupleValue.IsAddr())
- {
- initValue = BfTypedValue(mBfIRBuilder->CreateInBoundsGEP(initTupleValue.mValue, 0, fieldInstance->mDataIdx), resolvedType, true);
- initValue = LoadValue(initValue);
- }
- else
- initValue = ExtractValue(initTupleValue, fieldInstance, fieldInstance->mDataIdx);
- }
- BfTupleNameNode* tupleNameNode = NULL;
- if (varIdx < (int)tupleExpr->mNames.size())
- tupleNameNode = tupleExpr->mNames[varIdx];
- if (!fieldDef->IsUnnamedTupleField())
- {
- if (tupleNameNode != NULL)
- {
- if (fieldDef->mName != tupleNameNode->mNameNode->ToString())
- {
- Fail(StrFormat("Mismatched tuple field name, expected '%s'", fieldDef->mName.c_str()), tupleNameNode->mNameNode);
- }
- }
- }
- else if ((tupleNameNode != NULL) && (tupleNameNode->mNameNode != NULL))
- {
- Fail(StrFormat("Unexpected tuple field name, expected unnamed tuple field", fieldDef->mName.c_str()), tupleNameNode->mNameNode);
- }
- }
- else
- {
- resolvedType = mContext->mBfObjectType;
- initValue = GetDefaultTypedValue(resolvedType);
- }
- BfExpression* varNameNode = tupleExpr->mValues[varIdx];
- if (!varNameNode->IsExact<BfIdentifierNode>())
- {
- if (BfTupleExpression* innerTupleExpr = BfNodeDynCast<BfTupleExpression>(varNameNode))
- {
- HandleTupleVariableDeclaration(varDecl, innerTupleExpr, initValue, isReadOnly, isConst, false, declBlock);
- }
- else if (!varNameNode->IsExact<BfUninitializedExpression>())
- Fail("Variable name expected", varNameNode);
- continue;
- }
- bool initHandled = false;
- BfLocalVariable* localDef = new BfLocalVariable();
- varNameNode->ToString(localDef->mName);
- localDef->mNameNode = BfNodeDynCast<BfIdentifierNode>(varNameNode);
- localDef->mResolvedType = resolvedType;
- localDef->mReadFromId = 0; // Don't give usage errors for binds
- if (isReadOnly)
- {
- localDef->mIsReadOnly = true;
- if ((initValue) && (initValue.mValue.IsConst()))
- {
- isConst = true;
- }
- }
- CheckVariableDef(localDef);
- if ((!isConst) && ((forceAddr) || (!localDef->mIsReadOnly) || (mHasFullDebugInfo)))
- {
- localDef->mAddr = AllocLocalVariable(resolvedType, localDef->mName);
- }
- if ((varDecl != NULL) && (varDecl->mEqualsNode != NULL) && (mCompiler->mResolvePassData != NULL) && (mCompiler->mResolvePassData->mAutoComplete != NULL) && (!initHandled))
- {
- mCompiler->mResolvePassData->mAutoComplete->CheckEmptyStart(varDecl->mEqualsNode, resolvedType);
- }
- if ((varDecl == NULL) || (varDecl->mInitializer != NULL))
- {
- if ((!isConst) && (!initHandled))
- {
- if (initValue)
- {
- if (!forceAddr)
- localDef->mValue = initValue.mValue;
- if (localDef->mAddr)
- {
- mBfIRBuilder->CreateStore(initValue.mValue, localDef->mAddr);
- }
- }
- else if ((varDecl == NULL) || (varDecl->mInitializer->IsA<BfUninitializedExpression>()))
- {
- // Fake 'is assigned'
- }
- else
- {
- AssertErrorState();
- }
- }
- localDef->mAssignedKind = BfLocalVarAssignKind_Unconditional;
- }
- else if ((varDecl != NULL) && (varDecl->mInitializer == NULL))
- {
- if (auto refTypeRef = BfNodeDynCast<BfRefTypeRef>(varDecl->mTypeRef))
- {
- Fail("Ref variables must be initialized", refTypeRef->mRefToken);
- }
- else
- {
- BF_ASSERT(!localDef->mResolvedType->IsRef());
- }
- }
- if (isConst)
- localDef->mConstValue = initValue.mValue;
- CheckVariableDef(localDef);
- if ((varDecl != NULL) && (varDecl->GetSourceData() != NULL))
- UpdateSrcPos(varDecl);
- localDef->Init();
- auto defBlock = mBfIRBuilder->GetInsertBlock();
- if (declBlock != NULL)
- mBfIRBuilder->SetInsertPoint(*declBlock);
- AddLocalVariableDef(localDef, true, false, BfIRValue(), BfIRInitType_NotNeeded);
- if (declBlock != NULL)
- mBfIRBuilder->SetInsertPoint(defBlock);
- }
- }
- void BfModule::HandleTupleVariableDeclaration(BfVariableDeclaration* varDecl)
- {
- BfAutoComplete* bfAutocomplete = mCompiler->GetAutoComplete();
- if (bfAutocomplete != NULL)
- bfAutocomplete->CheckTypeRef(varDecl->mTypeRef, true);
- BfTupleExpression* tupleExpr = BfNodeDynCast<BfTupleExpression>(varDecl->mNameNode);
- bool isConst = (varDecl->mModSpecifier != NULL) && (varDecl->mModSpecifier->GetToken() == BfToken_Const);
- bool isReadOnly = (varDecl->mModSpecifier != NULL) && (varDecl->mModSpecifier->GetToken() == BfToken_ReadOnly);
- BfTypedValue initTupleValue;
- bool hadVarType = false;
- bool isLet = varDecl->mTypeRef->IsA<BfLetTypeReference>();
- bool isVar = varDecl->mTypeRef->IsA<BfVarTypeReference>();
- bool wasVarOrLet = isVar || isLet;
- if ((!isLet) && (!isVar))
- {
- ResolveTypeRef(varDecl->mTypeRef);
- Fail("'var' or 'let' expected", varDecl->mTypeRef);
- isVar = true;
- }
- if ((isVar) || (isLet))
- {
- hadVarType = true;
- if (varDecl->mInitializer == NULL)
- {
- Fail("Implicitly-typed variables must be initialized", varDecl);
- initTupleValue = GetDefaultTypedValue(mContext->mBfObjectType);
- }
- else
- {
- if (isConst)
- {
- BfConstResolver constResolver(this);
- initTupleValue = constResolver.Resolve(varDecl->mInitializer);
- }
- else
- {
- initTupleValue = CreateValueFromExpression(varDecl->mInitializer, NULL);
- }
- }
- initTupleValue = LoadValue(initTupleValue);
- if ((bfAutocomplete != NULL) && (wasVarOrLet))
- bfAutocomplete->CheckVarResolution(varDecl->mTypeRef, initTupleValue.mType);
- }
- bool isCompatible = false;
- if (initTupleValue)
- HandleTupleVariableDeclaration(varDecl, tupleExpr, initTupleValue, isLet || isReadOnly, isConst, false);
- else
- AssertErrorState();
- }
- void BfModule::HandleCaseEnumMatch_Tuple(BfTypedValue tupleVal, const BfSizedArray<BfExpression*>& arguments, BfAstNode* tooFewRef, BfIRValue phiVal, BfIRBlock& matchedBlockStart, BfIRBlock& matchedBlockEnd, BfIRBlock& falseBlockStart, BfIRBlock& falseBlockEnd, bool& hadConditional, bool clearOutOnMismatch, bool prevHadFallthrough)
- {
- SetAndRestoreValue<bool> prevInCondBlock(mCurMethodState->mInConditionalBlock);
- auto tupleType = tupleVal.mType->ToTypeInstance();
- struct DeferredAssign
- {
- BfExpression* mExpr;
- BfTypedValue mArgValue;
- BfTypedValue mTupleElement;
- int mFieldIdx;
- bool mIsOut;
- };
- Array<DeferredAssign> deferredAssigns;
- auto autoComplete = mCompiler->GetAutoComplete();
- for (int tupleFieldIdx = 0; tupleFieldIdx < (int)tupleType->mFieldInstances.size(); tupleFieldIdx++)
- {
- auto tupleFieldInstance = &tupleType->mFieldInstances[tupleFieldIdx];
- if (tupleFieldIdx >= arguments.size())
- {
- BfError* error = Fail(StrFormat("Not enough parameters specified, expected %d more.", tupleType->mFieldInstances.size() - (int)arguments.size()), tooFewRef);
- break;
- }
- BfTypedValue tupleElement;
- if (tupleFieldInstance->mDataIdx >= 0)
- {
- tupleElement = ExtractValue(tupleVal, tupleFieldInstance, tupleFieldInstance->mDataIdx);
- }
- else
- tupleElement = GetDefaultTypedValue(tupleFieldInstance->GetResolvedType());
- auto expr = BfNodeDynCast<BfExpression>(arguments[tupleFieldIdx]);
- if (auto varDecl = BfNodeDynCast<BfVariableDeclaration>(expr))
- {
- bool isVarOrLet = (varDecl->mTypeRef->IsExact<BfLetTypeReference>()) || (varDecl->mTypeRef->IsExact<BfVarTypeReference>());
- bool isRef = false;
- if (varDecl->mTypeRef->IsExact<BfVarRefTypeReference>())
- {
- isVarOrLet = true;
- isRef = true;
- }
- if (!isVarOrLet)
- {
- auto wantType = ResolveTypeRef(varDecl->mTypeRef);
- if (wantType == NULL)
- wantType = mContext->mBfObjectType;
- if (wantType != NULL)
- tupleElement = Cast(varDecl->mTypeRef, tupleElement, wantType);
- if (!tupleElement)
- tupleElement = GetDefaultTypedValue(wantType);
- }
- PopulateType(tupleElement.mType);
- if (!isRef)
- tupleElement = LoadValue(tupleElement);
- if (prevHadFallthrough)
- Fail("Destructuring cannot be used when the previous case contains a fallthrough", expr);
-
- CreateOutVariable(expr, varDecl, NULL, tupleElement.mType, tupleElement);
- continue;
- }
- if (auto binOpExpr = BfNodeDynCast<BfBinaryOperatorExpression>(expr))
- {
- if (binOpExpr->mOp == BfBinaryOp_Multiply)
- {
- SetAndRestoreValue<bool> prevIgnoreError(mIgnoreErrors, true);
- auto resolvedType = ResolveTypeRef(binOpExpr->mLeft, NULL);
- prevIgnoreError.Restore();
- if (resolvedType != NULL)
- {
- resolvedType = CreatePointerType(resolvedType);
- PopulateType(tupleElement.mType);
- tupleElement = LoadValue(tupleElement);
- tupleElement = Cast(binOpExpr->mLeft, tupleElement, resolvedType);
- if (prevHadFallthrough)
- Fail("Destructuring cannot be used when the previous case contains a fallthrough", expr);
- auto localVar = HandleVariableDeclaration(resolvedType, binOpExpr->mRight, tupleElement, false, true);
- localVar->mReadFromId = 0; // Don't give usage errors for binds
- auto curScope = mCurMethodState->mCurScope;
- if (curScope->mScopeKind == BfScopeKind_StatementTarget)
- MoveLocalToParentScope(localVar);
- continue;
- }
- }
- }
- if (auto uninitExpr = BfNodeDynCast<BfUninitializedExpression>(expr))
- {
- continue;
- }
- if (tupleFieldInstance->mDataIdx >= 0)
- {
- if (auto tupleExpr = BfNodeDynCast<BfTupleExpression>(expr))
- {
- if (tupleElement.mType->IsTuple())
- {
- BfAstNode* tooFewRef = tupleExpr->mCloseParen;
- if (tupleExpr->mValues.size() > 0)
- tooFewRef = tupleExpr->mValues[tupleExpr->mValues.size() - 1];
- if (tooFewRef == NULL)
- tooFewRef = tupleExpr->mOpenParen;
- HandleCaseEnumMatch_Tuple(tupleElement, tupleExpr->mValues, tooFewRef, phiVal, matchedBlockStart, matchedBlockEnd, falseBlockStart, falseBlockEnd, hadConditional, clearOutOnMismatch, prevHadFallthrough);
- continue;
- }
- }
- }
- if (expr == NULL)
- {
- // Error would have occured in the parser
- //AssertErrorState();
- }
- else
- {
- mCurMethodState->mInConditionalBlock = true;
- auto tupleElementAddr = tupleElement;
- BfTypedValue exprResult;
- if (auto invocationExpr = BfNodeDynCast<BfInvocationExpression>(expr))
- {
- if (auto memberRefExpr = BfNodeDynCast<BfMemberReferenceExpression>(invocationExpr->mTarget))
- {
- if (memberRefExpr->mTarget == NULL)
- {
- if (tupleElement.mType->IsPayloadEnum())
- {
- auto intType = GetPrimitiveType(BfTypeCode_Int32);
- BfTypedValue enumTagVal;
- if (tupleElement.IsAddr())
- {
- enumTagVal = BfTypedValue(mBfIRBuilder->CreateInBoundsGEP(tupleElement.mValue, 0, 2), intType, true);
- enumTagVal = LoadValue(enumTagVal);
- }
- else
- enumTagVal = BfTypedValue(mBfIRBuilder->CreateExtractValue(tupleElement.mValue, 2), intType, false);
- int uncondTagId = -1;
- bool hadConditional = false;
- exprResult = TryCaseEnumMatch(tupleElementAddr, enumTagVal, expr, NULL, NULL, NULL, uncondTagId, hadConditional, clearOutOnMismatch, prevHadFallthrough);
- }
- }
- }
- }
- if (!exprResult)
- {
- tupleElement = LoadValue(tupleElement);
- bool isMatchedBlockEnd = matchedBlockEnd == mBfIRBuilder->GetInsertBlock();
- bool isFalseBlockEnd = falseBlockEnd == mBfIRBuilder->GetInsertBlock();
- BfExprEvaluator exprEvaluator(this);
- exprEvaluator.mExpectingType = tupleFieldInstance->GetResolvedType();
- exprEvaluator.mBfEvalExprFlags = (BfEvalExprFlags)(BfEvalExprFlags_AllowOutExpr | BfEvalExprFlags_AllowRefExpr);
- if (mCurMethodState->mDeferredLocalAssignData != NULL)
- {
- SetAndRestoreValue<bool> prevIsIfCondition(mCurMethodState->mDeferredLocalAssignData->mIsIfCondition, true);
- SetAndRestoreValue<bool> prevIfMayBeSkipped(mCurMethodState->mDeferredLocalAssignData->mIfMayBeSkipped, true);
- exprEvaluator.Evaluate(expr);
- }
- else
- {
- exprEvaluator.Evaluate(expr);
- }
- if (isMatchedBlockEnd)
- matchedBlockEnd = mBfIRBuilder->GetInsertBlock();
- if (isFalseBlockEnd)
- falseBlockEnd = mBfIRBuilder->GetInsertBlock();
- auto argValue = exprEvaluator.mResult;
- if (!argValue)
- continue;
- if (argValue.mType->IsRef())
- {
- auto refType = (BfRefType*)argValue.mType;
- bool isOut = refType->mRefKind == BfRefType::RefKind_Out;
- if ((refType->mRefKind != BfRefType::RefKind_Out) && (refType->mRefKind != BfRefType::RefKind_Ref))
- {
- BfAstNode* refNode = expr;
- if (auto unaryOperatorExpr = BfNodeDynCast<BfUnaryOperatorExpression>(expr))
- refNode = unaryOperatorExpr->mOpToken;
- Fail("Invalid ref type", refNode);
- }
-
- DeferredAssign deferredAssign = { expr, argValue, tupleElement, tupleFieldIdx, isOut };
- deferredAssigns.push_back(deferredAssign);
- if (isOut)
- {
- if (mCurMethodState->mDeferredLocalAssignData != NULL)
- {
- SetAndRestoreValue<bool> prevIsIfCondition(mCurMethodState->mDeferredLocalAssignData->mIsIfCondition, true);
- SetAndRestoreValue<bool> prevIfMayBeSkipped(mCurMethodState->mDeferredLocalAssignData->mIfMayBeSkipped, true);
- exprEvaluator.MarkResultAssigned();
- }
- else
- {
- exprEvaluator.MarkResultAssigned();
- }
- }
- continue;
- }
- if (!argValue.mType->IsValueType())
- argValue = LoadValue(argValue);
- argValue = Cast(expr, argValue, tupleFieldInstance->GetResolvedType());
- if (!argValue)
- continue;
- exprEvaluator.PerformBinaryOperation(expr, expr, BfBinaryOp_Equality, expr, BfBinOpFlag_NoClassify, tupleElement, argValue);
- exprResult = exprEvaluator.mResult;
- }
- if (exprResult)
- {
- hadConditional = true;
- if (phiVal)
- {
- auto insertBlock = mBfIRBuilder->GetInsertBlock();
- mBfIRBuilder->AddPhiIncoming(phiVal, mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0), insertBlock);
- }
- matchedBlockStart = matchedBlockEnd = mBfIRBuilder->CreateBlock("match", false);
- mBfIRBuilder->CreateCondBr(exprResult.mValue, matchedBlockStart, falseBlockStart);
- mBfIRBuilder->AddBlock(matchedBlockStart);
- mBfIRBuilder->SetInsertPoint(matchedBlockStart);
- }
- }
- }
- if (!deferredAssigns.empty())
- mBfIRBuilder->SetInsertPoint(matchedBlockEnd);
- // We assign these only after the value checks succeed
- for (auto& deferredAssign : deferredAssigns)
- {
- auto argValue = RemoveRef(deferredAssign.mArgValue);
- auto tupleElement = Cast(deferredAssign.mExpr, deferredAssign.mTupleElement, argValue.mType);
- if (!tupleElement)
- continue;
- tupleElement = LoadOrAggregateValue(tupleElement);
- if (!tupleElement.mType->IsValuelessType())
- mBfIRBuilder->CreateStore(tupleElement.mValue, argValue.mValue);
- }
- if ((clearOutOnMismatch) && (!deferredAssigns.IsEmpty()))
- {
- auto curInsertPoint = mBfIRBuilder->GetInsertBlock();
- mBfIRBuilder->SetInsertPoint(falseBlockEnd);
- for (auto& deferredAssign : deferredAssigns)
- {
- if (!deferredAssign.mIsOut)
- continue;
- auto tupleFieldInstance = &tupleType->mFieldInstances[deferredAssign.mFieldIdx];
- // We have to re-process the expr because we haven't done it in this branch, and then clear the result out
- SetAndRestoreValue<bool> prevIgnoreErrors(mIgnoreErrors, mHadBuildError); // Don't fail twice
- BfExprEvaluator exprEvaluator(this);
- exprEvaluator.mExpectingType = tupleFieldInstance->GetResolvedType();
- exprEvaluator.mBfEvalExprFlags = BfEvalExprFlags_AllowOutExpr;
- exprEvaluator.Evaluate(deferredAssign.mExpr);
- auto argValue = exprEvaluator.mResult;
- if (!argValue)
- continue;
- mBfIRBuilder->CreateMemSet(argValue.mValue, GetConstValue8(0), GetConstValue(argValue.mType->mSize), GetConstValue(argValue.mType->mAlign));
- }
- falseBlockEnd = mBfIRBuilder->GetInsertBlock();
- mBfIRBuilder->SetInsertPoint(curInsertPoint);
- }
- if (arguments.size() > tupleType->mFieldInstances.size())
- {
- for (int i = (int)tupleType->mFieldInstances.size(); i < (int)arguments.size(); i++)
- {
- // For autocomplete and such
- auto expr = arguments[i];
- if (expr != NULL)
- CreateValueFromExpression(expr);
- }
- BfAstNode* errorRef = arguments[(int)tupleType->mFieldInstances.size()];
- BfError* error = Fail(StrFormat("Too many arguments, expected %d fewer.", arguments.size() - tupleType->mFieldInstances.size()), errorRef);
- }
- }
- BfTypedValue BfModule::TryCaseTupleMatch(BfTypedValue tupleVal, BfTupleExpression* tupleExpr, BfIRBlock* eqBlock, BfIRBlock* notEqBlock, BfIRBlock* matchBlock, bool& hadConditional, bool clearOutOnMismatch, bool prevHadFallthrough)
- {
- if (!tupleVal.mType->IsTuple())
- return BfTypedValue();
- auto tupleType = (BfTypeInstance*)tupleVal.mType;
- BfAstNode* tooFewRef = tupleExpr->mCloseParen;
- if ((tooFewRef == NULL) && (!tupleExpr->mCommas.IsEmpty()))
- tooFewRef = tupleExpr->mCommas[tupleExpr->mCommas.size() - 1];
- else if (tooFewRef == NULL)
- tooFewRef = tupleExpr->mOpenParen;
- ///
- auto autoComplete = mCompiler->GetAutoComplete();
- bool wasCapturingMethodInfo = false;
- if (autoComplete != NULL)
- {
- wasCapturingMethodInfo = autoComplete->mIsCapturingMethodMatchInfo;
- autoComplete->CheckInvocation(tupleExpr, tupleExpr->mOpenParen, tupleExpr->mCloseParen, tupleExpr->mCommas);
- if (autoComplete->mIsCapturingMethodMatchInfo)
- {
- autoComplete->mMethodMatchInfo->mInstanceList.Clear();
- auto methodMatchInfo = autoComplete->mMethodMatchInfo;
- // auto methodDef = tupleType->mTypeDef->mMethods[0];
- //
- // BfAutoComplete::MethodMatchEntry methodMatchEntry;
- // methodMatchEntry.mMethodDef = methodDef;
- // methodMatchEntry.mTypeInstance = tupleType;
- // methodMatchEntry.mCurMethodInstance = mCurMethodInstance;
- // //methodMatchEntry.mPayloadEnumField = fieldInstance;
- //autoComplete->mMethodMatchInfo->mInstanceList.push_back(methodMatchEntry);
- methodMatchInfo->mBestIdx = 0;
- methodMatchInfo->mMostParamsMatched = 0;
- int cursorIdx = tupleExpr->GetParser()->mCursorIdx;
- if ((tupleExpr->mCloseParen == NULL) || (cursorIdx <= tupleExpr->mCloseParen->GetSrcStart()))
- {
- int paramIdx = 0;
- for (int commaIdx = 0; commaIdx < (int)tupleExpr->mCommas.size(); commaIdx++)
- {
- auto commaNode = tupleExpr->mCommas[commaIdx];
- if ((commaNode != NULL) && (cursorIdx >= commaNode->GetSrcStart()))
- paramIdx = commaIdx + 1;
- }
- bool isEmpty = true;
- if (paramIdx < (int)tupleExpr->mValues.size())
- {
- auto paramNode = tupleExpr->mValues[paramIdx];
- if (paramNode != NULL)
- isEmpty = false;
- }
- if (isEmpty)
- {
- if (paramIdx < (int)tupleType->mFieldInstances.size())
- {
- auto fieldDef = tupleType->mFieldInstances[paramIdx].GetFieldDef();
- String insertStr;
- if (fieldDef->IsUnnamedTupleField())
- insertStr = "p";
- insertStr += fieldDef->mName;
- insertStr.Insert(0, "let ");
- autoComplete->mEntriesSet.Clear();
- autoComplete->AddEntry(AutoCompleteEntry("paramName", insertStr));
- autoComplete->mInsertStartIdx = cursorIdx;
- autoComplete->mInsertEndIdx = cursorIdx;
- }
- }
- }
- }
- }
- defer
- (
- if (autoComplete != NULL)
- autoComplete->mIsCapturingMethodMatchInfo = (wasCapturingMethodInfo) && (!autoComplete->mIsCapturingMethodMatchInfo);
- );
- ///
- //BfIRValue phiVal;
- auto boolType = GetPrimitiveType(BfTypeCode_Boolean);
- //phiVal = mBfIRBuilder->CreatePhi(mBfIRBuilder->MapType(boolType), 2);
- auto startBlock = mBfIRBuilder->GetInsertBlock();
- //auto dscrType = enumType->GetDiscriminatorType();
- //BfIRValue eqResult = mBfIRBuilder->CreateCmpEQ(tagVal.mValue, mBfIRBuilder->CreateConst(dscrType->mTypeDef->mTypeCode, tagId));
- BfIRBlock falseBlockStart;
- BfIRBlock falseBlockEnd;
- BfIRBlock doneBlockStart;
- if (notEqBlock != NULL)
- doneBlockStart = *notEqBlock;
- else
- doneBlockStart = mBfIRBuilder->CreateBlock("caseDone", false);
- BfIRBlock doneBlockEnd = doneBlockStart;
- if (clearOutOnMismatch)
- {
- falseBlockStart = falseBlockEnd = mBfIRBuilder->CreateBlock("caseNotEq", false);
- mBfIRBuilder->AddBlock(falseBlockStart);
- }
- BfIRBlock matchedBlockStart = mBfIRBuilder->CreateBlock("caseMatch", false);
- if (matchBlock != NULL)
- *matchBlock = matchedBlockStart;
- mBfIRBuilder->CreateBr(matchedBlockStart);
- mBfIRBuilder->AddBlock(matchedBlockStart);
- mBfIRBuilder->SetInsertPoint(doneBlockEnd);
- BfIRValue phiVal;
- if (eqBlock == NULL)
- phiVal = mBfIRBuilder->CreatePhi(mBfIRBuilder->MapType(boolType), 2);
- mBfIRBuilder->SetInsertPoint(matchedBlockStart);
- BfIRBlock matchedBlockEnd = matchedBlockStart;
- HandleCaseEnumMatch_Tuple(tupleVal, tupleExpr->mValues, tooFewRef, falseBlockStart ? BfIRValue() : phiVal, matchedBlockStart, matchedBlockEnd,
- falseBlockStart ? falseBlockStart : doneBlockStart, falseBlockEnd ? falseBlockEnd : doneBlockEnd, hadConditional, clearOutOnMismatch, prevHadFallthrough);
- if (phiVal)
- {
- auto falseVal = mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0);
- if (falseBlockEnd)
- mBfIRBuilder->AddPhiIncoming(phiVal, falseVal, falseBlockEnd);
- auto trueVal = mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 1);
- mBfIRBuilder->AddPhiIncoming(phiVal, trueVal, matchedBlockEnd);
- }
- if (eqBlock != NULL)
- mBfIRBuilder->CreateBr(*eqBlock);
- else
- mBfIRBuilder->CreateBr(doneBlockStart);
- if (falseBlockEnd)
- {
- mBfIRBuilder->SetInsertPoint(falseBlockEnd);
- mBfIRBuilder->CreateBr(doneBlockStart);
- //mBfIRBuilder->AddPhiIncoming(phiVal, mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0), falseBlock);
- }
- mBfIRBuilder->AddBlock(doneBlockStart);
- mBfIRBuilder->SetInsertPoint(doneBlockEnd);
- if (phiVal)
- return BfTypedValue(phiVal, boolType);
- else
- return GetDefaultTypedValue(boolType);
- }
- BfTypedValue BfModule::TryCaseEnumMatch(BfTypedValue enumVal, BfTypedValue tagVal, BfExpression* expr, BfIRBlock* eqBlock, BfIRBlock* notEqBlock, BfIRBlock* matchBlock, int& tagId, bool& hadConditional, bool clearOutOnMismatch, bool prevHadFallthrough)
- {
- auto invocationExpr = BfNodeDynCast<BfInvocationExpression>(expr);
- if (invocationExpr == NULL)
- return BfTypedValue();
- auto activeTypeDef = GetActiveTypeDef();
- BfType* targetType = NULL;
- BfIdentifierNode* nameNode = NULL;
- BfTokenNode* dotNode = NULL;
- if (auto memberRefExpr = BfNodeDynCast<BfMemberReferenceExpression>(invocationExpr->mTarget))
- {
- if (memberRefExpr->mTarget == NULL)
- {
- targetType = enumVal.mType;
- }
- else if (auto typeRef = BfNodeDynCast<BfTypeReference>(memberRefExpr->mTarget))
- {
- SetAndRestoreValue<bool> prevIgnoreErrors(mIgnoreErrors, true);
- targetType = ResolveTypeRef(typeRef);
- }
- else if (auto identifier = BfNodeDynCast<BfIdentifierNode>(memberRefExpr->mTarget))
- {
- SetAndRestoreValue<bool> prevIgnoreErrors(mIgnoreErrors, true);
- targetType = ResolveTypeRef(identifier, NULL);
- }
- if (auto nameIdentifier = BfNodeDynCast<BfIdentifierNode>(memberRefExpr->mMemberName))
- {
- dotNode = memberRefExpr->mDotToken;
- nameNode = nameIdentifier;
- }
- else
- return BfTypedValue();
- }
- else if (auto qualifiedNameNode = BfNodeDynCast<BfQualifiedNameNode>(invocationExpr->mTarget))
- {
- SetAndRestoreValue<bool> prevIgnoreErrors(mIgnoreErrors, true);
- targetType = ResolveTypeRef(qualifiedNameNode->mLeft, NULL);
- nameNode = qualifiedNameNode->mRight;
- }
- else if (auto identiferNode = BfNodeDynCast<BfIdentifierNode>(invocationExpr->mTarget))
- {
- targetType = mCurTypeInstance;
- nameNode = identiferNode;
- }
- else
- return BfTypedValue();
- // These may have been colorized as methods, so change that
- SetElementType(nameNode, BfSourceElementType_Normal);
- if ((targetType == NULL) || (!targetType->IsPayloadEnum()))
- return BfTypedValue();
- auto enumType = targetType->ToTypeInstance();
- PopulateType(enumType);
- StringT<128> enumCaseName;
- if (nameNode != NULL)
- nameNode->ToString(enumCaseName);
- auto tagType = GetPrimitiveType(BfTypeCode_Int32);
- if (enumVal.mType != enumType)
- {
- Fail(StrFormat("Cannot match enum type '%s' with type '%s'",
- TypeToString(enumVal.mType).c_str(), TypeToString(enumType).c_str()));
- enumVal = GetDefaultTypedValue(enumType);
- tagVal = GetDefaultTypedValue(tagType);
- }
- BfIRValue eqResult;
- for (int fieldIdx = 0; fieldIdx < (int)enumType->mFieldInstances.size(); fieldIdx++)
- {
- auto fieldInstance = &enumType->mFieldInstances[fieldIdx];
- auto fieldDef = fieldInstance->GetFieldDef();
- if (fieldDef == NULL)
- continue;
- if ((fieldInstance->mIsEnumPayloadCase) && (fieldDef->mName == enumCaseName))
- {
- if (!IsInSpecializedSection())
- {
- if ((!enumType->IsTypeMemberIncluded(fieldDef->mDeclaringType, activeTypeDef, this)) ||
- (!enumType->IsTypeMemberAccessible(fieldDef->mDeclaringType, activeTypeDef)))
- continue;
- }
- auto resolvePassData = mCompiler->mResolvePassData;
- if (resolvePassData != NULL)
- {
- if (resolvePassData->mGetSymbolReferenceKind == BfGetSymbolReferenceKind_Field)
- resolvePassData->HandleFieldReference(nameNode, enumType->mTypeDef, fieldDef);
- String filter;
- auto autoComplete = resolvePassData->mAutoComplete;
- if ((autoComplete != NULL) && (autoComplete->InitAutocomplete(dotNode, nameNode, filter)))
- autoComplete->AddEnumTypeMembers(enumType, enumCaseName, false, enumType == mCurTypeInstance);
- }
- BF_ASSERT(fieldInstance->mResolvedType->IsTuple());
- auto tupleType = (BfTypeInstance*)fieldInstance->mResolvedType;
- PopulateType(tupleType);
- mBfIRBuilder->PopulateType(tupleType);
- if (tupleType->IsDeleting())
- {
- mCompiler->RequestExtraCompile();
- InternalError("TryCaseEnumMatch using deleted type", expr);
- return BfTypedValue();
- }
- auto boolType = GetPrimitiveType(BfTypeCode_Boolean);
- tagId = -fieldInstance->mDataIdx - 1;
- auto startBlock = mBfIRBuilder->GetInsertBlock();
- auto dscrType = enumType->GetDiscriminatorType();
- BfIRValue eqResult = mBfIRBuilder->CreateCmpEQ(tagVal.mValue, mBfIRBuilder->CreateConst(dscrType->mTypeDef->mTypeCode, tagId));
- bool isConstMatch = false;
- bool isConstIgnore = false;
- if (auto constant = mBfIRBuilder->GetConstant(eqResult))
- {
- isConstMatch = constant->mBool;
- isConstIgnore = !constant->mBool;
- }
- SetAndRestoreValue<bool> prevIgnoreWrite(mBfIRBuilder->mIgnoreWrites);
- if (isConstIgnore)
- mBfIRBuilder->mIgnoreWrites = true;
- BfIRBlock falseBlockStart;
- BfIRBlock falseBlockEnd;
- BfIRBlock doneBlockStart;
- BfIRBlock doneBlockEnd;
- if (notEqBlock != NULL)
- doneBlockStart = doneBlockEnd = *notEqBlock;
- else
- doneBlockStart = doneBlockEnd = mBfIRBuilder->CreateBlock("caseDone", false);
- if (clearOutOnMismatch)
- {
- falseBlockStart = falseBlockEnd = mBfIRBuilder->CreateBlock("caseNotEq", false);
- mBfIRBuilder->AddBlock(falseBlockStart);
- }
- BfIRBlock matchedBlockStart = mBfIRBuilder->CreateBlock("caseMatch", false);
- BfIRBlock matchedBlockEnd = matchedBlockStart;
- if (matchBlock != NULL)
- *matchBlock = matchedBlockStart;
- if (isConstMatch)
- mBfIRBuilder->CreateBr(matchedBlockStart);
- else
- mBfIRBuilder->CreateCondBr(eqResult, matchedBlockStart, falseBlockStart ? falseBlockStart : doneBlockStart);
- mBfIRBuilder->AddBlock(matchedBlockStart);
- mBfIRBuilder->SetInsertPoint(doneBlockEnd);
- BfIRValue phiVal;
- if ((eqBlock == NULL) && (!isConstIgnore) && (!isConstMatch))
- phiVal = mBfIRBuilder->CreatePhi(mBfIRBuilder->MapType(boolType), 1 + (int)tupleType->mFieldInstances.size());
- mBfIRBuilder->SetInsertPoint(matchedBlockEnd);
- BfTypedValue tupleVal;
- if (!enumVal.IsAddr())
- {
- auto unionInnerType = enumType->GetUnionInnerType();
- if (unionInnerType == tupleType)
- {
- tupleVal = ExtractValue(enumVal, NULL, 1);
- }
- }
- if (!tupleVal)
- {
- if (!tupleType->IsValuelessType())
- {
- tupleVal = ExtractValue(enumVal, NULL, 1);
- tupleVal = Cast(NULL, tupleVal, tupleType, BfCastFlags_Force);
- }
- else
- tupleVal = GetDefaultTypedValue(tupleType);
- }
- ////
- BfAstNode* tooFewRef = invocationExpr->mCloseParen;
- if ((tooFewRef == NULL) && (!invocationExpr->mCommas.IsEmpty()))
- tooFewRef = invocationExpr->mCommas[invocationExpr->mCommas.size() - 1];
- else if (tooFewRef == NULL)
- tooFewRef = invocationExpr->mOpenParen;
- ///
- auto autoComplete = mCompiler->GetAutoComplete();
- bool wasCapturingMethodInfo = false;
- if (autoComplete != NULL)
- {
- wasCapturingMethodInfo = autoComplete->mIsCapturingMethodMatchInfo;
- autoComplete->CheckInvocation(invocationExpr, invocationExpr->mOpenParen, invocationExpr->mCloseParen, invocationExpr->mCommas);
- if (autoComplete->mIsCapturingMethodMatchInfo)
- {
- autoComplete->mMethodMatchInfo->mInstanceList.Clear();
- auto methodMatchInfo = autoComplete->mMethodMatchInfo;
- BfAutoComplete::MethodMatchEntry methodMatchEntry;
- methodMatchEntry.mTypeInstance = enumType;
- methodMatchEntry.mCurMethodInstance = mCurMethodInstance;
- methodMatchEntry.mPayloadEnumField = fieldInstance;
- autoComplete->mMethodMatchInfo->mInstanceList.push_back(methodMatchEntry);
- methodMatchInfo->mBestIdx = 0;
- methodMatchInfo->mMostParamsMatched = 0;
- int cursorIdx = invocationExpr->GetParser()->mCursorIdx;
- if ((invocationExpr->mCloseParen == NULL) || (cursorIdx <= invocationExpr->mCloseParen->GetSrcStart()))
- {
- int paramIdx = 0;
- for (int commaIdx = 0; commaIdx < (int)invocationExpr->mCommas.size(); commaIdx++)
- {
- auto commaNode = invocationExpr->mCommas[commaIdx];
- if ((commaNode != NULL) && (cursorIdx >= commaNode->GetSrcStart()))
- paramIdx = commaIdx + 1;
- }
- bool isEmpty = true;
- if (paramIdx < (int)invocationExpr->mArguments.size())
- {
- auto paramNode = invocationExpr->mArguments[paramIdx];
- if (paramNode != NULL)
- isEmpty = false;
- }
- if (isEmpty)
- {
- if (paramIdx < (int)tupleType->mFieldInstances.size())
- {
- auto fieldDef = tupleType->mFieldInstances[paramIdx].GetFieldDef();
- String insertStr;
- if (fieldDef->IsUnnamedTupleField())
- insertStr = "p";
- insertStr += fieldDef->mName;
- insertStr.Insert(0, "let ");
- autoComplete->mEntriesSet.Clear();
- autoComplete->AddEntry(AutoCompleteEntry("paramName", insertStr));
- autoComplete->mInsertStartIdx = cursorIdx;
- autoComplete->mInsertEndIdx = cursorIdx;
- }
- }
- }
- }
- }
- defer
- (
- if (autoComplete != NULL)
- autoComplete->mIsCapturingMethodMatchInfo = (wasCapturingMethodInfo) && (!autoComplete->mIsCapturingMethodMatchInfo);
- );
- ///
- HandleCaseEnumMatch_Tuple(tupleVal, invocationExpr->mArguments, tooFewRef, falseBlockStart ? BfIRValue() : phiVal, matchedBlockStart, matchedBlockEnd,
- falseBlockStart ? falseBlockStart : doneBlockStart, falseBlockEnd ? falseBlockEnd : doneBlockEnd,
- hadConditional, clearOutOnMismatch, prevHadFallthrough);
- ///////
- if (phiVal)
- {
- auto falseVal = mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0);
- if (falseBlockEnd)
- mBfIRBuilder->AddPhiIncoming(phiVal, falseVal, falseBlockEnd);
- else
- mBfIRBuilder->AddPhiIncoming(phiVal, falseVal, startBlock);
- auto trueVal = mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 1);
- mBfIRBuilder->AddPhiIncoming(phiVal, trueVal, matchedBlockEnd);
- }
- if (eqBlock != NULL)
- mBfIRBuilder->CreateBr(*eqBlock);
- else
- mBfIRBuilder->CreateBr(doneBlockStart);
- if (falseBlockEnd)
- {
- mBfIRBuilder->SetInsertPoint(falseBlockEnd);
- mBfIRBuilder->CreateBr(doneBlockStart);
- //mBfIRBuilder->AddPhiIncoming(phiVal, mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0), falseBlock);
- }
- mBfIRBuilder->AddBlock(doneBlockStart);
- mBfIRBuilder->SetInsertPoint(doneBlockEnd);
- if (phiVal)
- return BfTypedValue(phiVal, boolType);
- else if (eqResult)
- return BfTypedValue(eqResult, boolType);
- else
- return GetDefaultTypedValue(boolType);
- }
- }
- return BfTypedValue();
- }
- BfTypedValue BfModule::HandleCaseBind(BfTypedValue enumVal, const BfTypedValue& tagVal, BfEnumCaseBindExpression* bindExpr, BfIRBlock* eqBlock, BfIRBlock* notEqBlock, BfIRBlock* matchBlock, int* outEnumIdx)
- {
- BfTypeInstance* tupleType = NULL;
- auto activeTypeDef = GetActiveTypeDef();
- auto boolType = GetPrimitiveType(BfTypeCode_Boolean);
- BfIRValue eqResult;
- if (bindExpr->mEnumMemberExpr != NULL)
- {
- int enumIdx = -1;
- String findName;
- BfType* type = NULL;
- BfAstNode* targetNode = NULL;
- BfAstNode* nameNode = NULL;
- BfAstNode* dotNode = NULL;
- if (auto memberExpr = BfNodeDynCast<BfMemberReferenceExpression>(bindExpr->mEnumMemberExpr))
- {
- dotNode = memberExpr->mDotToken;
- if (memberExpr->mMemberName != NULL)
- {
- nameNode = memberExpr->mMemberName;
- findName = memberExpr->mMemberName->ToString();
- if (memberExpr->mTarget == NULL)
- {
- type = enumVal.mType;
- }
- else if (auto typeRef = BfNodeDynCast<BfTypeReference>(memberExpr->mTarget))
- {
- type = ResolveTypeRef(typeRef);
- }
- }
- targetNode = memberExpr->mTarget;
- }
- else if (auto identiferNode = BfNodeDynCast<BfIdentifierNode>(bindExpr->mEnumMemberExpr))
- {
- if (mCurTypeInstance->IsPayloadEnum())
- {
- nameNode = identiferNode;
- findName = nameNode->ToString();
- targetNode = identiferNode;
- type = mCurTypeInstance;
- }
- else
- {
- Fail("Expected a qualified enum case name. Consider prefixing name with a dot to infer enum type name.", bindExpr->mEnumMemberExpr);
- }
- }
- if (!findName.empty())
- {
- if (type != NULL)
- {
- if (type != enumVal.mType)
- {
- Fail(StrFormat("Enum case type '%s' does not match compared value of type '%s'",
- TypeToString(enumVal.mType).c_str(), TypeToString(type).c_str()), targetNode);
- }
- if (type->IsEnum())
- {
- auto enumType = (BfTypeInstance*)type;
- for (auto& fieldInstance : enumType->mFieldInstances)
- {
- auto fieldDef = fieldInstance.GetFieldDef();
- if ((fieldDef != NULL) && (fieldDef->IsEnumCaseEntry()) && (fieldDef->mName == findName))
- {
- if ((!enumType->IsTypeMemberIncluded(fieldDef->mDeclaringType, activeTypeDef, this)) ||
- (!enumType->IsTypeMemberAccessible(fieldDef->mDeclaringType, activeTypeDef)))
- continue;
- auto resolvePassData = mCompiler->mResolvePassData;
- if (resolvePassData != NULL)
- {
- if (resolvePassData->mGetSymbolReferenceKind == BfGetSymbolReferenceKind_Field)
- resolvePassData->HandleFieldReference(nameNode, enumType->mTypeDef, fieldDef);
- String filter;
- auto autoComplete = resolvePassData->mAutoComplete;
- if ((autoComplete != NULL) && (autoComplete->InitAutocomplete(dotNode, nameNode, filter)))
- autoComplete->AddEnumTypeMembers(enumType, findName, false, enumType == mCurTypeInstance);
- }
- enumIdx = -fieldInstance.mDataIdx - 1;
- if (outEnumIdx != NULL)
- *outEnumIdx = enumIdx;
- if (fieldInstance.mIsEnumPayloadCase)
- tupleType = fieldInstance.mResolvedType->ToTypeInstance();
- }
- }
- if (enumIdx == -1)
- {
- Fail("Enum case not found", nameNode);
- }
- }
- else
- {
- Fail(StrFormat("Type '%s' is not an enum type", TypeToString(type).c_str()), targetNode);
- }
- }
- }
- BF_ASSERT(tagVal.mType->IsPrimitiveType());
- eqResult = mBfIRBuilder->CreateCmpEQ(tagVal.mValue, mBfIRBuilder->CreateConst(((BfPrimitiveType*)tagVal.mType)->mTypeDef->mTypeCode, enumIdx));
- }
- else
- {
- eqResult = mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0);
- }
- BfIRBlock falseBlock;
- if (notEqBlock != NULL)
- {
- falseBlock = *notEqBlock;
- }
- else
- {
- falseBlock = mBfIRBuilder->CreateBlock("notEqBlock", false);
- }
- auto mainBlock = mBfIRBuilder->GetInsertBlock();
- BfIRBlock trueBlock = mBfIRBuilder->CreateBlock("eqBlock", false);
- if (matchBlock != NULL)
- *matchBlock = trueBlock;
- mBfIRBuilder->AddBlock(trueBlock);
- mBfIRBuilder->SetInsertPoint(trueBlock);
- if ((tupleType != NULL) && (bindExpr->mBindNames != NULL))
- {
- BfIRValue valueScopeStart;
- if (IsTargetingBeefBackend())
- valueScopeStart = mBfIRBuilder->CreateValueScopeStart();
- bool isVar = bindExpr->mBindToken->GetToken() == BfToken_Var;
- bool isLet = bindExpr->mBindToken->GetToken() == BfToken_Let;
- BfTypedValue tupleVal;
- if (enumVal.IsAddr())
- {
- auto ptrVal = mBfIRBuilder->CreateInBoundsGEP(enumVal.mValue, 0, 1);
- tupleVal = BfTypedValue(mBfIRBuilder->CreateBitCast(ptrVal, mBfIRBuilder->MapTypeInstPtr(tupleType)), tupleType, true);
- }
- else
- {
- auto unionInnerType = enumVal.mType->ToTypeInstance()->GetUnionInnerType();
- tupleVal = ExtractValue(enumVal, NULL, 1);
- if (unionInnerType != tupleType)
- {
- tupleVal = MakeAddressable(tupleVal);
- tupleVal = BfTypedValue(mBfIRBuilder->CreateBitCast(tupleVal.mValue, mBfIRBuilder->MapTypeInstPtr(tupleType)), tupleType, true);
- }
- }
- HandleTupleVariableDeclaration(NULL, bindExpr->mBindNames, tupleVal, isLet, false, true /*, &mainBlock*/);
- auto autoComplete = mCompiler->GetAutoComplete();
- if ((autoComplete != NULL) && ((isVar || isLet)))
- autoComplete->CheckVarResolution(bindExpr->mBindToken, tupleType);
- if (valueScopeStart)
- mBfIRBuilder->CreateValueScopeSoftEnd(valueScopeStart);
- }
- if (eqBlock != NULL)
- mBfIRBuilder->CreateBr(*eqBlock);
- else
- mBfIRBuilder->CreateBr(falseBlock);
- // Don't create the condBr until now, so HandleTupleVariableDeclaration can create the variable declarations in mainBlock--
- // we need them there since the code that uses the new variables is created outside the eqBlock
- mBfIRBuilder->SetInsertPoint(mainBlock);
- mBfIRBuilder->CreateCondBr(eqResult, trueBlock, falseBlock);
- mBfIRBuilder->AddBlock(falseBlock);
- mBfIRBuilder->SetInsertPoint(falseBlock);
- return BfTypedValue(eqResult, boolType);
- }
- void BfModule::AddBasicBlock(BfIRBlock bb, bool activate)
- {
- mBfIRBuilder->AddBlock(bb);
- if (activate)
- mBfIRBuilder->SetInsertPoint(bb);
- }
- void BfModule::VisitEmbeddedStatement(BfAstNode* stmt, BfExprEvaluator* exprEvaluator, BfEmbeddedStatementFlags flags)
- {
- if ((flags & BfEmbeddedStatementFlags_CheckStack) != 0)
- {
- BP_ZONE("BfModule.VisitEmbeddedStatement");
- StackHelper stackHelper;
- if (!stackHelper.CanStackExpand(64 * 1024))
- {
- if (!stackHelper.Execute([&]()
- {
- VisitEmbeddedStatement(stmt, exprEvaluator, flags);
- }))
- {
- Fail("Statement too complex to parse", stmt);
- }
- return;
- }
- }
- auto block = BfNodeDynCast<BfBlock>(stmt);
- BfLabelNode* labelNode = NULL;
- if (block == NULL)
- {
- auto labeledBlock = BfNodeDynCast<BfLabeledBlock>(stmt);
- if (labeledBlock != NULL)
- {
- block = labeledBlock->mBlock;
- labelNode = labeledBlock->mLabelNode;
- }
- }
- BfAstNode* openBrace = NULL;
- BfAstNode* closeBrace = NULL;
- if (block != NULL)
- {
- openBrace = block->mOpenBrace;
- closeBrace = block->mCloseBrace;
- if (openBrace == NULL)
- {
- auto checkScope = mCurMethodState->mCurScope;
- while ((checkScope != NULL) && (closeBrace == NULL))
- {
- closeBrace = checkScope->mCloseNode;
- checkScope = checkScope->mPrevScope;
- }
- BF_ASSERT(closeBrace != NULL);
- }
- }
- if ((block != NULL) && (openBrace != NULL))
- UpdateSrcPos(openBrace);
- if ((flags & BfEmbeddedStatementFlags_Unscoped) != 0)
- {
- SetAndRestoreValue<BfExprEvaluator*> prevExprEvaluator(mCurMethodState->mCurScope->mExprEvaluator, exprEvaluator);
- SetAndRestoreValue<bool> prevAllowReturn(mCurMethodState->mDisableReturns, true);
- VisitCodeBlock(block);
- }
- else if (mCurMethodState != NULL)
- {
- bool isIgnore = mBfIRBuilder->mIgnoreWrites;
- mCurMethodState->mInHeadScope = false;
- BfScopeData scopeData;
- if (IsTargetingBeefBackend())
- scopeData.mValueScopeStart = mBfIRBuilder->CreateValueScopeStart();
- mCurMethodState->AddScope(&scopeData);
- if (block != NULL)
- {
- mCurMethodState->mCurScope->mAstBlock = block;
- mCurMethodState->mCurScope->mCloseNode = closeBrace;
- }
- if (labelNode != NULL)
- scopeData.mLabelNode = labelNode->mLabel;
- NewScopeState(block != NULL);
- mCurMethodState->mCurScope->mOuterIsConditional = (flags & BfEmbeddedStatementFlags_IsConditional) != 0;
- mCurMethodState->mCurScope->mIsDeferredBlock = (flags & BfEmbeddedStatementFlags_IsDeferredBlock) != 0;
- mCurMethodState->mCurScope->mExprEvaluator = exprEvaluator;
- //
- {
- SetAndRestoreValue<bool> inDeferredBlock(mCurMethodState->mInDeferredBlock, mCurMethodState->mInDeferredBlock || mCurMethodState->mCurScope->mIsDeferredBlock);
- if (block != NULL)
- {
- if (labelNode != NULL)
- VisitCodeBlock(block, BfIRBlock(), BfIRBlock(), BfIRBlock(), false, NULL, labelNode);
- else
- VisitCodeBlock(block);
- }
- else
- {
- if (auto varDecl = BfNodeDynCast<BfVariableDeclaration>(stmt))
- {
- Fail("Variable declarations must be wrapped in a block statement", varDecl);
- }
- VisitChild(stmt);
- }
- }
- if ((block != NULL) && (closeBrace != NULL))
- {
- UpdateSrcPos(closeBrace);
- if (!mCurMethodState->mLeftBlockUncond)
- EmitEnsureInstructionAt();
- }
- if (block != NULL)
- {
- BfAutoParentNodeEntry autoParentNodeEntry(this, block);
- RestoreScopeState();
- }
- else
- RestoreScopeState();
- BF_ASSERT(isIgnore == mBfIRBuilder->mIgnoreWrites);
- }
- else
- {
- if (block != NULL)
- VisitCodeBlock(block);
- else
- VisitChild(stmt);
- }
- }
- void BfModule::VisitCodeBlock(BfBlock* block, BfIRBlock continueBlock, BfIRBlock breakBlock, BfIRBlock fallthroughBlock, bool defaultBreak, bool* hadReturn, BfLabelNode* labelNode, bool closeScope, BfEmbeddedStatementFlags flags)
- {
- BfBreakData breakData;
- breakData.mIRContinueBlock = continueBlock;
- breakData.mIRBreakBlock = breakBlock;
- breakData.mIRFallthroughBlock = fallthroughBlock;
- breakData.mScope = mCurMethodState->mCurScope;
- breakData.mPrevBreakData = mCurMethodState->mBreakData;
- SetAndRestoreValue<BfBreakData*> prevBreakData(mCurMethodState->mBreakData, &breakData);
- VisitEmbeddedStatement(block, NULL, flags);
- if (closeScope)
- RestoreScopeState();
- if ((!mCurMethodState->mLeftBlockUncond) && (defaultBreak))
- {
- mBfIRBuilder->CreateBr(breakBlock);
- }
- if (hadReturn != NULL)
- {
- *hadReturn = mCurMethodState->mHadReturn;
- mCurMethodState->SetHadReturn(false);
- mCurMethodState->mLeftBlockUncond = false;
- }
- }
- void BfModule::VisitCodeBlock(BfBlock* block)
- {
- //BP_ZONE("BfModule::VisitCodeBlock");
- BfAutoParentNodeEntry autoParentNodeEntry(this, block);
- BfIRBlock prevInsertBlock;
- bool hadReturn = false;
- int startLocalMethod = 0; // was -1
- auto rootMethodState = mCurMethodState->GetRootMethodState();
- BfIRBlock startInsertBlock = mBfIRBuilder->GetInsertBlock();
- bool allowLocalMethods = mCurMethodInstance != NULL;
- //int startDeferredLocalIdx = (int)rootMethodState->mDeferredLocalMethods.size();
- int curLocalMethodIdx = -1;
- // Scan for any local method declarations
- if (allowLocalMethods)
- {
- startLocalMethod = (int)mCurMethodState->mLocalMethods.size();
- curLocalMethodIdx = startLocalMethod;
- auto itr = block->begin();
- while (itr != block->end())
- {
- BfAstNode* child = *itr;
- if (auto localMethodDecl = BfNodeDynCastExact<BfLocalMethodDeclaration>(child))
- {
- BfLocalMethod* localMethod;
- auto rootMethodState = mCurMethodState->GetRootMethodState();
- String methodName;
- if (localMethodDecl->mMethodDeclaration->mNameNode != NULL)
- {
- methodName = GetLocalMethodName(localMethodDecl->mMethodDeclaration->mNameNode->ToString(), localMethodDecl->mMethodDeclaration->mOpenParen, mCurMethodState, mCurMethodState->mMixinState);
- BfLocalMethod** localMethodPtr = NULL;
- if (rootMethodState->mLocalMethodCache.TryGetValue(methodName, &localMethodPtr))
- {
- localMethod = *localMethodPtr;
- }
- else
- {
- localMethod = new BfLocalMethod();
- localMethod->mSystem = mSystem;
- localMethod->mModule = this;
- localMethod->mMethodDeclaration = localMethodDecl->mMethodDeclaration;
- localMethod->mSource = mCurTypeInstance->mTypeDef->mSource;
- localMethod->mSource->mRefCount++;
- if (mCurMethodState->mClosureState != NULL)
- localMethod->mOuterLocalMethod = mCurMethodState->mClosureState->mLocalMethod;
- auto autoComplete = mCompiler->GetAutoComplete();
- if ((autoComplete != NULL) && (autoComplete->mResolveType == BfResolveType_Autocomplete))
- {
- auto autoComplete = mCompiler->mResolvePassData->mAutoComplete;
- if (!autoComplete->IsAutocompleteNode(localMethod->mMethodDeclaration))
- localMethod->mDeclOnly = true;
- }
- if (localMethod->mMethodDeclaration->mNameNode != NULL)
- localMethod->mMethodName = localMethod->mMethodDeclaration->mNameNode->ToString();
- localMethod->mExpectedFullName = methodName;
- rootMethodState->mLocalMethodCache[methodName] = localMethod;
- mContext->mLocalMethodGraveyard.push_back(localMethod);
- }
- BF_ASSERT(mCurMethodState->mCurScope != NULL);
- localMethod->mDeclDIScope = mCurMethodState->mCurScope->mDIScope;
- localMethod->mDeclMethodState = mCurMethodState;
- localMethod->mDeclMixinState = mCurMethodState->mMixinState;
- if (localMethod->mDeclMixinState != NULL)
- localMethod->mDeclMixinState->mHasDeferredUsage = true;
- mCurMethodState->mLocalMethods.push_back(localMethod);
- bool valid = true;
- String* namePtr;
- if (!mCurMethodState->mLocalMethodMap.TryAdd(localMethod->mMethodName, &namePtr, &localMethodPtr))
- {
- if (localMethod == *localMethodPtr)
- {
- valid = false;
- Fail("Duplicate local method name", localMethodDecl->mMethodDeclaration->mNameNode);
- }
- if (valid)
- localMethod->mNextWithSameName = *localMethodPtr;
- }
- if (valid)
- *localMethodPtr = localMethod;
- }
- }
- ++itr;
- }
- }
- bool wantsAllLocalMethods = true;
- auto autoComplete = mCompiler->GetAutoComplete();
- if (autoComplete != NULL)
- {
- // If we only need reasoning "at the cursor" then we don't need all local methods
- if ((!autoComplete->mIsAutoComplete) ||
- (autoComplete->mResolveType == BfResolveType_GetCurrentLocation) ||
- (autoComplete->mResolveType == BfResolveType_GetFixits) ||
- (autoComplete->mResolveType == BfResolveType_GetResultString) ||
- (autoComplete->mResolveType == BfResolveType_GetSymbolInfo) ||
- (autoComplete->mResolveType == BfResolveType_ShowFileSymbolReferences))
- wantsAllLocalMethods = false;
- }
- /*if ((mCompiler->mResolvePassData != NULL) && (mCompiler->mResolvePassData->mResolveType == BfResolveType_ShowFileSymbolReferences))
- {
- if (mCompiler->mResolvePassData->mSymbolReferenceLocalIdx != -1)
- {
- // We need to reproduce the behavior when we found the symbol - only process autocomplete nodes, otherwise local method ids will be wrong
- // when we have local methods that were skipped the first time but not the second
- wantsAllLocalMethods = false;
- }
- }*/
- SetAndRestoreValue<bool> prevIgnoreWrite(mBfIRBuilder->mIgnoreWrites);
- bool hadUnreachableCode = false;
- // Handle statements
- auto itr = block->begin();
- while (itr != block->end())
- {
- BfAstNode* child = *itr;
- if (auto localMethodDecl = BfNodeDynCastExact<BfLocalMethodDeclaration>(child))
- {
- /*if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mMethodDef->mMethodType == BfMethodType_Mixin))
- Fail("Mixins cannot contain local methods", child);*/
- if (!allowLocalMethods)
- {
- Fail("Invalid use of local methods", child);
- }
- else if (localMethodDecl->mMethodDeclaration->mNameNode != NULL)
- {
- BfLocalMethod* localMethod = mCurMethodState->mLocalMethods[curLocalMethodIdx];
- if (localMethod->mMethodDeclaration != localMethodDecl->mMethodDeclaration)
- {
- AssertErrorState();
- }
- else
- {
- bool wantsLocalMethod = (wantsAllLocalMethods) || (autoComplete->IsAutocompleteNode(localMethod->mMethodDeclaration));
- if ((!wantsLocalMethod) && (mCurMethodInstance->mMethodDef->mIsLocalMethod))
- wantsLocalMethod = true;
- if (wantsLocalMethod)
- {
- if (!mCurMethodInstance->IsSpecializedGenericMethodOrType())
- GetLocalMethodInstance(localMethod, BfTypeVector(), NULL, true); // Only necessary on unspecialized pass
- }
- if ((mCompiler->mResolvePassData != NULL) && (mCompiler->mResolvePassData->mAutoComplete != NULL))
- mCompiler->mResolvePassData->mAutoComplete->CheckMethod(localMethod->mMethodDeclaration, true);
- curLocalMethodIdx++;
- }
- }
- ++itr;
- continue;
- }
- if ((mCurMethodState != NULL) && (mCurMethodState->mLeftBlockUncond)) // mLeftBlock is cleared after conditional block is completed
- {
- if (mCurMethodState->mHadReturn)
- hadReturn = true;
- if ((!hadUnreachableCode) && (!mCurMethodState->mInPostReturn))
- {
- if ((mCurMethodState->mCurScope == NULL) || (!mCurMethodState->mCurScope->mSupressNextUnreachable))
- Warn(BfWarning_CS0162_UnreachableCode, "Unreachable code", child);
- hadUnreachableCode = true;
- prevInsertBlock = mBfIRBuilder->GetInsertBlock();
- mCurMethodState->mInPostReturn = true;
- mBfIRBuilder->mIgnoreWrites = true;
- }
- }
- if ((mCurMethodState != NULL) && (mCurMethodState->mCurScope != NULL))
- mCurMethodState->mCurScope->mSupressNextUnreachable = false;
- if (itr.IsLast())
- {
- if (auto expr = BfNodeDynCast<BfExpression>(child))
- {
- if (expr->IsExpression())
- {
- if (mCurMethodState != NULL)
- {
- if (mCurMethodState->mCurScope->mExprEvaluator != NULL)
- {
- if ((mAttributeState != NULL) &&
- ((mAttributeState->mFlags & (BfAttributeState::Flag_StopOnError | BfAttributeState::Flag_HadError)) == (BfAttributeState::Flag_StopOnError | BfAttributeState::Flag_HadError)))
- {
- // Resolve as just 'false'
- mCurMethodState->mCurScope->mExprEvaluator->mResult = GetDefaultTypedValue(GetPrimitiveType(BfTypeCode_Boolean));
- }
- else
- {
- auto exprEvaluator = mCurMethodState->mCurScope->mExprEvaluator;
- // Evaluate last child as an expression
- exprEvaluator->VisitChild(expr);
- exprEvaluator->FinishExpressionResult();
- if ((exprEvaluator->mResult) && (!exprEvaluator->mResult.mType->IsValuelessType()) && (!exprEvaluator->mResult.mValue.IsConst()) &&
- (!exprEvaluator->mResult.IsAddr()) && (exprEvaluator->mResult.mValue) && (!exprEvaluator->mResult.mValue.IsFake()))
- {
- if ((mCurMethodState->mCurScope != NULL) && (mCurMethodState->mCurScope->mPrevScope != NULL))
- {
- // We need to make sure we don't retain any values through the scope's ValueScopeHardEnd - and extend alloca through previous scope
- bool wasReadOnly = exprEvaluator->mResult.IsReadOnly();
- FixIntUnknown(exprEvaluator->mResult, exprEvaluator->mExpectingType);
- auto prevInsertBlock = mBfIRBuilder->GetInsertBlock();
- auto tempVar = CreateAlloca(exprEvaluator->mResult.mType, false, "blockExpr");
- mBfIRBuilder->SetInsertPointAtStart(startInsertBlock);
- auto lifetimeStart = mBfIRBuilder->CreateLifetimeStart(tempVar);
- mBfIRBuilder->ClearDebugLocation(lifetimeStart);
- if ((!mBfIRBuilder->mIgnoreWrites) && (IsTargetingBeefBackend()))
- mCurMethodState->mCurScope->mPrevScope->mDeferredLifetimeEnds.push_back(tempVar);
- mBfIRBuilder->SetInsertPoint(prevInsertBlock);
- if (exprEvaluator->mResult.IsSplat())
- AggregateSplatIntoAddr(exprEvaluator->mResult, tempVar);
- else if (!exprEvaluator->mResult.mType->IsValuelessType())
- mBfIRBuilder->CreateAlignedStore(exprEvaluator->mResult.mValue, tempVar, exprEvaluator->mResult.mType->mAlign);
- exprEvaluator->mResult = BfTypedValue(tempVar, exprEvaluator->mResult.mType,
- exprEvaluator->mResult.IsThis() ?
- (wasReadOnly ? BfTypedValueKind_ReadOnlyThisAddr : BfTypedValueKind_ThisAddr) :
- (wasReadOnly ? BfTypedValueKind_ReadOnlyAddr : BfTypedValueKind_Addr));
- }
- }
- if (exprEvaluator->mResult.IsAddr())
- {
- if (mCurMethodState->mCurScope->ExtendLifetime(exprEvaluator->mResult.mValue))
- mBfIRBuilder->CreateLifetimeSoftEnd(exprEvaluator->mResult.mValue);
- }
- }
- break;
- }
- else if (mCurMethodState->InMainMixinScope())
- {
- mCurMethodState->mMixinState->mResultExpr = expr;
- break;
- }
- else if ((mCurMethodInstance != NULL) && (mCurMethodInstance->IsMixin()) && (mCurMethodState->mCurScope == &mCurMethodState->mHeadScope))
- {
- // Only in mixin definition - result ignored
- CreateValueFromExpression(expr, NULL, BfEvalExprFlags_AllowRefExpr);
- break;
- }
- else
- {
- FailAfter("Expression block cannot be used here. Consider adding semicolon if a statement was intended.", expr);
- }
- }
- }
- }
- }
- UpdateSrcPos(child);
- BfAutoParentNodeEntry autoParentNode(this, child);
- if ((mAttributeState != NULL) &&
- ((mAttributeState->mFlags & (BfAttributeState::Flag_StopOnError | BfAttributeState::Flag_HadError)) == (BfAttributeState::Flag_StopOnError | BfAttributeState::Flag_HadError)))
- {
- // Ignore child
- }
- else
- child->Accept(this);
- mContext->CheckLockYield();
- ++itr;
- }
- if (mCurMethodState != NULL)
- {
- // Any local method that hasn't been called needs to be processed now
- for (int localMethodIdx = startLocalMethod; localMethodIdx < (int)mCurMethodState->mLocalMethods.size(); localMethodIdx++)
- {
- auto localMethod = mCurMethodState->mLocalMethods[localMethodIdx];
- if ((wantsAllLocalMethods) || (autoComplete->IsAutocompleteNode(localMethod->mMethodDeclaration)))
- {
- //??
- auto moduleMethodInstance = GetLocalMethodInstance(localMethod, BfTypeVector(), NULL, true);
- }
- mContext->CheckLockYield();
- }
- while ((int)mCurMethodState->mLocalMethods.size() > startLocalMethod)
- {
- auto localMethod = mCurMethodState->mLocalMethods.back();
- #if _DEBUG
- BfLocalMethod** localMethodPtr = NULL;
- mCurMethodState->mLocalMethodMap.TryGetValue(localMethod->mMethodName, &localMethodPtr);
- if ((localMethodPtr == NULL) || (*localMethodPtr != localMethod))
- AssertErrorState();
- #endif
- if (localMethod->mNextWithSameName == NULL)
- mCurMethodState->mLocalMethodMap.Remove(localMethod->mMethodName);
- else
- {
- mCurMethodState->mLocalMethodMap[localMethod->mMethodName] = localMethod->mNextWithSameName;
- localMethod->mNextWithSameName = NULL;
- }
- mCurMethodState->mLocalMethods.pop_back();
- }
- if (hadUnreachableCode)
- {
- if (hadReturn)
- mCurMethodState->SetHadReturn(true);
- mCurMethodState->mLeftBlockUncond = true;
- mCurMethodState->mInPostReturn = false;
- if (prevInsertBlock)
- mBfIRBuilder->SetInsertPoint(prevInsertBlock);
- }
- }
- }
- void BfModule::Visit(BfAstNode* astNode)
- {
- AssertErrorState();
- }
- void BfModule::Visit(BfIdentifierNode* identifierNode)
- {
- Visit((BfExpression*)identifierNode);
- }
- void BfModule::Visit(BfTypeReference* typeRef)
- {
- Visit((BfAstNode*)typeRef);
- if ((mCompiler->mResolvePassData != NULL) && (mCompiler->mResolvePassData->mAutoComplete != NULL))
- mCompiler->mResolvePassData->mAutoComplete->CheckTypeRef(typeRef, true);
- }
- void BfModule::Visit(BfEmptyStatement* astNode)
- {
- }
- void BfModule::Visit(BfTryStatement* tryStmt)
- {
- Fail("Exceptions not supported", tryStmt->mTryToken);
- VisitChild(tryStmt->mStatement);
- }
- void BfModule::Visit(BfCatchStatement* catchStmt)
- {
- Fail("Exceptions not supported", catchStmt->mCatchToken);
- }
- void BfModule::Visit(BfFinallyStatement* finallyStmt)
- {
- Fail("Exceptions not supported", finallyStmt->mFinallyToken);
- VisitChild(finallyStmt->mStatement);
- }
- void BfModule::Visit(BfCheckedStatement* checkedStmt)
- {
- Fail("'checked' not supported", checkedStmt->mCheckedToken);
- VisitChild(checkedStmt->mStatement);
- }
- void BfModule::Visit(BfUncheckedStatement* uncheckedStmt)
- {
- VisitChild(uncheckedStmt->mStatement);
- }
- void BfModule::DoIfStatement(BfIfStatement* ifStmt, bool includeTrueStmt, bool includeFalseStmt)
- {
- auto autoComplete = mCompiler->GetAutoComplete();
- if (autoComplete != NULL)
- autoComplete->CheckIdentifier(ifStmt->mIfToken, true);
- if (ifStmt->mCondition == NULL)
- {
- AssertErrorState();
- return;
- }
- //TODO: Only conditionally create the scopeData here if we create a variable inside the condition statement
- UpdateSrcPos(ifStmt);
- BfScopeData newScope;
- newScope.mOuterIsConditional = true;
- newScope.mScopeKind = BfScopeKind_StatementTarget;
- if (ifStmt->mLabelNode != NULL)
- newScope.mLabelNode = ifStmt->mLabelNode->mLabel;
- mCurMethodState->AddScope(&newScope);
- NewScopeState();
- BfBreakData breakData;
- breakData.mScope = &newScope;
- breakData.mPrevBreakData = mCurMethodState->mBreakData;
- SetAndRestoreValue<BfBreakData*> prevBreakData(mCurMethodState->mBreakData, &breakData);
- auto boolType = GetPrimitiveType(BfTypeCode_Boolean);
- BfDeferredLocalAssignData deferredLocalAssignData(mCurMethodState->mCurScope);
- deferredLocalAssignData.mIsIfCondition = true;
- deferredLocalAssignData.ExtendFrom(mCurMethodState->mDeferredLocalAssignData, true);
- deferredLocalAssignData.mVarIdBarrier = mCurMethodState->GetRootMethodState()->mCurLocalVarId;
- SetAndRestoreValue<BfDeferredLocalAssignData*> prevDLA(mCurMethodState->mDeferredLocalAssignData, &deferredLocalAssignData);
- BfAutoParentNodeEntry autoParentNodeEntry(this, ifStmt);
- BfTypedValue condValue = CreateValueFromExpression(ifStmt->mCondition, boolType);
- newScope.mScopeKind = BfScopeKind_Normal;
- deferredLocalAssignData.mIsIfCondition = false;
- // The "extend chain" is only valid for the conditional -- since that expression may contain unconditionally executed and
- // conditionally executed code (in the case of "(GetVal(out a) && GetVal(out b))" for example
- mCurMethodState->mDeferredLocalAssignData->BreakExtendChain();
- if (!condValue)
- {
- AssertErrorState();
- condValue = BfTypedValue(GetDefaultValue(boolType), boolType);
- }
- BfIRBlock trueBB;
- BfIRBlock falseBB;
- bool isConstBranch = false;
- bool constResult = false;
- if (condValue.mValue.IsConst())
- {
- auto constant = mBfIRBuilder->GetConstant(condValue.mValue);
- if ((constant != NULL) && (constant->mTypeCode == BfTypeCode_Boolean))
- {
- isConstBranch = true;
- constResult = constant->mBool;
- }
- }
- if (!isConstBranch)
- {
- trueBB = mBfIRBuilder->CreateBlock("if.then", true);
- falseBB = (ifStmt->mFalseStatement == NULL) ? BfIRBlock() : mBfIRBuilder->CreateBlock("if.else");
- }
- else
- EmitEnsureInstructionAt();
- auto contBB = mBfIRBuilder->CreateBlock("if.end");
- if (!isConstBranch)
- {
- mBfIRBuilder->CreateCondBr(condValue.mValue, trueBB, (falseBB) ? falseBB : contBB);
- }
- // TRUE statement
- bool ignoredLastBlock = true;
- if (includeTrueStmt)
- {
- SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites);
- SetAndRestoreValue<bool> prevInConstIgnore(mCurMethodState->mCurScope->mInConstIgnore);
- if (trueBB)
- mBfIRBuilder->SetInsertPoint(trueBB);
- if ((isConstBranch) && (constResult != true))
- {
- mBfIRBuilder->mIgnoreWrites = true;
- mCurMethodState->mCurScope->mInConstIgnore = true;
- }
- else
- ignoredLastBlock = false;
- VisitEmbeddedStatement(ifStmt->mTrueStatement);
- }
- prevDLA.Restore();
- if (mCurMethodState->mDeferredLocalAssignData != NULL)
- mCurMethodState->mDeferredLocalAssignData->mHadBreak |= deferredLocalAssignData.mHadBreak;
- bool trueHadReturn = mCurMethodState->mHadReturn;
- // We restore the scopeData before the False block because we don't want variables created in the if condition to
- // be visible in the false section
- //RestoreScopeState();
- RestoreScoreState_LocalVariables(mCurMethodState->mCurScope->mLocalVarStart);
- if ((!mCurMethodState->mLeftBlockUncond) && (!ignoredLastBlock))
- mBfIRBuilder->CreateBr_NoCollapse(contBB);
- if (mCurMethodState->mLeftBlockUncond)
- {
- deferredLocalAssignData.mLeftBlockUncond = true;
- mCurMethodState->mLeftBlockCond = true;
- }
- mCurMethodState->mLeftBlockUncond = false;
- mCurMethodState->SetHadReturn(false);
- bool falseHadReturn = false;
- if (ifStmt->mFalseStatement != NULL)
- {
- BfDeferredLocalAssignData falseDeferredLocalAssignData(&newScope);
- falseDeferredLocalAssignData.mVarIdBarrier = mCurMethodState->GetRootMethodState()->mCurLocalVarId;
- if (falseBB)
- {
- mBfIRBuilder->AddBlock(falseBB);
- mBfIRBuilder->SetInsertPoint(falseBB);
- }
- ignoredLastBlock = true;
- //
- {
- SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites);
- SetAndRestoreValue<bool> prevInConstIgnore(mCurMethodState->mCurScope->mInConstIgnore);
- if ((isConstBranch) && (constResult != false))
- {
- mBfIRBuilder->mIgnoreWrites = true;
- mCurMethodState->mCurScope->mInConstIgnore = true;
- }
- else
- ignoredLastBlock = false;
- falseDeferredLocalAssignData.ExtendFrom(mCurMethodState->mDeferredLocalAssignData);
- SetAndRestoreValue<BfDeferredLocalAssignData*> prevDLA(mCurMethodState->mDeferredLocalAssignData, &falseDeferredLocalAssignData);
- if (includeFalseStmt)
- VisitEmbeddedStatement(ifStmt->mFalseStatement, NULL, (BfEmbeddedStatementFlags)(BfEmbeddedStatementFlags_IsConditional | BfEmbeddedStatementFlags_CheckStack));
- }
- if ((!mCurMethodState->mLeftBlockUncond) && (!ignoredLastBlock))
- {
- if (IsTargetingBeefBackend())
- {
- // If we don't do this, then with:
- // if (a) { } else if (b) { }
- // Then we hit the closing second brace even if 'b' is false
- //SetIllegalSrcPos();
- //BfIRBuilder->ClearDebugLocation();
- }
- auto br = mBfIRBuilder->CreateBr_NoCollapse(contBB);
- //mBfIRBuilder->ClearDebugLocation(br);
- }
- falseHadReturn = mCurMethodState->mHadReturn;
- if (mCurMethodState->mLeftBlockUncond)
- {
- falseDeferredLocalAssignData.mLeftBlockUncond = true;
- mCurMethodState->mLeftBlockCond = true;
- }
- mCurMethodState->mLeftBlockUncond = false;
- mCurMethodState->SetHadReturn(false);
- deferredLocalAssignData.SetIntersection(falseDeferredLocalAssignData);
- mCurMethodState->ApplyDeferredLocalAssignData(deferredLocalAssignData);
- }
- else
- {
- // If we had a const-ignored if statement with no else
- if (ignoredLastBlock)
- {
- if (!mCurMethodState->mLeftBlockUncond)
- mBfIRBuilder->CreateBr_NoCollapse(contBB);
- }
- }
- mBfIRBuilder->AddBlock(contBB);
- mBfIRBuilder->SetInsertPoint(contBB);
- if (isConstBranch)
- mCurMethodState->SetHadReturn(constResult ? trueHadReturn : falseHadReturn);
- else
- mCurMethodState->SetHadReturn(trueHadReturn && falseHadReturn);
- mCurMethodState->mLeftBlockUncond = mCurMethodState->mHadReturn;
- if (mCurMethodState->mHadReturn)
- {
- mBfIRBuilder->EraseFromParent(contBB);
- }
- else
- {
- mBfIRBuilder->SetInsertPoint(contBB);
- }
- RestoreScopeState();
- }
- void BfModule::Visit(BfIfStatement* ifStmt)
- {
- DoIfStatement(ifStmt, true, true);
- }
- void BfModule::Visit(BfVariableDeclaration* varDecl)
- {
- //BP_ZONE("BfModule::Visit(BfVariableDeclaration)");
- UpdateSrcPos(varDecl);
- BfTupleExpression* tupleVariableDeclaration = BfNodeDynCast<BfTupleExpression>(varDecl->mNameNode);
- if (tupleVariableDeclaration != NULL)
- {
- HandleTupleVariableDeclaration(varDecl);
- }
- else
- HandleVariableDeclaration(varDecl);
- }
- void BfModule::Visit(BfLocalMethodDeclaration* methodDecl)
- {
- Fail("Local method declarations must be wrapped in a block statement", methodDecl->mMethodDeclaration->mNameNode);
- }
- void BfModule::Visit(BfAttributedStatement* attribStmt)
- {
- BfAttributeState attributeState;
- attributeState.mSrc = attribStmt->mAttributes;
- attributeState.mTarget = (BfAttributeTargets)(BfAttributeTargets_Invocation | BfAttributeTargets_MemberAccess);
- if (auto block = BfNodeDynCast<BfBlock>(attribStmt->mStatement))
- attributeState.mTarget = BfAttributeTargets_Block;
- attributeState.mCustomAttributes = GetCustomAttributes(attribStmt->mAttributes, attributeState.mTarget);
- SetAndRestoreValue<BfAttributeState*> prevAttributeState(mAttributeState, &attributeState);
- if (auto ignoreErrorsAttrib = attributeState.mCustomAttributes->Get(mCompiler->mIgnoreErrorsAttributeTypeDef))
- {
- SetAndRestoreValue<bool> ignoreErrors(mIgnoreErrors, true);
- if (!ignoreErrorsAttrib->mCtorArgs.IsEmpty())
- {
- auto constant = mCurTypeInstance->mConstHolder->GetConstant(ignoreErrorsAttrib->mCtorArgs[0]);
- if (constant->mBool)
- attributeState.mFlags = BfAttributeState::Flag_StopOnError;
- }
- VisitChild(attribStmt->mStatement);
- attributeState.mUsed = true;
- }
- else if (attributeState.mCustomAttributes->Contains(mCompiler->mConstSkipAttributeTypeDef))
- {
- if ((mCurMethodState == NULL) || (mCurMethodState->mCurScope == NULL) || (!mCurMethodState->mCurScope->mInConstIgnore))
- {
- VisitChild(attribStmt->mStatement);
- }
- else
- {
- BF_ASSERT(mBfIRBuilder->mIgnoreWrites);
- }
- attributeState.mUsed = true;
- }
- else
- {
- VisitChild(attribStmt->mStatement);
- }
- FinishAttributeState(&attributeState);
- }
- void BfModule::Visit(BfExpression* expression)
- {
- UpdateSrcPos(expression);
- BfExprEvaluator exprEvaluator(this);
- exprEvaluator.mUsedAsStatement = true;
- exprEvaluator.Evaluate(expression);
- }
- void BfModule::Visit(BfExpressionStatement* expressionStmt)
- {
- expressionStmt->mExpression->Accept(this);
- }
- void BfModule::Visit(BfThrowStatement* throwStmt)
- {
- if (throwStmt->mExpression == NULL)
- {
- AssertErrorState();
- return;
- }
- UpdateSrcPos(throwStmt->mThrowToken);
- auto throwValue = CreateValueFromExpression(throwStmt->mExpression);
- Fail("Exceptions are not supported", throwStmt->mThrowToken);
- if (mCurMethodInstance->mReturnType->IsVoid())
- EmitReturn(BfTypedValue());
- else
- EmitReturn(GetDefaultTypedValue(mCurMethodInstance->mReturnType));
- }
- void BfModule::Visit(BfDeleteStatement* deleteStmt)
- {
- UpdateSrcPos(deleteStmt);
- auto autoComplete = mCompiler->GetAutoComplete();
- if (autoComplete != NULL)
- autoComplete->CheckIdentifier(deleteStmt->mDeleteToken, true);
- bool isAppendDelete = false;
- BfTypedValue customAllocator;
- if (deleteStmt->mAllocExpr != NULL)
- {
- if (auto expr = BfNodeDynCast<BfExpression>(deleteStmt->mAllocExpr))
- customAllocator = CreateValueFromExpression(expr);
- else if (auto tokenNode = BfNodeDynCast<BfTokenNode>(deleteStmt->mAllocExpr))
- {
- if (tokenNode->mToken == BfToken_Append)
- isAppendDelete = true;
- }
- }
- BfAttributeState attributeState;
- attributeState.mTarget = BfAttributeTargets_Delete;
- SetAndRestoreValue<BfAttributeState*> prevAttributeState(mAttributeState, &attributeState);
- attributeState.mCustomAttributes = GetCustomAttributes(deleteStmt->mAttributes, attributeState.mTarget);
- if (deleteStmt->mExpression == NULL)
- {
- AssertErrorState();
- return;
- }
- auto val = CreateValueFromExpression(deleteStmt->mExpression);
- if (!val)
- return;
-
- auto checkType = val.mType;
- for (int pass = 0; pass < 2; pass++)
- {
- BfGenericParamType* genericType = NULL;
- if (checkType->IsGenericParam())
- genericType = (BfGenericParamType*)checkType;
- if ((checkType->IsPointer()) && (checkType->GetUnderlyingType()->IsGenericParam()))
- genericType = (BfGenericParamType*)checkType->GetUnderlyingType();
- if ((genericType != NULL) || (checkType->IsUnspecializedType()))
- {
- BfGenericParamFlags genericParamFlags = BfGenericParamFlag_None;
- BfType* typeConstraint = NULL;
- BfGenericParamInstance* genericParam = NULL;
- if (genericType != NULL)
- genericParam = GetMergedGenericParamData(genericType, genericParamFlags, typeConstraint);
- if (genericParam == NULL)
- GetMergedGenericParamData(checkType, genericParamFlags, typeConstraint);
- if (typeConstraint != NULL)
- checkType = typeConstraint;
- bool canAlwaysDelete = checkType->IsDelegate() || checkType->IsFunction() || checkType->IsArray();
- if (auto checkTypeInst = checkType->ToTypeInstance())
- {
- if ((checkTypeInst->IsInstanceOf(mCompiler->mDelegateTypeDef)) ||
- (checkTypeInst->IsInstanceOf(mCompiler->mFunctionTypeDef)))
- canAlwaysDelete = true;
- }
- if (!canAlwaysDelete)
- {
- bool success = false;
- if (genericParamFlags & (BfGenericParamFlag_Delete | BfGenericParamFlag_Var))
- success = true;
- else if (genericParamFlags & BfGenericParamFlag_StructPtr)
- success = true;
- else if ((genericParamFlags & BfGenericParamFlag_Struct) && (checkType->IsPointer()))
- success = true;
- if (success)
- {
- if ((pass == 1) && (genericType != NULL))
- {
- auto genericParamInst = GetGenericParamInstance(genericType);
- Warn(0, StrFormat("Must add 'where alloctype(%s) : delete' constraint to generic parameter to delete generic type '%s'",
- genericParamInst->GetGenericParamDef()->mName.c_str(), TypeToString(val.mType).c_str()), deleteStmt->mExpression);
- }
- return;
- }
- if (genericType != NULL)
- {
- auto genericParamInst = GetGenericParamInstance(genericType);
- Fail(StrFormat("Must add 'where %s : delete' constraint to generic parameter to delete generic type '%s'",
- genericParamInst->GetGenericParamDef()->mName.c_str(), TypeToString(val.mType).c_str()), deleteStmt->mExpression);
- return;
- }
- }
- }
- if (pass == 0)
- {
- if (checkType->IsAllocType())
- checkType = checkType->GetUnderlyingType();
- else
- break;
- }
- }
- if (checkType->IsVar())
- {
- // Mixin or unconstrained generic
- return;
- }
- if ((!checkType->IsPointer()) && (!checkType->IsObjectOrInterface()))
- {
- Fail(StrFormat("Cannot delete a value of type '%s'", TypeToString(val.mType).c_str()), deleteStmt->mExpression);
- return;
- }
- if (val.mType->IsGenericParam())
- return;
- auto bodyBB = mBfIRBuilder->CreateBlock("delete.body");
- auto endBB = mBfIRBuilder->CreateBlock("delete.end");
- bool mayBeSentinel = false;
- if (checkType->IsPointer())
- {
- auto innerType = checkType->GetUnderlyingType();
- PopulateType(innerType);
- if (innerType->IsValuelessType())
- mayBeSentinel = true;
- }
- BfIRValue isNotNull;
- if (mayBeSentinel)
- {
- auto intVal = mBfIRBuilder->CreatePtrToInt(val.mValue, BfTypeCode_IntPtr);
- isNotNull = mBfIRBuilder->CreateCmpGT(intVal, mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 1), false);
- }
- else
- {
- isNotNull = mBfIRBuilder->CreateIsNotNull(val.mValue);
- }
- mBfIRBuilder->CreateCondBr(isNotNull, bodyBB, endBB);
- mBfIRBuilder->AddBlock(bodyBB);
- mBfIRBuilder->SetInsertPoint(bodyBB);
- if (val.mType->IsObjectOrInterface())
- {
- EmitObjectAccessCheck(val);
- }
- SizedArray<BfIRValue, 4> llvmArgs;
- auto bitAddr = mBfIRBuilder->CreateBitCast(val.mValue, mBfIRBuilder->GetPrimitiveType(BfTypeCode_NullPtr));
- llvmArgs.push_back(bitAddr);
- if (val.mType->IsObjectOrInterface())
- {
- auto objectType = mContext->mBfObjectType;
- BfTypeInstance* checkTypeInst = val.mType->ToTypeInstance();
- bool allowPrivate = checkTypeInst == mCurTypeInstance;
- bool allowProtected = allowPrivate || TypeIsSubTypeOf(mCurTypeInstance, checkTypeInst);
- while (checkTypeInst != NULL)
- {
- auto dtorMethodDef = checkTypeInst->mTypeDef->GetMethodByName("~this");
- if (dtorMethodDef)
- {
- if (!CheckProtection(dtorMethodDef->mProtection, checkTypeInst->mTypeDef, allowProtected, allowPrivate))
- {
- auto error = Fail(StrFormat("'%s.~this()' is inaccessible due to its protection level", TypeToString(checkTypeInst).c_str()), deleteStmt->mExpression); // CS0122
- }
- }
- checkTypeInst = checkTypeInst->mBaseType;
- allowPrivate = false;
- }
- if ((mCompiler->mOptions.mObjectHasDebugFlags) && (!mIsComptimeModule))
- {
- auto preDelete = GetInternalMethod((deleteStmt->mTargetTypeToken != NULL) ? "Dbg_ObjectPreCustomDelete" : "Dbg_ObjectPreDelete");
- SizedArray<BfIRValue, 4> llvmArgs;
- llvmArgs.push_back(mBfIRBuilder->CreateBitCast(val.mValue, mBfIRBuilder->MapType(objectType)));
- mBfIRBuilder->CreateCall(preDelete.mFunc, llvmArgs);
- }
- // call dtor
- BfExprEvaluator expressionEvaluator(this);
- PopulateType(val.mType);
- PopulateType(objectType, BfPopulateType_DataAndMethods);
- if (objectType->mVirtualMethodTable.size() == 0)
- {
- if (!mCompiler->IsAutocomplete())
- AssertErrorState();
- }
- else if (!IsSkippingExtraResolveChecks())
- {
- BfMethodInstance* methodInstance = objectType->mVirtualMethodTable[mCompiler->GetVTableMethodOffset() + 0].mImplementingMethod;
- BF_ASSERT(methodInstance->mMethodDef->mName == "~this");
- SizedArray<BfIRValue, 4> llvmArgs;
- llvmArgs.push_back(mBfIRBuilder->CreateBitCast(val.mValue, mBfIRBuilder->MapType(objectType)));
- expressionEvaluator.CreateCall(deleteStmt->mDeleteToken, methodInstance, mBfIRBuilder->GetFakeVal(), false, llvmArgs);
- }
- if ((deleteStmt->mTargetTypeToken != NULL) && (!isAppendDelete))
- {
- if (deleteStmt->mAllocExpr != NULL)
- {
- if (customAllocator)
- {
- auto customAllocTypeInst = customAllocator.mType->ToTypeInstance();
- if (customAllocTypeInst != NULL)
- {
- if ((customAllocTypeInst != NULL) && (customAllocTypeInst->mTypeDef->GetMethodByName("FreeObject") != NULL))
- {
- BfTypedValueExpression typedValueExpr;
- typedValueExpr.Init(val);
- typedValueExpr.mRefNode = deleteStmt->mAllocExpr;
- BfExprEvaluator exprEvaluator(this);
- SizedArray<BfExpression*, 2> argExprs;
- argExprs.push_back(&typedValueExpr);
- BfSizedArray<BfExpression*> sizedArgExprs(argExprs);
- BfResolvedArgs argValues(&sizedArgExprs);
- exprEvaluator.ResolveArgValues(argValues);
- exprEvaluator.mNoBind = true;
- exprEvaluator.MatchMethod(deleteStmt->mAllocExpr, NULL, customAllocator, false, true, "FreeObject", argValues, BfMethodGenericArguments());
- customAllocator = BfTypedValue();
- }
- }
- }
- }
- }
- else
- {
- if ((mCompiler->mOptions.mEnableRealtimeLeakCheck) && (!mIsComptimeModule))
- {
- SizedArray<BfIRValue, 4> llvmArgs;
- llvmArgs.push_back(mBfIRBuilder->CreateBitCast(val.mValue, mBfIRBuilder->MapType(objectType)));
- auto moduleMethodInstance = GetInternalMethod("Dbg_MarkObjectDeleted");
- mBfIRBuilder->CreateCall(moduleMethodInstance.mFunc, llvmArgs);
- }
- else if (!isAppendDelete)
- {
- mBfIRBuilder->CreateCall(GetBuiltInFunc(BfBuiltInFuncType_Free), llvmArgs);
- }
- }
- }
- else
- {
- if ((isAppendDelete) || (customAllocator))
- {
- // Do nothing
- }
- else
- {
- auto func = GetBuiltInFunc(BfBuiltInFuncType_Free);
- if (!func)
- {
- BF_ASSERT(mCompiler->mIsResolveOnly);
- }
- else
- mBfIRBuilder->CreateCall(func, llvmArgs);
- }
- }
- if (customAllocator.mType == GetPrimitiveType(BfTypeCode_NullPtr))
- {
- if (!checkType->IsObjectOrInterface())
- Warn(0, "Type '%' has no destructor, so delete:null has no effect", deleteStmt->mExpression);
- }
- else if (customAllocator)
- {
- auto voidPtrType = GetPrimitiveType(BfTypeCode_NullPtr);
- auto ptrValue = BfTypedValue(mBfIRBuilder->CreateBitCast(val.mValue, mBfIRBuilder->MapType(voidPtrType)), voidPtrType);
- BfTypedValueExpression typedValueExpr;
- typedValueExpr.Init(ptrValue);
- BfExprEvaluator exprEvaluator(this);
- SizedArray<BfExpression*, 2> argExprs;
- argExprs.push_back(&typedValueExpr);
- BfSizedArray<BfExpression*> sizedArgExprs(argExprs);
- BfResolvedArgs argValues(&sizedArgExprs);
- exprEvaluator.ResolveArgValues(argValues);
- exprEvaluator.mNoBind = true;
- exprEvaluator.MatchMethod(deleteStmt->mAllocExpr, NULL, customAllocator, false, false, "Free", argValues, BfMethodGenericArguments());
- }
- mBfIRBuilder->CreateBr(endBB);
- mBfIRBuilder->AddBlock(endBB);
- mBfIRBuilder->SetInsertPoint(endBB);
- }
- void BfModule::Visit(BfSwitchStatement* switchStmt)
- {
- BfScopeData outerScope;
- outerScope.mInnerIsConditional = false;
- outerScope.mCloseNode = switchStmt;
- if (switchStmt->mCloseBrace != NULL)
- outerScope.mCloseNode = switchStmt->mCloseBrace;
- mCurMethodState->AddScope(&outerScope);
- NewScopeState();
- auto valueScopeStartOuter = ValueScopeStart();
- BfTypedValue switchValue;
- if (switchStmt->mSwitchValue == NULL)
- {
- AssertErrorState();
- UpdateSrcPos(switchStmt->mSwitchToken);
- }
- else
- {
- UpdateExprSrcPos(switchStmt->mSwitchValue);
- BfEvalExprFlags flags = BfEvalExprFlags_None;
- flags = BfEvalExprFlags_AllowSplat;
- switchValue = CreateValueFromExpression(switchStmt->mSwitchValue, NULL, flags);
- }
- EmitEnsureInstructionAt();
- if (!switchValue)
- {
- AssertErrorState();
- switchValue = GetDefaultTypedValue(mContext->mBfObjectType);
- }
- if (switchValue.mType->IsPointer())
- {
- auto underlyingType = switchValue.mType->GetUnderlyingType();
- if (underlyingType->IsEnum())
- {
- switchValue = LoadValue(switchValue);
- switchValue = BfTypedValue(switchValue.mValue, underlyingType, true);
- }
- }
- // We make the switch value conditional, but all other uses of this scope is conditional since it's conditional on cases
- BfScopeData newScope;
- newScope.mInnerIsConditional = true;
- newScope.mCloseNode = switchStmt;
- if (switchStmt->mCloseBrace != NULL)
- newScope.mCloseNode = switchStmt->mCloseBrace;
- if (switchStmt->mLabelNode != NULL)
- newScope.mLabelNode = switchStmt->mLabelNode->mLabel;
- mCurMethodState->AddScope(&newScope);
- NewScopeState();
- BfTypedValue switchValueAddr = switchValue;
- BfLocalVariable* localDef = new BfLocalVariable();
- localDef->mName = "_";
- localDef->mResolvedType = switchValueAddr.mType;
- localDef->mIsReadOnly = true;
- localDef->mAssignedKind = BfLocalVarAssignKind_Unconditional;
- if (switchValue.IsAddr())
- {
- localDef->mAddr = switchValue.mValue;
- }
- else
- {
- localDef->mValue = switchValue.mValue;
- localDef->mIsSplat = switchValue.IsSplat();
- }
- bool wantsDebugInfo = mHasFullDebugInfo && !mBfIRBuilder->mIgnoreWrites;
- bool tryExtendValue = false;
- bool addDebugInfo = true;
- if ((wantsDebugInfo) && (!switchValue.mType->IsValuelessType()) && (!switchValue.mType->IsVar()))
- {
- if (IsTargetingBeefBackend())
- {
- // We don't need to make a copy
- if (switchValue.IsSplat())
- {
- localDef->mIsSplat = true;
- if (WantsDebugInfo())
- {
- bool found = false;
- String varName = "_";
- for (auto dbgVar : mCurMethodState->mLocals)
- {
- if (dbgVar->mAddr == switchValue.mValue)
- {
- varName += "$a$" + dbgVar->mName;
- found = true;
- break;
- }
- }
- if (found)
- {
- auto fakeVal = CreateAlloca(GetPrimitiveType(BfTypeCode_Int32), true, "_fake");
- addDebugInfo = false;
- auto diVariable = mBfIRBuilder->DbgCreateAutoVariable(mCurMethodState->mCurScope->mDIScope, varName, mCurFilePosition.mFileInstance->mDIFile, mCurFilePosition.mCurLine, mBfIRBuilder->DbgGetType(localDef->mResolvedType), BfIRInitType_NotNeeded_AliveOnDecl);
- mBfIRBuilder->DbgInsertDeclare(fakeVal, diVariable);
- }
- }
- }
- else
- {
- // if (!localDef->mAddr)
- // {
- // BfIRValue value = localDef->mValue;
- // if (newLocalVar->mConstValue)
- // value = localDef->mConstValue;
- // auto aliasValue = mBfIRBuilder->CreateAliasValue(value);
- // mBfIRBuilder->DbgInsertValueIntrinsic(aliasValue, diVariable);
- // scopeData.mDeferredLifetimeEnds.push_back(aliasValue);
- // }
- tryExtendValue = true;
- }
- }
- else if ((switchValue.mType->IsComposite()) && (switchValue.IsAddr()))
- {
- auto refType = CreateRefType(switchValue.mType);
- auto allocaVal = CreateAlloca(refType);
- mBfIRBuilder->CreateStore(switchValue.mValue, allocaVal);
- auto diType = mBfIRBuilder->DbgGetType(refType);
- auto diVariable = mBfIRBuilder->DbgCreateAutoVariable(mCurMethodState->mCurScope->mDIScope,
- localDef->mName, mCurFilePosition.mFileInstance->mDIFile, mCurFilePosition.mCurLine, diType);
- mBfIRBuilder->DbgInsertDeclare(allocaVal, diVariable);
- addDebugInfo = false;
- }
- else
- {
- if (switchValueAddr.IsSplat())
- {
- auto addr = CreateAlloca(switchValue.mType);
- if (switchValue.IsSplat())
- AggregateSplatIntoAddr(switchValue, addr);
- else
- mBfIRBuilder->CreateStore(switchValue.mValue, addr);
- localDef->mAddr = addr;
- localDef->mValue = BfIRValue();
- localDef->mIsSplat = false;
- }
- }
- }
- if (!localDef->mResolvedType->IsVar())
- AddLocalVariableDef(localDef, addDebugInfo, true);
- BfDeferredLocalAssignData deferredLocalAssignData(mCurMethodState->mCurScope);
- deferredLocalAssignData.mVarIdBarrier = mCurMethodState->GetRootMethodState()->mCurLocalVarId;
- int numExpressions = 0;
- SizedArray<BfIRBlock, 8> blocks;
- SizedArray<BfWhenExpression*, 8> whenExprs;
- SizedArray<BfIRBlock, 8> whenFailBlocks;
- BfIRBlock defaultBlock;
- auto endBlock = mBfIRBuilder->CreateBlock("switch.end");
- for (BfSwitchCase* switchCase : switchStmt->mSwitchCases)
- {
- auto caseBlock = mBfIRBuilder->CreateBlock(StrFormat("switch.%d", blocks.size()));
- blocks.push_back(caseBlock);
- numExpressions += (int)switchCase->mCaseExpressions.size();
- }
- defaultBlock = mBfIRBuilder->CreateBlock("default");
- bool hasDefaultCase = switchStmt->mDefaultCase != NULL;
- if (hasDefaultCase)
- blocks.push_back(defaultBlock);
- SizedArray<BfDeferredLocalAssignData, 8> deferredLocalAssignDataVec;
- deferredLocalAssignDataVec.resize(blocks.size());
- auto boolType = GetPrimitiveType(BfTypeCode_Boolean);
- BfTypedValue enumTagVal;
- // Declare cases
- int blockIdx = 0;
- bool hadConstIntVals = false;
- bool hadWhen = false;
- BfIRValue switchStatement;
- auto switchBlock = mBfIRBuilder->GetInsertBlock();
- BfIRBlock noSwitchBlock = mBfIRBuilder->CreateBlock("noSwitch", true);
- BfPrimitiveType* intCoercibleType = GetIntCoercibleType(switchValue.mType);
- bool isConstSwitch = false;
- if ((mBfIRBuilder->IsConstValue(switchValue.mValue)) || (switchValue.mType->IsValuelessType()))
- {
- isConstSwitch = true;
- }
- if (switchValue.mValue)
- {
- mBfIRBuilder->PopulateType(switchValue.mType);
- if (intCoercibleType != NULL)
- {
- auto intValue = GetIntCoercible(switchValue);
- switchStatement = mBfIRBuilder->CreateSwitch(intValue.mValue, noSwitchBlock, numExpressions);
- }
- else if (switchValue.mType->IsPayloadEnum())
- {
- enumTagVal = ExtractValue(switchValue, NULL, 2);
- enumTagVal = LoadValue(enumTagVal);
- switchStatement = mBfIRBuilder->CreateSwitch(enumTagVal.mValue, noSwitchBlock, numExpressions);
- }
- else if ((!isConstSwitch) && (!switchValue.mType->IsVar()))
- switchStatement = mBfIRBuilder->CreateSwitch(switchValue.mValue, noSwitchBlock, numExpressions);
- }
- auto valueScopeStartInner = ValueScopeStart();
- mBfIRBuilder->SetInsertPoint(noSwitchBlock);
- bool isPayloadEnum = switchValue.mType->IsPayloadEnum();
- bool isTuple = switchValue.mType->IsTuple();
- bool isIntegralSwitch = switchValue.mType->IsIntegral() || (intCoercibleType != NULL) || ((switchValue.mType->IsEnum()) && (!isPayloadEnum));
- auto _ShowCaseError = [&] (int64 id, BfAstNode* errNode)
- {
- if (isPayloadEnum)
- {
- auto enumType = switchValue.mType->ToTypeInstance();
- for (auto& fieldInstance : enumType->mFieldInstances)
- {
- auto fieldDef = fieldInstance.GetFieldDef();
- if (fieldDef->IsEnumCaseEntry())
- {
- int enumIdx = -fieldInstance.mDataIdx - 1;
- if (enumIdx == id)
- {
- Fail(StrFormat("The switch statement already contains a case for the the value '%s'", fieldDef->mName.c_str()), errNode);
- return;
- }
- }
- }
- }
- Fail(StrFormat("The switch statement already contains a case for the the value '%lld'", id), errNode);
- };
- int caseCount = 0;
- bool allHadReturns = true;
- bool hadCondCase = false;
- BfIRBlock lastDefaultBlock;
- struct _CaseState
- {
- BfIRBlock mCondBlock;
- BfIRBlock mUncondBlock;
- };
- bool hadConstMatch = false;
- auto startingLocalVarId = mCurMethodState->GetRootMethodState()->mCurLocalVarId;
- bool prevHadFallthrough = false;
- Dictionary<int64, _CaseState> handledCases;
- HashSet<int64> condCases;
- for (BfSwitchCase* switchCase : switchStmt->mSwitchCases)
- {
- deferredLocalAssignDataVec[blockIdx].mScopeData = mCurMethodState->mCurScope;
- deferredLocalAssignDataVec[blockIdx].ExtendFrom(mCurMethodState->mDeferredLocalAssignData);
- SetAndRestoreValue<BfDeferredLocalAssignData*> prevDLA(mCurMethodState->mDeferredLocalAssignData, &deferredLocalAssignDataVec[blockIdx]);
- mCurMethodState->mDeferredLocalAssignData->mVarIdBarrier = startingLocalVarId;
- SetIllegalSrcPos();
- auto caseBlock = blocks[blockIdx];
- BfScopeData caseScopeData;
- bool openedScope = false;
- if ((mCompiler->mResolvePassData != NULL) && (mCompiler->mResolvePassData->mAutoComplete != NULL))
- {
- // This does the enum autocomplete popup
- BfAstNode* checkNode = NULL;
- int caseExprIdx = (int)switchCase->mCaseExpressions.size();
- if (caseExprIdx == 0)
- checkNode = switchCase->mCaseToken;
- else if (caseExprIdx - 1 < (int)switchCase->mCaseCommas.size())
- checkNode = switchCase->mCaseCommas[caseExprIdx - 1];
- if (checkNode != NULL)
- mCompiler->mResolvePassData->mAutoComplete->CheckEmptyStart(checkNode, switchValue.mType);
- }
- bool mayHaveMatch = false;
- BfWhenExpression* whenExpr = NULL;
- for (BfExpression* caseExpr : switchCase->mCaseExpressions)
- {
- if (auto checkWhenExpr = BfNodeDynCast<BfWhenExpression>(caseExpr))
- {
- hadWhen = true;
- whenExpr = checkWhenExpr;
- }
- }
- bool wantsOpenedScope = isPayloadEnum || isTuple;
- BfIRBlock lastNotEqBlock;
- for (BfExpression* caseExpr : switchCase->mCaseExpressions)
- {
- BfConstant* constantInt = NULL;
- if (auto checkWhenExpr = BfNodeDynCast<BfWhenExpression>(caseExpr))
- continue;
- if ((!openedScope) && (wantsOpenedScope))
- {
- openedScope = true;
- caseScopeData.mOuterIsConditional = true;
- caseScopeData.mIsSharedTempBlock = true;
- mCurMethodState->AddScope(&caseScopeData);
- NewScopeState();
- UpdateSrcPos(caseExpr);
- SetIllegalSrcPos();
- }
- BfIRValue eqResult;
- BfIRBlock notEqBB;
- bool handled = false;
- BfTypedValue caseValue;
- BfIRBlock doBlock = caseBlock;
- bool hadConditional = false;
- bool isEnumDescValue = isPayloadEnum;
- if (isPayloadEnum)
- {
- auto dscrType = switchValue.mType->ToTypeInstance()->GetDiscriminatorType();
- if (!enumTagVal)
- {
- enumTagVal = ExtractValue(switchValue, NULL, 2);
- enumTagVal = LoadValue(enumTagVal);
- }
- notEqBB = mBfIRBuilder->CreateBlock(StrFormat("switch.notEq.%d", blockIdx), false);
- int tagId = -1;
- BfIRBlock matchBlock;
- BfTypedValue eqTypedResult;
- if (auto bindExpr = BfNodeDynCast<BfEnumCaseBindExpression>(caseExpr))
- {
- eqTypedResult = HandleCaseBind(switchValueAddr, enumTagVal, bindExpr, &caseBlock, ¬EqBB, &matchBlock, &tagId);
- }
- else
- {
- eqTypedResult = TryCaseEnumMatch(switchValueAddr, enumTagVal, caseExpr, &caseBlock, ¬EqBB, &matchBlock, tagId, hadConditional, false, prevHadFallthrough);
- if (auto constant = mBfIRBuilder->GetConstant(eqTypedResult.mValue))
- {
- if (constant->mBool)
- mayHaveMatch = true;
- }
- if (hadConditional)
- hadCondCase = true;
- }
- if (tagId != -1)
- {
- doBlock = matchBlock; // Jump to binds rather than just the code
- caseValue = BfTypedValue(GetConstValue(tagId, GetPrimitiveType(dscrType->mTypeDef->mTypeCode)), dscrType);
- }
- else
- hadCondCase = true;
- if (eqTypedResult)
- {
- handled = true;
- eqResult = eqTypedResult.mValue;
- }
- }
- else if (auto tupleExpr = BfNodeDynCast<BfTupleExpression>(caseExpr))
- {
- notEqBB = mBfIRBuilder->CreateBlock(StrFormat("switch.notEq.%d", blockIdx), false);
- BfIRBlock matchBlock;
- BfTypedValue eqTypedResult = TryCaseTupleMatch(switchValue, tupleExpr, &caseBlock, ¬EqBB, &matchBlock, hadConditional, false, prevHadFallthrough);
- if (hadConditional)
- hadCondCase = true;
- if (eqTypedResult)
- {
- mayHaveMatch = true;
- handled = true;
- eqResult = eqTypedResult.mValue;
- }
- }
- if (!eqResult)
- {
- caseValue = CreateValueFromExpression(caseExpr, switchValue.mType, (BfEvalExprFlags)(BfEvalExprFlags_AllowEnumId | BfEvalExprFlags_NoCast));
- if (!caseValue)
- continue;
- isEnumDescValue = false;
- }
- BfTypedValue caseIntVal = caseValue;
- if ((isIntegralSwitch) || (isPayloadEnum))
- {
- if ((intCoercibleType != NULL) &&
- (caseValue.mType == switchValue.mType) &&
- (caseValue.mValue.IsConst()))
- {
- caseIntVal = GetIntCoercible(caseValue);
- constantInt = mBfIRBuilder->GetConstant(caseIntVal.mValue);
- }
- else
- {
- // For a non-const case, allow for conversion operators, otherwise cast now
- if ((isIntegralSwitch) && (caseValue.mValue.IsConst()))
- {
- if (caseValue.mType != switchValue.mType)
- {
- caseValue = Cast(caseExpr, caseValue, switchValue.mType);
- if (!caseValue)
- continue;
- caseIntVal = caseValue;
- }
- }
- if ((caseValue.mType == switchValue.mType) || (eqResult))
- {
- constantInt = mBfIRBuilder->GetConstant(caseValue.mValue);
- if ((constantInt != NULL) && (!mBfIRBuilder->IsInt(constantInt->mTypeCode)))
- constantInt = NULL;
- }
- }
- }
- if ((!switchStatement) && (!isConstSwitch))
- {
- // Do nothing
- mayHaveMatch = true;
- }
- else if ((constantInt != NULL) && (!hadWhen) && (!isConstSwitch))
- {
- if (hadConditional)
- {
- condCases.Add(constantInt->mInt64);
- }
- else
- {
- _CaseState* caseState = NULL;
- handledCases.TryAdd(constantInt->mInt64, NULL, &caseState);
- if (condCases.Contains(constantInt->mInt64))
- {
- // This is a 'case .A:' after a 'case .A(let value):'
- eqResult = mBfIRBuilder->CreateCmpEQ(enumTagVal.mValue, caseValue.mValue);
- notEqBB = mBfIRBuilder->CreateBlock(StrFormat("switch.notEq.%d", blockIdx));
- mayHaveMatch = true;
- mBfIRBuilder->CreateCondBr(eqResult, caseBlock, notEqBB);
- mBfIRBuilder->AddBlock(notEqBB);
- mBfIRBuilder->SetInsertPoint(notEqBB);
- }
- else
- {
- if (caseState->mUncondBlock)
- {
- _ShowCaseError(constantInt->mInt64, caseExpr);
- }
- else
- {
- caseState->mUncondBlock = doBlock;
- mBfIRBuilder->AddSwitchCase(switchStatement, caseIntVal.mValue, doBlock);
- hadConstIntVals = true;
- }
- }
- }
- mayHaveMatch = true;
- }
- else if (!handled)
- {
- hadCondCase = true;
- if (!eqResult)
- {
- BfExprEvaluator exprEvaluator(this);
- BfAstNode* refNode = switchCase->mColonToken;
- if ((caseValue.mType->IsPayloadEnum()) && (caseValue.mValue.IsConst()) && (switchValue.mType == caseValue.mType) &&
- ((isEnumDescValue) || (constantInt != NULL)))
- {
- if (!enumTagVal)
- {
- enumTagVal = ExtractValue(switchValue, NULL, 2);
- enumTagVal = LoadValue(enumTagVal);
- }
- eqResult = mBfIRBuilder->CreateCmpEQ(enumTagVal.mValue, caseValue.mValue);
- }
- else
- {
- exprEvaluator.PerformBinaryOperation(switchStmt->mSwitchValue, caseExpr, BfBinaryOp_Equality, refNode, (BfBinOpFlags)(BfBinOpFlag_ForceLeftType), switchValue, caseValue);
- if (switchStmt->mSwitchValue != NULL)
- UpdateSrcPos(switchStmt->mSwitchValue);
- SetIllegalSrcPos();
- eqResult = exprEvaluator.mResult.mValue;
- if (!eqResult)
- eqResult = GetConstValue(0, boolType);
- }
- }
- ValueScopeEnd(valueScopeStartInner);
- bool isConstResult = false;
- bool constResult = false;
- if (eqResult.IsConst())
- {
- auto constant = mBfIRBuilder->GetConstant(eqResult);
- if (constant->mTypeCode == BfTypeCode_Boolean)
- {
- isConstResult = true;
- constResult = constant->mBool;
- }
- }
- if (isConstResult)
- {
- if (constResult)
- {
- mBfIRBuilder->CreateBr(caseBlock);
- mayHaveMatch = true;
- if (whenExpr == NULL)
- {
- hadConstMatch = true;
- }
- else
- {
- notEqBB = mBfIRBuilder->CreateBlock(StrFormat("switch.notEq.%d", blockIdx));
- mBfIRBuilder->AddBlock(notEqBB);
- mBfIRBuilder->SetInsertPoint(notEqBB);
- }
- }
- }
- else
- {
- notEqBB = mBfIRBuilder->CreateBlock(StrFormat("switch.notEq.%d", blockIdx));
- mayHaveMatch = true;
- mBfIRBuilder->CreateCondBr(eqResult, caseBlock, notEqBB);
- mBfIRBuilder->AddBlock(notEqBB);
- mBfIRBuilder->SetInsertPoint(notEqBB);
- }
- }
- else if (whenExpr != NULL)
- {
- mayHaveMatch = true;
- }
- if (notEqBB)
- lastNotEqBlock = notEqBB;
- if ((!hadCondCase) && (notEqBB))
- lastDefaultBlock = notEqBB;
- }
- if ((whenExpr != NULL) && (switchCase->mCaseExpressions.size() == 1))
- {
- // This was a "case when" expression, always matches
- mayHaveMatch = true;
- auto notEqBB = mBfIRBuilder->CreateBlock(StrFormat("switch.notEq_when.%d", blockIdx));
- mBfIRBuilder->CreateBr(caseBlock);
- mBfIRBuilder->AddBlock(notEqBB);
- mBfIRBuilder->SetInsertPoint(notEqBB);
- lastNotEqBlock = notEqBB;
- }
- if ((lastDefaultBlock) && (switchStatement))
- mBfIRBuilder->SetSwitchDefaultDest(switchStatement, lastDefaultBlock);
- auto prevInsertBlock = mBfIRBuilder->GetInsertBlock();
- bool isConstIgnore = !mayHaveMatch && !prevHadFallthrough;
- SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true, isConstIgnore);
- SetAndRestoreValue<bool> prevInConstIgnore(mCurMethodState->mCurScope->mInConstIgnore, true, isConstIgnore);
- mBfIRBuilder->AddBlock(caseBlock);
- mBfIRBuilder->SetInsertPoint(caseBlock);
- if (whenExpr != NULL)
- {
- UpdateSrcPos(whenExpr);
- BfTypedValue whenValue;
- if (whenExpr->mExpression != NULL)
- whenValue = CreateValueFromExpression(whenExpr->mExpression, boolType, BfEvalExprFlags_AllowEnumId);
- if (!whenValue)
- {
- AssertErrorState();
- whenValue = GetDefaultTypedValue(boolType);
- }
- bool constResult = false;
- if (mBfIRBuilder->TryGetBool(whenValue.mValue, constResult))
- {
- if (!constResult)
- prevIgnoreWrites.Set();
- }
- else
- {
- BfIRBlock eqBB = mBfIRBuilder->CreateBlock(StrFormat("switch.when.%d", blockIdx));
- mBfIRBuilder->CreateCondBr(whenValue.mValue, eqBB, lastNotEqBlock);
- mBfIRBuilder->AddBlock(eqBB);
- mBfIRBuilder->SetInsertPoint(eqBB);
- }
- }
- BfIRBlock fallthroughBlock;
- if (blockIdx < (int) blocks.size() - 1)
- fallthroughBlock = blocks[blockIdx + 1];
- else
- fallthroughBlock = defaultBlock;
- bool hadReturn = false;
- if ((switchCase->mCodeBlock != NULL) && (!switchCase->mCodeBlock->mChildArr.IsEmpty()))
- {
- UpdateSrcPos(switchCase->mCodeBlock);
- VisitCodeBlock(switchCase->mCodeBlock, BfIRBlock(), endBlock, fallthroughBlock, true, &hadReturn, switchStmt->mLabelNode, openedScope /*, BfEmbeddedStatementFlags_RescopeDLA*/);
- openedScope = false;
- deferredLocalAssignDataVec[blockIdx].mHadReturn = hadReturn;
- caseCount++;
- if ((!hadReturn) &&
- ((!mCurMethodState->mDeferredLocalAssignData->mHadFallthrough) || (mCurMethodState->mDeferredLocalAssignData->mHadBreak)))
- allHadReturns = false;
- if (auto block = BfNodeDynCast<BfBlock>(switchCase->mCodeBlock))
- {
- //
- }
- else
- {
- if (switchStmt->mCloseBrace != NULL)
- {
- UpdateSrcPos(switchStmt->mCloseBrace);
- }
- EmitEnsureInstructionAt();
- }
- //UpdateSrcPos(switchCase->mCodeBlock);
- //SetIllegalSrcPos();
- mBfIRBuilder->ClearDebugLocation();
- }
- else
- {
- if (openedScope)
- RestoreScopeState();
- mBfIRBuilder->CreateBr(endBlock);
- allHadReturns = false;
- }
- prevIgnoreWrites.Restore();
- mBfIRBuilder->SetInsertPoint(prevInsertBlock);
- prevHadFallthrough = mCurMethodState->mDeferredLocalAssignData->mHadFallthrough;
- blockIdx++;
- }
- // Check for comprehensiveness
- bool isComprehensive = true;
- if ((switchValue) && (switchStmt->mDefaultCase == NULL))
- {
- if (switchValue.mType->IsEnum())
- {
- if (hadConstMatch)
- {
- // Already handled
- }
- else
- {
- auto enumType = switchValue.mType->ToTypeInstance();
- if (enumType->IsPayloadEnum())
- {
- int lastTagId = -1;
- for (auto& field : enumType->mFieldInstances)
- {
- auto fieldDef = field.GetFieldDef();
-
- if (fieldDef == NULL)
- continue;
- if (!fieldDef->IsEnumCaseEntry())
- continue;
- if (field.mDataIdx < 0)
- lastTagId = -field.mDataIdx - 1;
- }
- isComprehensive = lastTagId == (int)handledCases.size() - 1;
- }
- else
- {
- for (auto& field : enumType->mFieldInstances)
- {
- auto fieldDef = field.GetFieldDef();
- if ((fieldDef != NULL) && (fieldDef->IsEnumCaseEntry()))
- {
- if (field.mConstIdx != -1)
- {
- auto constant = enumType->mConstHolder->GetConstantById(field.mConstIdx);
- isComprehensive &= handledCases.ContainsKey(constant->mInt64);
- }
- }
- }
- }
- }
- if (!isComprehensive)
- {
- Fail("Switch must be exhaustive, consider adding a default clause", switchStmt->mSwitchToken);
- }
- }
- else
- isComprehensive = false;
- }
- BfAstNode* refNode = switchStmt->mSwitchToken;
- if ((switchStmt->mCloseBrace) && (mCompiler->IsAutocomplete()) && (mCompiler->mResolvePassData->mAutoComplete->CheckFixit((switchStmt->mSwitchToken))))
- {
- BfParserData* parser = refNode->GetSourceData()->ToParserData();
- if (parser != NULL)
- {
- if (switchStmt->mDefaultCase == NULL)
- {
- int fileLoc = switchStmt->mCloseBrace->GetSrcStart();
- mCompiler->mResolvePassData->mAutoComplete->AddEntry(AutoCompleteEntry("fixit", StrFormat("Add default case\tdefault:|%s|%d||default:", parser->mFileName.c_str(), fileLoc).c_str()));
- }
- if ((switchValue.mType->IsEnum()) && (!isComprehensive) || (switchStmt->mDefaultCase != NULL))
- {
- int fileLoc;
- if ((handledCases.IsEmpty()) && (switchStmt->mOpenBrace != NULL))
- fileLoc = switchStmt->mOpenBrace->GetSrcEnd() + 1;
- else if (switchStmt->mDefaultCase != NULL)
- fileLoc = switchStmt->mDefaultCase->GetSrcStart();
- else
- fileLoc = switchStmt->mCloseBrace->GetSrcStart();
- String explicitInsertStr;
- auto enumType = switchValue.mType->ToTypeInstance();
- HashSet<int64> missingValues;
- if (enumType->IsPayloadEnum())
- {
- for (auto& field : enumType->mFieldInstances)
- {
- auto fieldDef = field.GetFieldDef();
- if (fieldDef == NULL)
- continue;
- if (!fieldDef->IsEnumCaseEntry())
- continue;
- if ((field.mDataIdx < 0))
- {
- auto key = -field.mDataIdx - 1;
- if ((!handledCases.ContainsKey(key)) && (missingValues.Add(key)))
- {
- auto paramDecl = fieldDef->mTypeRef;
- if ((field.mIsEnumPayloadCase) && (field.mResolvedType->IsTuple()))
- {
- auto payloadType = (BfTypeInstance*)field.mResolvedType;
- if (!payloadType->mFieldInstances.empty())
- {
- String fieldsStr;
- int count = 0;
- for (auto& payloadField : payloadType->mFieldInstances)
- {
- auto payloadFieldDef = payloadField.GetFieldDef();
- if (payloadFieldDef == NULL)
- continue;
- String fieldName = payloadFieldDef->mName;
- if ((fieldName.IsEmpty()) || (fieldName.length() > 0) && (isdigit(fieldName[0])))
- fieldName = StrFormat("p%d", count);
- if (count > 0)
- fieldsStr += ", ";
- fieldsStr += StrFormat("let %s", fieldName.c_str());
- count++;
- }
- if (!fieldsStr.IsEmpty())
- {
- explicitInsertStr += StrFormat("|case .%s(%s):", fieldDef->mName.c_str(), fieldsStr.c_str());
- continue;
- }
- }
- }
- explicitInsertStr += StrFormat("|case .%s:", fieldDef->mName.c_str());
- }
- }
- }
- }
- else
- {
- for (auto& field : enumType->mFieldInstances)
- {
- auto fieldDef = field.GetFieldDef();
- if ((fieldDef != NULL) && (fieldDef->IsEnumCaseEntry()))
- {
- if (field.mConstIdx != -1)
- {
- auto constant = enumType->mConstHolder->GetConstantById(field.mConstIdx);
- if ((!handledCases.ContainsKey(constant->mInt64)) && (missingValues.Add(constant->mInt64)))
- {
- explicitInsertStr += StrFormat("|case .%s:", fieldDef->mName.c_str());
- }
- }
- }
- }
- }
- if (missingValues.GetCount() > 0)
- mCompiler->mResolvePassData->mAutoComplete->AddEntry(AutoCompleteEntry("fixit", StrFormat("Add missing cases\tdefault:|%s|%d|%s", parser->mFileName.c_str(), fileLoc, explicitInsertStr.c_str()).c_str()));
- }
- }
- }
- if (!hadConstMatch)
- mBfIRBuilder->CreateBr(defaultBlock);
- mBfIRBuilder->SetInsertPoint(switchBlock);
- if (!hadConstIntVals)
- {
- if (switchStatement)
- mBfIRBuilder->EraseInstFromParent(switchStatement);
- mBfIRBuilder->CreateBr(noSwitchBlock);
- }
- if (switchStmt->mDefaultCase != NULL)
- {
- SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true, hadConstMatch);
- SetAndRestoreValue<bool> prevInConstIgnore(mCurMethodState->mCurScope->mInConstIgnore, true, hadConstMatch);
- mBfIRBuilder->AddBlock(defaultBlock);
- mBfIRBuilder->SetInsertPoint(defaultBlock);
- auto switchCase = switchStmt->mDefaultCase;
- if (switchCase->mCodeBlock != NULL)
- {
- isComprehensive = true;
- UpdateSrcPos(switchCase->mCodeBlock);
- deferredLocalAssignDataVec[blockIdx].mScopeData = mCurMethodState->mCurScope;
- deferredLocalAssignDataVec[blockIdx].ExtendFrom(mCurMethodState->mDeferredLocalAssignData);
- SetAndRestoreValue<BfDeferredLocalAssignData*> prevDLA(mCurMethodState->mDeferredLocalAssignData, &deferredLocalAssignDataVec[blockIdx]);
- mCurMethodState->mDeferredLocalAssignData->mVarIdBarrier = startingLocalVarId;
- BfScopeData caseScopeData;
- caseScopeData.mOuterIsConditional = true;
- caseScopeData.mIsSharedTempBlock = true;
- mCurMethodState->AddScope(&caseScopeData);
- NewScopeState();
- caseScopeData.mLabel = newScope.mLabel;
- bool hadReturn = false;
- VisitCodeBlock(switchCase->mCodeBlock, BfIRBlock(), endBlock, BfIRBlock(), true, &hadReturn, switchStmt->mLabelNode);
- deferredLocalAssignDataVec[blockIdx].mHadReturn = hadReturn;
- caseCount++;
- if (!hadReturn)
- allHadReturns = false;
- RestoreScopeState();
- }
- }
- else
- {
- mBfIRBuilder->AddBlock(defaultBlock);
- mBfIRBuilder->SetInsertPoint(defaultBlock);
- if (isComprehensive)
- {
- mBfIRBuilder->CreateUnreachable();
- //TODO: This masks a bug in our backend
- if (IsTargetingBeefBackend())
- mBfIRBuilder->CreateBr(endBlock);
- }
- else
- mBfIRBuilder->CreateBr(endBlock);
- }
- if (isComprehensive)
- {
- // Merge and apply deferred local assign data
- // We only do this if there's a default case, otherwise we assume we may have missed a case
- // that by definition had no local assigns
- BfDeferredLocalAssignData* mergedDeferredLocalAssignData = NULL;
- for (blockIdx = 0; blockIdx < (int)blocks.size(); blockIdx++)
- {
- auto deferredLocalAssignData = &deferredLocalAssignDataVec[blockIdx];
- if (deferredLocalAssignData->mHadFallthrough)
- continue;
- if (mergedDeferredLocalAssignData == NULL)
- mergedDeferredLocalAssignData = deferredLocalAssignData;
- else
- mergedDeferredLocalAssignData->SetIntersection(*deferredLocalAssignData);
- }
- if (mergedDeferredLocalAssignData != NULL)
- mCurMethodState->ApplyDeferredLocalAssignData(*mergedDeferredLocalAssignData);
- }
- if ((caseCount > 0) && (allHadReturns) &&
- ((hasDefaultCase) || (isComprehensive)))
- {
- mCurMethodState->SetHadReturn(true);
- mCurMethodState->mLeftBlockUncond = true;
- if ((!hasDefaultCase) && (!isComprehensive))
- mBfIRBuilder->DeleteBlock(endBlock);
- else
- {
- if (switchStmt->mCloseBrace != NULL)
- UpdateSrcPos(switchStmt->mCloseBrace);
- mBfIRBuilder->AddBlock(endBlock);
- mBfIRBuilder->SetInsertPoint(endBlock);
- mBfIRBuilder->CreateUnreachable();
- }
- }
- else
- {
- if (switchStmt->mCloseBrace != NULL)
- UpdateSrcPos(switchStmt->mCloseBrace);
- mBfIRBuilder->AddBlock(endBlock);
- mBfIRBuilder->SetInsertPoint(endBlock);
- }
- BfIRValue lifetimeExtendVal;
- if (tryExtendValue)
- {
- if (localDef->mAddr)
- lifetimeExtendVal = localDef->mAddr;
- else
- lifetimeExtendVal = localDef->mValue;
- }
- RestoreScopeState(); // newScope
- RestoreScopeState(); // outerScope
- if (lifetimeExtendVal)
- mBfIRBuilder->CreateLifetimeExtend(lifetimeExtendVal);
- ValueScopeEnd(valueScopeStartOuter);
- }
- static int gRetIdx = 0;
- void BfModule::Visit(BfReturnStatement* returnStmt)
- {
- if ((mCurMethodInstance == NULL) || (mCurMethodState->mDisableReturns))
- {
- Fail("Unexpected return", returnStmt);
- if (returnStmt->mExpression != NULL)
- {
- BfExprEvaluator exprEvaluator(this);
- CreateValueFromExpression(exprEvaluator, returnStmt->mExpression);
- }
- return;
- }
- UpdateSrcPos(returnStmt);
- EmitEnsureInstructionAt();
- auto retType = mCurMethodInstance->mReturnType;
- if (mCurMethodInstance->IsMixin())
- retType = NULL;
- bool inferReturnType = false;
- if (mCurMethodState->mClosureState != NULL)
- {
- retType = mCurMethodState->mClosureState->mReturnType;
- inferReturnType = (mCurMethodState->mClosureState->mReturnTypeInferState != BfReturnTypeInferState_None);
- }
- auto checkScope = mCurMethodState->mCurScope;
- while (checkScope != NULL)
- {
- if (checkScope->mIsDeferredBlock)
- {
- Fail("Deferred blocks cannot contain 'return' statements", returnStmt);
- if (returnStmt->mExpression != NULL)
- {
- BfExprEvaluator exprEvaluator(this);
- CreateValueFromExpression(exprEvaluator, returnStmt->mExpression, GetPrimitiveType(BfTypeCode_Var), BfEvalExprFlags_None);
- }
- return;
- }
- if (checkScope->mInInitBlock)
- {
- Fail("Initialization blocks cannot contain 'return' statements", returnStmt);
- }
- checkScope = checkScope->mPrevScope;
- }
- auto checkLocalAssignData = mCurMethodState->mDeferredLocalAssignData;
- while (checkLocalAssignData != NULL)
- {
- if (checkLocalAssignData->mScopeData != NULL)
- checkLocalAssignData->mLeftBlock = true;
- checkLocalAssignData = checkLocalAssignData->mChainedAssignData;
- }
- if ((retType == NULL) && (!inferReturnType))
- {
- if (returnStmt->mExpression != NULL)
- {
- BfExprEvaluator exprEvaluator(this);
- CreateValueFromExpression(exprEvaluator, returnStmt->mExpression, GetPrimitiveType(BfTypeCode_Var), BfEvalExprFlags_None);
- }
- MarkScopeLeft(&mCurMethodState->mHeadScope);
- return;
- }
- if (returnStmt->mExpression == NULL)
- {
- MarkScopeLeft(&mCurMethodState->mHeadScope);
- if ((retType != NULL) && (retType->IsVoid()))
- {
- EmitReturn(BfTypedValue());
- return;
- }
- Fail("Expected return value", returnStmt);
- if (retType != NULL)
- EmitReturn(GetDefaultTypedValue(retType));
- else
- EmitReturn(BfTypedValue());
- return;
- }
- BfType* expectingReturnType = retType;
- BfType* origType;
- BfExprEvaluator exprEvaluator(this);
- bool alreadyWritten = false;
- if ((!mIsComptimeModule) && (mCurMethodInstance->GetStructRetIdx() != -1))
- exprEvaluator.mReceivingValue = &mCurMethodState->mRetVal;
- if (mCurMethodInstance->mMethodDef->mIsReadOnly)
- exprEvaluator.mAllowReadOnlyReference = true;
- if (inferReturnType)
- expectingReturnType = NULL;
- auto retValue = CreateValueFromExpression(exprEvaluator, returnStmt->mExpression, expectingReturnType, BfEvalExprFlags_AllowRefExpr, &origType);
- if ((retValue) && (inferReturnType))
- {
- if (mCurMethodState->mClosureState->mReturnType == NULL)
- mCurMethodState->mClosureState->mReturnType = retValue.mType;
- else
- {
- if ((retValue.mType == mCurMethodState->mClosureState->mReturnType) ||
- (CanCast(retValue, mCurMethodState->mClosureState->mReturnType)))
- {
- // Leave as-is
- }
- else if (CanCast(GetFakeTypedValue(mCurMethodState->mClosureState->mReturnType), retValue.mType))
- {
- mCurMethodState->mClosureState->mReturnType = retValue.mType;
- }
- else
- {
- mCurMethodState->mClosureState->mReturnTypeInferState = BfReturnTypeInferState_Fail;
- }
- }
- }
- if ((retType == NULL) && (inferReturnType))
- retType = mCurMethodState->mClosureState->mReturnType;
- if (retType == NULL)
- retType = GetPrimitiveType(BfTypeCode_None);
- if ((!mIsComptimeModule) && (mCurMethodInstance->GetStructRetIdx() != -1))
- alreadyWritten = exprEvaluator.mReceivingValue == NULL;
- MarkScopeLeft(&mCurMethodState->mHeadScope);
- if (!retValue)
- {
- AssertErrorState();
- if ((expectingReturnType != NULL) && (!expectingReturnType->IsVoid()))
- {
- retValue = GetDefaultTypedValue(expectingReturnType, true);
- }
- else
- {
- EmitReturn(BfTypedValue());
- return;
- }
- }
- if (retValue.mType->IsVar())
- {
- EmitReturn(BfTypedValue());
- }
- else if (retValue.mType->IsVoid())
- {
- if (retType->IsVoid())
- {
- Warn(0, "Returning void value", returnStmt->mReturnToken);
- EmitReturn(BfTypedValue());
- }
- }
- else
- {
- if (retType->IsVoid())
- {
- expectingReturnType = NULL;
- Fail("Attempting to return value from void method", returnStmt->mExpression);
- EmitReturn(BfTypedValue());
- return;
- }
- if ((origType != NULL) && (origType->IsStructOrStructPtr()) && (retValue.mType->IsObjectOrInterface()))
- {
- Fail(StrFormat("Stack boxing of type '%s' is not allowed on return statements. Use 'new box' to box on the heap.", TypeToString(origType).c_str()), returnStmt->mExpression);
- }
- if (!alreadyWritten)
- EmitReturn(LoadOrAggregateValue(retValue));
- else
- EmitReturn(BfTypedValue());
- }
- }
- void BfModule::Visit(BfYieldStatement* yieldStmt)
- {
- Fail("Yield not supported", yieldStmt);
- }
- void BfModule::Visit(BfBreakStatement* breakStmt)
- {
- bool inMixinDecl = (mCurMethodInstance != NULL) && (mCurMethodInstance->IsMixin());
- UpdateSrcPos(breakStmt);
- EmitEnsureInstructionAt();
- BfBreakData* breakData = mCurMethodState->mBreakData;
- if (breakStmt->mLabel != NULL)
- {
- breakData = FindBreakData(breakStmt->mLabel);
- }
- else
- {
- while (breakData != NULL)
- {
- if (breakData->mIRBreakBlock)
- break;
- breakData = breakData->mPrevBreakData;
- }
- }
- if ((mCompiler->mResolvePassData != NULL) && (mCompiler->mResolvePassData->mAutoComplete != NULL))
- {
- BfScopeData* scope = NULL;
- if (breakData != NULL)
- scope = breakData->mScope;
- if (auto identifer = BfNodeDynCast<BfIdentifierNode>(breakStmt->mLabel))
- mCompiler->mResolvePassData->mAutoComplete->CheckLabel(identifer, breakStmt->mBreakNode, scope);
- }
- if ((breakData == NULL) || (!breakData->mIRBreakBlock))
- {
- if (inMixinDecl)
- {
- // Our mixin may just require that we're injected into a breakable scope
- }
- else
- Fail("'break' not applicable in this block", breakStmt);
- return;
- }
- if (mCurMethodState->mInDeferredBlock)
- {
- auto checkScope = mCurMethodState->mCurScope;
- while (checkScope != NULL)
- {
- if (checkScope == breakData->mScope)
- break;
- if (checkScope->mIsDeferredBlock)
- {
- Fail("The break target crosses a deferred block boundary", breakStmt);
- return;
- }
- checkScope = checkScope->mPrevScope;
- }
- }
- if (HasDeferredScopeCalls(breakData->mScope))
- {
- EmitDeferredScopeCalls(true, breakData->mScope, breakData->mIRBreakBlock);
- }
- else
- {
- mBfIRBuilder->CreateBr(breakData->mIRBreakBlock);
- }
- mCurMethodState->mLeftBlockUncond = true;
- bool isCond = false;
- int uncondScopeDepth = 0;
- if (mCurMethodState->mCurScope != NULL)
- uncondScopeDepth = mCurMethodState->mCurScope->mScopeDepth + 1;
- BfIRValue earliestValueScopeStart;
- auto checkScope = mCurMethodState->mCurScope;
- while (checkScope != NULL)
- {
- if (!isCond)
- uncondScopeDepth = checkScope->mScopeDepth;
- if ((checkScope->mOuterIsConditional) && (!checkScope->mIsSharedTempBlock))
- isCond = true;
- if (checkScope->mValueScopeStart)
- earliestValueScopeStart = checkScope->mValueScopeStart;
- if (checkScope == breakData->mScope)
- break;
- checkScope = checkScope->mPrevScope;
- }
- auto checkLocalAssignData = mCurMethodState->mDeferredLocalAssignData;
- while (checkLocalAssignData != NULL)
- {
- if ((checkLocalAssignData->mScopeData != NULL) && (checkLocalAssignData->mScopeData->mScopeDepth >= breakData->mScope->mScopeDepth))
- {
- if (checkLocalAssignData->mScopeData->mScopeDepth >= uncondScopeDepth)
- checkLocalAssignData->mLeftBlockUncond = true;
- checkLocalAssignData->mLeftBlock = true;
- checkLocalAssignData->mHadBreak = true;
- }
- checkLocalAssignData = checkLocalAssignData->mChainedAssignData;
- }
- MarkScopeLeft(breakData->mScope);
- ValueScopeEnd(earliestValueScopeStart);
- auto checkBreakData = mCurMethodState->mBreakData;
- while (true)
- {
- checkBreakData->mHadBreak = true;
- if (checkBreakData == breakData)
- break;
- checkBreakData = checkBreakData->mPrevBreakData;
- }
- }
- void BfModule::Visit(BfContinueStatement* continueStmt)
- {
- bool inMixinDecl = (mCurMethodInstance != NULL) && (mCurMethodInstance->IsMixin());
- UpdateSrcPos(continueStmt);
- EmitEnsureInstructionAt();
- // If we're in a switch, 'break' is valid but we need to continue looking outward for a 'continue' target
- BfBreakData* breakData = mCurMethodState->mBreakData;
- if (continueStmt->mLabel != NULL)
- {
- breakData = FindBreakData(continueStmt->mLabel);
- if ((breakData != NULL) && (!breakData->mIRContinueBlock))
- {
- Fail(StrFormat("'continue' not applicable in '%s'", continueStmt->mLabel->ToString().c_str()), continueStmt);
- return;
- }
- }
- else
- {
- while (breakData != NULL)
- {
- if (breakData->mIRContinueBlock)
- break;
- breakData = breakData->mPrevBreakData;
- }
- }
- if ((mCompiler->mResolvePassData != NULL) && (mCompiler->mResolvePassData->mAutoComplete != NULL))
- {
- BfScopeData* scope = NULL;
- if (breakData != NULL)
- scope = breakData->mScope;
- if (auto identifer = BfNodeDynCast<BfIdentifierNode>(continueStmt->mLabel))
- mCompiler->mResolvePassData->mAutoComplete->CheckLabel(identifer, continueStmt->mContinueNode, scope);
- }
- if ((breakData == NULL) || (!breakData->mIRContinueBlock))
- {
- if (inMixinDecl)
- {
- // Our mixin may just require that we're injected into a breakable scope
- }
- else
- Fail("'continue' not applicable in this block", continueStmt);
- return;
- }
- BfIRValue earliestValueScopeStart;
- // We don't want to close out our own scope, we want to close out any scopes that were opened after us
- auto nextScope = mCurMethodState->mCurScope;
- while (nextScope != NULL)
- {
- if (nextScope->mValueScopeStart)
- earliestValueScopeStart = nextScope->mValueScopeStart;
- if (nextScope->mPrevScope == breakData->mScope)
- break;
- nextScope = nextScope->mPrevScope;
- }
- if (breakData->mInnerValueScopeStart)
- earliestValueScopeStart = breakData->mInnerValueScopeStart;
- if (mCurMethodState->mInDeferredBlock)
- {
- auto checkScope = mCurMethodState->mCurScope;
- while (checkScope != NULL)
- {
- if (checkScope == breakData->mScope)
- break;
- if (checkScope->mIsDeferredBlock)
- {
- Fail("The continue target crosses a deferred block boundary", continueStmt);
- return;
- }
- checkScope = checkScope->mPrevScope;
- }
- }
- if ((nextScope != NULL) && (HasDeferredScopeCalls(nextScope)))
- {
- EmitDeferredScopeCalls(true, nextScope, breakData->mIRContinueBlock);
- }
- else
- {
- mBfIRBuilder->CreateBr(breakData->mIRContinueBlock);
- }
- MarkScopeLeft(breakData->mScope);
- ValueScopeEnd(earliestValueScopeStart);
- mCurMethodState->mLeftBlockUncond = true;
- if (!mCurMethodState->mInPostReturn)
- mCurMethodState->mHadContinue = true;
- }
- void BfModule::Visit(BfFallthroughStatement* fallthroughStmt)
- {
- UpdateSrcPos(fallthroughStmt);
- BfBreakData* breakData = mCurMethodState->mBreakData;
- if (fallthroughStmt->mLabel != NULL)
- {
- breakData = FindBreakData(fallthroughStmt->mLabel);
- }
- else
- {
- while (breakData != NULL)
- {
- if (breakData->mIRFallthroughBlock)
- break;
- breakData = breakData->mPrevBreakData;
- }
- }
- if ((mCompiler->mResolvePassData != NULL) && (mCompiler->mResolvePassData->mAutoComplete != NULL))
- {
- BfScopeData* scope = NULL;
- if (breakData != NULL)
- scope = breakData->mScope;
- if (auto identifer = BfNodeDynCast<BfIdentifierNode>(fallthroughStmt->mLabel))
- mCompiler->mResolvePassData->mAutoComplete->CheckLabel(identifer, fallthroughStmt->mFallthroughToken, scope);
- }
- if (mCurMethodState->mInDeferredBlock)
- {
- auto checkScope = mCurMethodState->mCurScope;
- while (checkScope != NULL)
- {
- if (checkScope == breakData->mScope)
- break;
- if (checkScope->mIsDeferredBlock)
- {
- Fail("The fallthrough crosses a deferred block boundary", fallthroughStmt);
- return;
- }
- checkScope = checkScope->mPrevScope;
- }
- }
- if (breakData == NULL)
- {
- Fail("'fallthrough' not applicable in this block", fallthroughStmt);
- return;
- }
- EmitDeferredScopeCalls(true, breakData->mScope, breakData->mIRFallthroughBlock);
- mCurMethodState->mLeftBlockUncond = true; // Not really a return, but handled the same way
- if (mCurMethodState->mDeferredLocalAssignData != NULL)
- mCurMethodState->mDeferredLocalAssignData->mHadFallthrough = true;
- auto checkBreakData = mCurMethodState->mBreakData;
- while (true)
- {
- if (checkBreakData == breakData)
- break;
- checkBreakData->mHadBreak = true;
- checkBreakData = checkBreakData->mPrevBreakData;
- }
- }
- void BfModule::Visit(BfUsingStatement* usingStmt)
- {
- UpdateSrcPos(usingStmt);
- mCurMethodState->mInHeadScope = false;
- BfScopeData newScope;
- mCurMethodState->AddScope(&newScope);
- NewScopeState();
- if (usingStmt->mVariableDeclaration != NULL)
- UpdateSrcPos(usingStmt->mVariableDeclaration);
- BfTypedValue embeddedValue;
- SizedArray<BfIRValue, 1> llvmArgs;
- BfModuleMethodInstance moduleMethodInstance;
- BfFunctionBindResult functionBindResult;
- BfExprEvaluator exprEvaluator(this);
- bool failed = false;
- if (usingStmt->mVariableDeclaration == NULL)
- {
- AssertErrorState();
- failed = true;
- }
- else if (usingStmt->mVariableDeclaration->mNameNode != NULL)
- {
- BfLocalVariable* localVar = HandleVariableDeclaration(usingStmt->mVariableDeclaration);
- if (localVar == NULL)
- {
- AssertErrorState();
- failed = true;
- }
- else
- {
- embeddedValue = exprEvaluator.LoadLocal(localVar);
- }
- //exprEvaluator.CheckModifyResult(embeddedValue, usingStmt->mVariableDeclaration->mNameNode,);
- }
- else
- {
- embeddedValue = CreateValueFromExpression(usingStmt->mVariableDeclaration->mInitializer);
- if (!embeddedValue)
- failed = true;
- }
- if (!failed)
- {
- auto iDisposableType = ResolveTypeDef(mCompiler->mIDisposableTypeDef)->ToTypeInstance();
- auto dispMethod = GetMethodByName(iDisposableType, "Dispose");
- if ((!dispMethod) || (!CanCast(embeddedValue, iDisposableType)))
- {
- Fail(StrFormat("Type '%s' must be implicitly convertible to 'System.IDisposable' for use in 'using' statement", TypeToString(embeddedValue.mType).c_str()), usingStmt->mVariableDeclaration);
- failed = true;
- }
- else
- {
- bool mayBeNull = true;
- if (embeddedValue.mType->IsStruct())
- {
- // It's possible that a struct can convert to an IDisposable through a conversion operator that CAN
- // return null, so the only way we can know we are not null is if we are a struct that directly
- // implements the interface
- if (TypeIsSubTypeOf(embeddedValue.mType->ToTypeInstance(), iDisposableType))
- mayBeNull = false;
- }
- exprEvaluator.mFunctionBindResult = &functionBindResult;
- SizedArray<BfResolvedArg, 0> resolvedArgs;
- BfMethodMatcher methodMatcher(usingStmt->mVariableDeclaration, this, dispMethod.mMethodInstance, resolvedArgs, BfMethodGenericArguments());
- methodMatcher.CheckType(iDisposableType, embeddedValue, false);
- methodMatcher.TryDevirtualizeCall(embeddedValue);
- auto retVal = exprEvaluator.CreateCall(&methodMatcher, embeddedValue);
- if (functionBindResult.mMethodInstance != NULL)
- {
- moduleMethodInstance = BfModuleMethodInstance(functionBindResult.mMethodInstance, functionBindResult.mFunc);
- AddDeferredCall(moduleMethodInstance, functionBindResult.mIRArgs, mCurMethodState->mCurScope, NULL, false, mayBeNull);
- }
- }
- }
- if (usingStmt->mEmbeddedStatement == NULL)
- {
- AssertErrorState();
- }
- else
- {
- VisitEmbeddedStatement(usingStmt->mEmbeddedStatement);
- }
- RestoreScopeState();
- }
- void BfModule::Visit(BfDoStatement* doStmt)
- {
- UpdateSrcPos(doStmt);
- auto bodyBB = mBfIRBuilder->CreateBlock("do.body", true);
- auto endBB = mBfIRBuilder->CreateBlock("do.end");
- BfScopeData scopeData;
- if (doStmt->mLabelNode != NULL)
- scopeData.mLabelNode = doStmt->mLabelNode->mLabel;
- mCurMethodState->AddScope(&scopeData);
- NewScopeState();
- BfBreakData breakData;
- breakData.mIRBreakBlock = endBB;
- breakData.mScope = &scopeData;
- breakData.mPrevBreakData = mCurMethodState->mBreakData;
- SetAndRestoreValue<BfBreakData*> prevBreakData(mCurMethodState->mBreakData, &breakData);
- BfDeferredLocalAssignData deferredLocalAssignData(mCurMethodState->mCurScope);
- deferredLocalAssignData.ExtendFrom(mCurMethodState->mDeferredLocalAssignData, false);
- deferredLocalAssignData.mVarIdBarrier = mCurMethodState->GetRootMethodState()->mCurLocalVarId;
- SetAndRestoreValue<BfDeferredLocalAssignData*> prevDLA(mCurMethodState->mDeferredLocalAssignData, &deferredLocalAssignData);
- // We may have a call in the loop body
- mCurMethodState->mMayNeedThisAccessCheck = true;
- mBfIRBuilder->CreateBr(bodyBB);
- mBfIRBuilder->SetInsertPoint(bodyBB);
- VisitEmbeddedStatement(doStmt->mEmbeddedStatement);
- prevDLA.Restore();
- mCurMethodState->ApplyDeferredLocalAssignData(deferredLocalAssignData);
- RestoreScopeState();
- if (!mCurMethodState->mLeftBlockUncond)
- mBfIRBuilder->CreateBr(endBB);
- mCurMethodState->SetHadReturn(false);
- mCurMethodState->mLeftBlockUncond = false;
- mBfIRBuilder->AddBlock(endBB);
- mBfIRBuilder->SetInsertPoint(endBB);
- }
- void BfModule::Visit(BfRepeatStatement* repeatStmt)
- {
- // if (repeatStmt->mCondition != NULL)
- // UpdateSrcPos(repeatStmt->mCondition);
- // else
- UpdateSrcPos(repeatStmt);
- if (repeatStmt->mRepeatToken->mToken == BfToken_Do)
- {
- Fail("Repeat block requires 'repeat' token", repeatStmt->mRepeatToken);
- }
- auto bodyBB = mBfIRBuilder->CreateBlock("repeat.body", true);
- auto condBB = mBfIRBuilder->CreateBlock("repeat.cond");
- auto endBB = mBfIRBuilder->CreateBlock("repeat.end");
- BfScopeData scopeData;
- // We set mIsLoop later
- if (repeatStmt->mLabelNode != NULL)
- scopeData.mLabelNode = repeatStmt->mLabelNode->mLabel;
- mCurMethodState->AddScope(&scopeData);
- NewScopeState();
- BfBreakData breakData;
- breakData.mIRContinueBlock = condBB;
- breakData.mIRBreakBlock = endBB;
- breakData.mScope = &scopeData;
- breakData.mPrevBreakData = mCurMethodState->mBreakData;
- SetAndRestoreValue<BfBreakData*> prevBreakData(mCurMethodState->mBreakData, &breakData);
- // We may have a call in the loop body
- mCurMethodState->mMayNeedThisAccessCheck = true;
- mBfIRBuilder->CreateBr(bodyBB);
- mBfIRBuilder->SetInsertPoint(bodyBB);
- scopeData.mIsLoop = true;
- BfDeferredLocalAssignData deferredLocalAssignData(mCurMethodState->mCurScope);
- deferredLocalAssignData.ExtendFrom(mCurMethodState->mDeferredLocalAssignData, false);
- deferredLocalAssignData.mVarIdBarrier = mCurMethodState->GetRootMethodState()->mCurLocalVarId;
- SetAndRestoreValue<BfDeferredLocalAssignData*> prevDLA(mCurMethodState->mDeferredLocalAssignData, &deferredLocalAssignData);
- VisitEmbeddedStatement(repeatStmt->mEmbeddedStatement);
- if (!mCurMethodState->mLeftBlockUncond)
- mBfIRBuilder->CreateBr(condBB);
- mCurMethodState->SetHadReturn(false);
- mCurMethodState->mLeftBlockUncond = false;
- mCurMethodState->mLeftBlockCond = false;
- mBfIRBuilder->AddBlock(condBB);
- mBfIRBuilder->SetInsertPoint(condBB);
- bool isInfiniteLoop = false;
- if (repeatStmt->mCondition != NULL)
- {
- UpdateSrcPos(repeatStmt->mCondition);
- auto checkVal = CreateValueFromExpression(repeatStmt->mCondition, GetPrimitiveType(BfTypeCode_Boolean));
- if (checkVal)
- {
- if ((!breakData.mHadBreak) && (checkVal.mValue.IsConst()))
- {
- auto constVal = mBfIRBuilder->GetConstantById(checkVal.mValue.mId);
- if (constVal->mTypeCode == BfTypeCode_Boolean)
- isInfiniteLoop = constVal->mBool;
- }
- mBfIRBuilder->CreateCondBr(checkVal.mValue, bodyBB, endBB);
- mBfIRBuilder->AddBlock(endBB);
- mBfIRBuilder->SetInsertPoint(endBB);
- }
- }
- RestoreScopeState();
- prevDLA.Restore();
- mCurMethodState->ApplyDeferredLocalAssignData(deferredLocalAssignData);
- if (isInfiniteLoop)
- EmitDefaultReturn();
- }
- void BfModule::Visit(BfWhileStatement* whileStmt)
- {
- UpdateSrcPos(whileStmt);
- bool prevHadReturn = mCurMethodState->mHadReturn;
- auto condBB = mBfIRBuilder->CreateBlock("while.cond");
- auto bodyBB = mBfIRBuilder->CreateBlock("while.body");
- auto endBB = mBfIRBuilder->CreateBlock("while.end");
- mCurMethodState->mInHeadScope = false;
- BfScopeData scopeData;
- scopeData.mScopeKind = BfScopeKind_StatementTarget_Conditional;
- scopeData.mIsLoop = true;
- if (whileStmt->mLabelNode != NULL)
- scopeData.mLabelNode = whileStmt->mLabelNode->mLabel;
- scopeData.mValueScopeStart = ValueScopeStart();
- mCurMethodState->AddScope(&scopeData);
- NewScopeState();
- BfBreakData breakData;
- breakData.mIRContinueBlock = condBB;
- breakData.mIRBreakBlock = endBB;
- breakData.mScope = &scopeData;
- breakData.mPrevBreakData = mCurMethodState->mBreakData;
- breakData.mInnerValueScopeStart = scopeData.mValueScopeStart;
- SetAndRestoreValue<BfBreakData*> prevBreakData(mCurMethodState->mBreakData, &breakData);
- mBfIRBuilder->AddBlock(condBB);
- mBfIRBuilder->CreateBr(condBB);
- mBfIRBuilder->SetInsertPoint(condBB);
- BfTypedValue checkVal;
- if (whileStmt->mCondition != NULL)
- {
- UpdateSrcPos(whileStmt->mCondition);
- checkVal = CreateValueFromExpression(whileStmt->mCondition, GetPrimitiveType(BfTypeCode_Boolean));
- }
- if (!checkVal)
- {
- AssertErrorState();
- checkVal = GetDefaultTypedValue(GetPrimitiveType(BfTypeCode_Boolean));
- }
- bool isInfiniteLoop = false;
- bool isFalseLoop = false;
- if (checkVal.mValue.IsConst())
- {
- EmitEnsureInstructionAt();
- auto constVal = mBfIRBuilder->GetConstantById(checkVal.mValue.mId);
- if (constVal->mTypeCode == BfTypeCode_Boolean)
- {
- isInfiniteLoop = constVal->mBool;
- isFalseLoop = !isInfiniteLoop;
- }
- }
- // We may have a call in the loop body
- mCurMethodState->mMayNeedThisAccessCheck = true;
- // For BeefBackend we continue to do CondBr because it helps our flow analysis and we optimize it anyway
- if ((isInfiniteLoop) && (!IsTargetingBeefBackend()))
- mBfIRBuilder->CreateBr(bodyBB);
- else if (isFalseLoop)
- mBfIRBuilder->CreateBr(endBB);
- else
- mBfIRBuilder->CreateCondBr(checkVal.mValue, bodyBB, endBB);
- // Apply deferred local assign to mEmbeddedStatement and itrStmt
- BfDeferredLocalAssignData deferredLocalAssignData(mCurMethodState->mCurScope);
- deferredLocalAssignData.ExtendFrom(mCurMethodState->mDeferredLocalAssignData, false);
- deferredLocalAssignData.mVarIdBarrier = mCurMethodState->GetRootMethodState()->mCurLocalVarId;
- SetAndRestoreValue<BfDeferredLocalAssignData*> prevDLA(mCurMethodState->mDeferredLocalAssignData, &deferredLocalAssignData);
- deferredLocalAssignData.mIsUnconditional = isInfiniteLoop;
- mBfIRBuilder->AddBlock(bodyBB);
- mBfIRBuilder->SetInsertPoint(bodyBB);
- if (whileStmt->mEmbeddedStatement != NULL)
- {
- if (isFalseLoop)
- {
- SetAndRestoreValue<bool> ignoreWrites(mBfIRBuilder->mIgnoreWrites, true);
- SetAndRestoreValue<bool> prevInConstIgnore(mCurMethodState->mCurScope->mInConstIgnore, true);
- VisitEmbeddedStatement(whileStmt->mEmbeddedStatement);
- }
- else
- VisitEmbeddedStatement(whileStmt->mEmbeddedStatement);
- }
- else
- {
- AssertErrorState();
- }
- if (breakData.mHadBreak)
- {
- isInfiniteLoop = false;
- }
- if ((!mCurMethodState->mLeftBlockUncond) && (!isFalseLoop))
- {
- mBfIRBuilder->CreateBr(condBB);
- }
- if (!isInfiniteLoop)
- mCurMethodState->mHadReturn = prevHadReturn;
- mCurMethodState->mLeftBlockUncond = false;
- mCurMethodState->mLeftBlockCond = false;
- mBfIRBuilder->AddBlock(endBB);
- mBfIRBuilder->SetInsertPoint(endBB);
- if (isFalseLoop)
- {
- mBfIRBuilder->EraseFromParent(bodyBB);
- }
- RestoreScopeState();
- if ((isInfiniteLoop) && (mCurMethodInstance != NULL))
- EmitDefaultReturn();
- }
- void BfModule::Visit(BfForStatement* forStmt)
- {
- auto autoComplete = mCompiler->GetAutoComplete();
- if (autoComplete != NULL)
- autoComplete->CheckIdentifier(forStmt->mForToken, true);
- UpdateSrcPos(forStmt);
- auto startBB = mBfIRBuilder->CreateBlock("for.start", true);
- mBfIRBuilder->CreateBr(startBB);
- mBfIRBuilder->SetInsertPoint(startBB);
- BfScopeData scopeData;
- scopeData.mIsLoop = true;
- if (forStmt->mLabelNode != NULL)
- scopeData.mLabelNode = forStmt->mLabelNode->mLabel;
- scopeData.mCloseNode = forStmt;
- scopeData.mValueScopeStart = ValueScopeStart();
- mCurMethodState->AddScope(&scopeData);
- NewScopeState();
- for (auto initializer : forStmt->mInitializers)
- {
- VisitChild(initializer);
- }
- // We may have a call in the loop body
- mCurMethodState->mMayNeedThisAccessCheck = true;
- auto boolType = GetPrimitiveType(BfTypeCode_Boolean);
- auto condBB = mBfIRBuilder->CreateBlock("for.cond", true);
- auto bodyBB = mBfIRBuilder->CreateBlock("for.body");
- auto incBB = mBfIRBuilder->CreateBlock("for.inc");
- auto endBB = mBfIRBuilder->CreateBlock("for.end");
- BfBreakData breakData;
- breakData.mIRContinueBlock = incBB;
- breakData.mIRBreakBlock = endBB;
- breakData.mScope = &scopeData;
- breakData.mPrevBreakData = mCurMethodState->mBreakData;
- SetAndRestoreValue<BfBreakData*> prevBreakData(mCurMethodState->mBreakData, &breakData);
- mBfIRBuilder->CreateBr(condBB);
- bool isInfiniteLoop = false;
- mBfIRBuilder->SetInsertPoint(condBB);
- if (forStmt->mCondition != NULL)
- {
- auto conditionValue = CreateValueFromExpression(forStmt->mCondition, boolType);
- if (!conditionValue)
- conditionValue = GetDefaultTypedValue(boolType);
- auto constant = mBfIRBuilder->GetConstant(conditionValue.mValue);
- if ((constant != NULL) && (constant->mTypeCode == BfTypeCode_Boolean))
- isInfiniteLoop = constant->mBool;
- ValueScopeEnd(scopeData.mValueScopeStart);
- mBfIRBuilder->CreateCondBr(conditionValue.mValue, bodyBB, endBB);
- }
- else
- {
- isInfiniteLoop = true;
- mBfIRBuilder->CreateBr(bodyBB);
- }
- // Apply deferred local assign to mEmbeddedStatement and itrStmt
- BfDeferredLocalAssignData deferredLocalAssignData(mCurMethodState->mCurScope);
- deferredLocalAssignData.ExtendFrom(mCurMethodState->mDeferredLocalAssignData, false);
- deferredLocalAssignData.mVarIdBarrier = mCurMethodState->GetRootMethodState()->mCurLocalVarId;
- SetAndRestoreValue<BfDeferredLocalAssignData*> prevDLA(mCurMethodState->mDeferredLocalAssignData, &deferredLocalAssignData);
- mBfIRBuilder->AddBlock(bodyBB);
- mBfIRBuilder->SetInsertPoint(bodyBB);
- if (forStmt->mEmbeddedStatement != NULL)
- {
- VisitEmbeddedStatement(forStmt->mEmbeddedStatement);
- }
- if (!mCurMethodState->mLeftBlockUncond)
- mBfIRBuilder->CreateBr(incBB);
- mBfIRBuilder->AddBlock(incBB);
- mBfIRBuilder->SetInsertPoint(incBB);
- for (auto itrStmt : forStmt->mIterators)
- {
- VisitChild(itrStmt);
- if ((mCurMethodState->mLeftBlockUncond) && (!mCurMethodState->mHadContinue) && (!mCurMethodState->mInPostReturn))
- Warn(BfWarning_CS0162_UnreachableCode, "Unreachable code", itrStmt);
- }
- ValueScopeEnd(scopeData.mValueScopeStart);
- mBfIRBuilder->CreateBr(condBB);
- mBfIRBuilder->AddBlock(endBB);
- mBfIRBuilder->SetInsertPoint(endBB);
- // The 'return' may have been inside the block, which may not have been entered if preconditions were not met
- mCurMethodState->SetHadReturn(false);
- mCurMethodState->mLeftBlockUncond = false;
- mCurMethodState->mLeftBlockCond = false;
- if (breakData.mHadBreak)
- isInfiniteLoop = false;
- RestoreScopeState();
- if (isInfiniteLoop)
- EmitDefaultReturn();
- }
- void BfModule::DoForLess(BfForEachStatement* forEachStmt)
- {
- UpdateSrcPos(forEachStmt);
- auto startBB = mBfIRBuilder->GetInsertBlock();
- auto condBB = mBfIRBuilder->CreateBlock("forless.cond", true);
- mBfIRBuilder->SetInsertPoint(condBB);
- BfScopeData scopeData;
- // We set mIsLoop later
- if (forEachStmt->mLabelNode != NULL)
- scopeData.mLabelNode = forEachStmt->mLabelNode->mLabel;
- mCurMethodState->AddScope(&scopeData);
- NewScopeState();
- auto autoComplete = mCompiler->GetAutoComplete();
- auto isLet = BfNodeDynCast<BfLetTypeReference>(forEachStmt->mVariableTypeRef) != 0;
- auto isVar = BfNodeDynCast<BfVarTypeReference>(forEachStmt->mVariableTypeRef) != 0;
- BfTypedValue target;
- BfType* varType = NULL;
- bool didInference = false;
- if (isLet || isVar)
- {
- if (forEachStmt->mCollectionExpression != NULL)
- target = CreateValueFromExpression(forEachStmt->mCollectionExpression);
- if (target)
- {
- FixIntUnknown(target);
- varType = target.mType;
- }
- if (autoComplete != NULL)
- autoComplete->CheckVarResolution(forEachStmt->mVariableTypeRef, varType);
- didInference = true;
- }
- else
- {
- varType = ResolveTypeRef(forEachStmt->mVariableTypeRef, BfPopulateType_Data, BfResolveTypeRefFlag_AllowRef);
- if (forEachStmt->mCollectionExpression != NULL)
- target = CreateValueFromExpression(forEachStmt->mCollectionExpression, varType);
- }
- if (varType == NULL)
- varType = GetPrimitiveType(BfTypeCode_IntPtr);
- BfDeferredLocalAssignData deferredLocalAssignData(mCurMethodState->mCurScope);
- deferredLocalAssignData.mIsIfCondition = true;
- deferredLocalAssignData.ExtendFrom(mCurMethodState->mDeferredLocalAssignData, true);
- deferredLocalAssignData.mVarIdBarrier = mCurMethodState->GetRootMethodState()->mCurLocalVarId;
- SetAndRestoreValue<BfDeferredLocalAssignData*> prevDLA(mCurMethodState->mDeferredLocalAssignData, &deferredLocalAssignData);
- deferredLocalAssignData.mIsIfCondition = false;
- // The "extend chain" is only valid for the conditional -- since that expression may contain unconditionally executed and
- // conditionally executed code (in the case of "(GetVal(out a) && GetVal(out b))" for example
- mCurMethodState->mDeferredLocalAssignData->BreakExtendChain();
- BfType* checkType = varType;
- if (checkType->IsTypedPrimitive())
- checkType = checkType->GetUnderlyingType();
- if (!checkType->IsIntegral())
- {
- Fail(StrFormat("Cannot iterate over '%s' in for-less statements, only integer types are allowed", TypeToString(varType).c_str()), forEachStmt->mVariableTypeRef);
- varType = GetPrimitiveType(BfTypeCode_IntPtr);
- if (didInference)
- target = GetDefaultTypedValue(varType);
- }
- PopulateType(varType, BfPopulateType_Data);
- auto condEndBB = mBfIRBuilder->GetInsertBlock();
- mBfIRBuilder->SetInsertPoint(startBB);
- BfLocalVariable* localDef = new BfLocalVariable();
- localDef->mNameNode = BfNodeDynCast<BfIdentifierNode>(forEachStmt->mVariableName);
- localDef->mName = localDef->mNameNode->ToString();
- localDef->mResolvedType = varType;
- BfIRValue varInst;
- if (!varType->IsValuelessType())
- {
- varInst = CreateAlloca(varType);
- }
- localDef->mAddr = varInst;
- localDef->mAssignedKind = BfLocalVarAssignKind_Unconditional;
- localDef->mReadFromId = 0;
- localDef->mIsReadOnly = isLet || (forEachStmt->mReadOnlyToken != NULL);
- CheckVariableDef(localDef);
- mBfIRBuilder->CreateAlignedStore(GetDefaultValue(varType), localDef->mAddr, varType->mAlign);
- localDef->Init();
- UpdateExprSrcPos(forEachStmt->mVariableName);
- AddLocalVariableDef(localDef, true);
- auto bodyBB = mBfIRBuilder->CreateBlock("forless.body");
- auto incBB = mBfIRBuilder->CreateBlock("forless.inc");
- auto endBB = mBfIRBuilder->CreateBlock("forless.end");
- BfBreakData breakData;
- breakData.mIRContinueBlock = incBB;
- breakData.mIRBreakBlock = endBB;
- breakData.mScope = &scopeData;
- breakData.mPrevBreakData = mCurMethodState->mBreakData;
- SetAndRestoreValue<BfBreakData*> prevBreakData(mCurMethodState->mBreakData, &breakData);
- mBfIRBuilder->CreateBr(condBB);
- mBfIRBuilder->SetInsertPoint(condEndBB);
- if (forEachStmt->mCollectionExpression != NULL)
- UpdateExprSrcPos(forEachStmt->mCollectionExpression);
- BfIRValue conditionValue;
- // We may have a call in the loop body
- mCurMethodState->mMayNeedThisAccessCheck = true;
- // Cond
- auto valueScopeStart = ValueScopeStart();
- auto localVal = mBfIRBuilder->CreateAlignedLoad(localDef->mAddr, localDef->mResolvedType->mAlign);
- if (!target)
- {
- // Soldier on
- target = GetDefaultTypedValue(varType);
- }
-
- if (!target.mValue.IsFake())
- {
- if (forEachStmt->mInToken->mToken == BfToken_LessEquals)
- conditionValue = mBfIRBuilder->CreateCmpLTE(localVal, target.mValue, varType->IsSigned());
- else
- conditionValue = mBfIRBuilder->CreateCmpLT(localVal, target.mValue, varType->IsSigned());
- mBfIRBuilder->CreateCondBr(conditionValue, bodyBB, endBB);
- }
- ValueScopeEnd(valueScopeStart);
- mBfIRBuilder->AddBlock(bodyBB);
- mBfIRBuilder->SetInsertPoint(bodyBB);
- // Body
- scopeData.mIsLoop = true;
- if (forEachStmt->mEmbeddedStatement != NULL)
- {
- VisitEmbeddedStatement(forEachStmt->mEmbeddedStatement);
- }
- // Inc
- if (!mCurMethodState->mLeftBlockUncond)
- {
- mBfIRBuilder->CreateBr(incBB);
- }
- mBfIRBuilder->AddBlock(incBB);
- mBfIRBuilder->SetInsertPoint(incBB);
- if (forEachStmt->mCollectionExpression != NULL)
- UpdateExprSrcPos(forEachStmt->mCollectionExpression);
- auto one = GetConstValue(1, localDef->mResolvedType);
- // We have to reload localVal before the inc, user logic could have changed it
- localVal = mBfIRBuilder->CreateAlignedLoad(localDef->mAddr, localDef->mResolvedType->mAlign);
- auto result = mBfIRBuilder->CreateAdd(localVal, one);
- mBfIRBuilder->CreateAlignedStore(result, localDef->mAddr, localDef->mResolvedType->mAlign);
- ValueScopeEnd(valueScopeStart);
- mBfIRBuilder->CreateBr(condBB);
- mBfIRBuilder->AddBlock(endBB);
- mBfIRBuilder->SetInsertPoint(endBB);
- // The 'return' may have been inside the block, which may not have been entered if preconditions were not met
- mCurMethodState->SetHadReturn(false);
- mCurMethodState->mLeftBlockUncond = false;
- mCurMethodState->mLeftBlockCond = false;
- bool definitelyExecuted = false;
- if (target.mValue.IsConst())
- {
- auto constant = mBfIRBuilder->GetConstant(target.mValue);
- if (constant->mInt32 > 0)
- definitelyExecuted = true;
- }
- prevDLA.Restore();
- if (definitelyExecuted)
- mCurMethodState->ApplyDeferredLocalAssignData(deferredLocalAssignData);
- RestoreScopeState();
- }
- void BfModule::Visit(BfForEachStatement* forEachStmt)
- {
- if ((forEachStmt->mInToken != NULL) &&
- ((forEachStmt->mInToken->GetToken() == BfToken_LChevron) || (forEachStmt->mInToken->GetToken() == BfToken_LessEquals)))
- {
- DoForLess(forEachStmt);
- return;
- }
- auto autoComplete = mCompiler->GetAutoComplete();
- UpdateSrcPos(forEachStmt);
- BfScopeData scopeData;
- // We set mIsLoop after the non-looped initializations
- scopeData.mValueScopeStart = ValueScopeStart();
- mCurMethodState->AddScope(&scopeData);
- NewScopeState();
- bool isRefExpression = false;
- BfExpression* collectionExpr = forEachStmt->mCollectionExpression;
- if (auto unaryOpExpr = BfNodeDynCast<BfUnaryOperatorExpression>(collectionExpr))
- {
- if ((unaryOpExpr->mOp == BfUnaryOp_Ref) || (unaryOpExpr->mOp == BfUnaryOp_Mut))
- {
- isRefExpression = true;
- collectionExpr = unaryOpExpr->mExpression;
- }
- }
- BfTypedValue target;
- if (collectionExpr != NULL)
- target = CreateValueFromExpression(collectionExpr);
- if (!target)
- {
- // Soldier on
- target = BfTypedValue(GetDefaultValue(mContext->mBfObjectType), mContext->mBfObjectType);
- }
- bool isLet = (forEachStmt->mVariableTypeRef != NULL) && (forEachStmt->mVariableTypeRef->IsA<BfLetTypeReference>());
- BfType* varType = NULL;
- bool inferVarType = false;
- if ((forEachStmt->mVariableTypeRef == NULL) || (forEachStmt->mVariableTypeRef->IsA<BfVarTypeReference>()) || (isLet))
- {
- if (target.mType->IsSizedArray())
- {
- varType = target.mType->GetUnderlyingType();
- if (isRefExpression)
- varType = CreateRefType(varType);
- }
- else if (target.mType->IsArray())
- {
- varType = target.mType->GetUnderlyingType();
- if (isRefExpression)
- varType = CreateRefType(varType);
- }
- else
- inferVarType = true;
- }
- else
- {
- if (autoComplete != NULL)
- autoComplete->CheckTypeRef(forEachStmt->mVariableTypeRef, false);
- varType = ResolveTypeRef(forEachStmt->mVariableTypeRef, BfPopulateType_Data, BfResolveTypeRefFlag_AllowRef);
- }
- if (varType == NULL)
- varType = GetPrimitiveType(BfTypeCode_Var);
- bool isArray = target.mType->IsArray();
- bool isSizedArray = target.mType->IsSizedArray();
- bool isVarEnumerator = target.mType->IsVar();
- // Array
- BfType* itrType;
- BfTypedValue itr;
- BfTypeInstance* itrInterface = NULL;
- BfTypeInstance* refItrInterface = NULL;
- if (isVarEnumerator)
- varType = GetPrimitiveType(BfTypeCode_Var);
- BfGenericParamInstance* genericParamInst = NULL;
- if (target.mType->IsGenericParam())
- {
- genericParamInst = GetGenericParamInstance((BfGenericParamType*)target.mType);
- if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_Var) != 0)
- {
- varType = GetPrimitiveType(BfTypeCode_Var);
- isVarEnumerator = true;
- }
- if (genericParamInst->mTypeConstraint != NULL)
- {
- if (genericParamInst->mTypeConstraint->IsVar())
- {
- varType = GetPrimitiveType(BfTypeCode_Var);
- isVarEnumerator = true;
- }
- if (genericParamInst->mTypeConstraint->IsGenericTypeInstance())
- {
- auto genericConstraintType = (BfTypeInstance*)genericParamInst->mTypeConstraint;
- if (genericConstraintType->IsInstanceOf(mCompiler->mSizedArrayTypeDef))
- {
- varType = genericConstraintType->mGenericTypeInfo->mTypeGenericArguments[0];
- isVarEnumerator = true;
- }
- }
- }
- }
- if (target.mType->IsConcreteInterfaceType())
- target.mType = target.mType->GetUnderlyingType();
- if (isArray || isSizedArray)
- {
- itrType = GetPrimitiveType(BfTypeCode_IntPtr);
- BfIRValue itrInst = CreateAlloca(itrType);
- itr = BfTypedValue(itrInst, itrType, true);
- }
- else if (isVarEnumerator)
- {
- // Generic method or mixin decl
- }
- else if ((!target.mType->IsTypeInstance()) && (genericParamInst == NULL))
- {
- Fail(StrFormat("Type '%s' cannot be used in enumeration", TypeToString(target.mType).c_str()), forEachStmt->mCollectionExpression);
- }
- else if (forEachStmt->mCollectionExpression != NULL)
- {
- auto targetTypeInstance = target.mType->ToTypeInstance();
- itr = target;
- bool hadGetEnumeratorType = false;
- if (genericParamInst != NULL)
- {
- for (auto ifaceConstraint : genericParamInst->mInterfaceConstraints)
- {
- if (ifaceConstraint->IsInstanceOf(mCompiler->mGenericIEnumerableTypeDef))
- {
- if (targetTypeInstance != NULL)
- {
- targetTypeInstance = NULL;
- break;
- }
- targetTypeInstance = ifaceConstraint->ToTypeInstance();
- }
- }
- }
- if (targetTypeInstance != NULL)
- {
- PopulateType(targetTypeInstance, BfPopulateType_DataAndMethods);
- auto getEnumeratorMethod = GetMethodByName(targetTypeInstance, "GetEnumerator", 0, true);
- if (!getEnumeratorMethod)
- {
- hadGetEnumeratorType = false;
- }
- else if (getEnumeratorMethod.mMethodInstance->mMethodDef->mIsStatic)
- {
- hadGetEnumeratorType = true;
- Fail(StrFormat("Type '%s' does not contain a non-static 'GetEnumerator' method", TypeToString(targetTypeInstance).c_str()), forEachStmt->mCollectionExpression);
- }
- else
- {
- if (getEnumeratorMethod.mMethodInstance->mMethodDef->mIsConcrete)
- {
- hadGetEnumeratorType = true;
- if (genericParamInst != NULL)
- {
- if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_Concrete) == 0)
- Fail(StrFormat("Iteration requires a concrete implementation of '%s', consider adding 'concrete' constraint to '%s'", TypeToString(targetTypeInstance).c_str(), genericParamInst->GetName().c_str()), forEachStmt->mCollectionExpression);
- }
- else
- Fail(StrFormat("Iteration requires a concrete implementation of '%s'", TypeToString(targetTypeInstance).c_str()), forEachStmt->mCollectionExpression);
- }
- hadGetEnumeratorType = true;
- BfExprEvaluator exprEvaluator(this);
- SizedArray<BfIRValue, 1> args;
- auto castedTarget = Cast(forEachStmt->mCollectionExpression, target, getEnumeratorMethod.mMethodInstance->GetOwner());
- exprEvaluator.PushThis(forEachStmt->mCollectionExpression, castedTarget, getEnumeratorMethod.mMethodInstance, args);
- itr = exprEvaluator.CreateCall(forEachStmt->mCollectionExpression, getEnumeratorMethod.mMethodInstance, IsSkippingExtraResolveChecks() ? BfIRValue() : getEnumeratorMethod.mFunc, false, args);
- if (itr.mType->IsConcreteInterfaceType())
- itr.mType = itr.mType->GetUnderlyingType();
- }
- }
- if (itr)
- {
- PopulateType(itr.mType, BfPopulateType_DataAndMethods);
- BfTypeInstance* genericItrInterface = NULL;
- auto _CheckInterface = [&](BfTypeInstance* interface)
- {
- if (interface->IsInstanceOf(isRefExpression ? mCompiler->mGenericIRefEnumeratorTypeDef : mCompiler->mGenericIEnumeratorTypeDef))
- {
- if (genericItrInterface != NULL)
- {
- Fail(StrFormat("Type '%s' implements multiple %s<T> interfaces", TypeToString(itr.mType).c_str(), isRefExpression ? "IRefEnumerator" : "IEnumerator"), forEachStmt->mCollectionExpression);
- }
- itrInterface = interface;
- genericItrInterface = itrInterface->ToGenericTypeInstance();
- if (inferVarType)
- {
- varType = genericItrInterface->mGenericTypeInfo->mTypeGenericArguments[0];
- if (isRefExpression)
- {
- if (varType->IsPointer())
- varType = CreateRefType(varType->GetUnderlyingType());
- }
- }
- }
- };
- auto enumeratorTypeInst = itr.mType->ToTypeInstance();
- while (enumeratorTypeInst != NULL)
- {
- PopulateType(enumeratorTypeInst, Beefy::BfPopulateType_Interfaces_All);
- for (auto& interfaceRef : enumeratorTypeInst->mInterfaces)
- {
- BfTypeInstance* interface = interfaceRef.mInterfaceType;
- _CheckInterface(interface);
- }
- if (enumeratorTypeInst->IsInstanceOf(isRefExpression ? mCompiler->mGenericIRefEnumeratorTypeDef : mCompiler->mGenericIEnumeratorTypeDef))
- {
- itrInterface = enumeratorTypeInst;
- genericItrInterface = itrInterface->ToGenericTypeInstance();
- if (inferVarType)
- {
- varType = genericItrInterface->mGenericTypeInfo->mTypeGenericArguments[0];
- if (isRefExpression)
- {
- if (varType->IsPointer())
- varType = CreateRefType(varType);
- }
- }
- break;
- }
- if (itrInterface != NULL)
- break;
- enumeratorTypeInst = enumeratorTypeInst->mBaseType;
- }
- if ((genericItrInterface == NULL) && (genericParamInst != NULL))
- {
- for (auto interface : genericParamInst->mInterfaceConstraints)
- _CheckInterface(interface);
- }
- if (genericItrInterface == NULL)
- {
- if (!hadGetEnumeratorType)
- {
- Fail(StrFormat("Type '%s' must contain a 'GetEnumerator' method or implement an IEnumerator<T> interface", TypeToString(target.mType).c_str()), forEachStmt->mCollectionExpression);
- }
- else
- Fail(StrFormat("Enumerator type '%s' must implement an %s<T> interface", TypeToString(itr.mType).c_str(), isRefExpression ? "IRefEnumerator" : "IEnumerator"), forEachStmt->mCollectionExpression);
- itrInterface = NULL;
- itr = BfTypedValue();
- }
- else
- {
- itrInterface = genericItrInterface;
- if (isRefExpression)
- {
- refItrInterface = itrInterface;
- PopulateType(refItrInterface);
- // Must IRefEnumeratorf<T> must include only IEnumerator<T>
- // BF_ASSERT(refItrInterface->mInterfaces.size() == 1);
- // if (refItrInterface->mInterfaces.size() == 1)
- // itrInterface = refItrInterface->mInterfaces[0].mInterfaceType;
- }
- itr = MakeAddressable(itr);
- itr = RemoveReadOnly(itr);
- }
- }
- }
- else
- {
- AssertErrorState();
- }
- PopulateType(varType, BfPopulateType_Data);
- // Apply deferred local assign to mEmbeddedStatement and itrStmt
- BfDeferredLocalAssignData deferredLocalAssignData(mCurMethodState->mCurScope);
- deferredLocalAssignData.ExtendFrom(mCurMethodState->mDeferredLocalAssignData, false);
- deferredLocalAssignData.mVarIdBarrier = mCurMethodState->GetRootMethodState()->mCurLocalVarId;
- SetAndRestoreValue<BfDeferredLocalAssignData*> prevDLA(mCurMethodState->mDeferredLocalAssignData, &deferredLocalAssignData);
- SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites);
- if ((target.mType->IsSizedArray()) && (((BfSizedArrayType*)target.mType)->mElementCount == 0))
- {
- EmitEnsureInstructionAt();
- mBfIRBuilder->mIgnoreWrites = true;
- }
- BfIdentifierNode* nameNode = NULL;
- String variableName;
- struct _TupleBind
- {
- BfIdentifierNode* mNameNode;
- String mName;
- BfType* mType;
- BfLocalVariable* mVariable;
- };
- Array<_TupleBind> tupleBinds;
- if (forEachStmt->mVariableName != NULL)
- {
- if (auto tupleExpr = BfNodeDynCast<BfTupleExpression>(forEachStmt->mVariableName))
- {
- CheckTupleVariableDeclaration(tupleExpr, varType);
- if (varType->IsTuple())
- {
- auto tupleType = (BfTypeInstance*)varType;
- for (int idx = 0; idx < BF_MIN((int)tupleExpr->mValues.size(), (int)tupleType->mFieldInstances.size()); idx++)
- {
- auto nameNode = tupleExpr->mValues[idx];
- _TupleBind tupleBind;
- tupleBind.mNameNode = BfNodeDynCast<BfIdentifierNode>(nameNode);
- if ((tupleBind.mNameNode == NULL) && (nameNode != NULL))
- {
- Fail("Variable name expected", nameNode);
- }
- tupleBind.mName = nameNode->ToString();
- tupleBind.mType = tupleType->mFieldInstances[idx].mResolvedType;
- tupleBind.mVariable = NULL;
- tupleBinds.Add(tupleBind);
- if (idx == 0)
- variableName = tupleBind.mName;
- }
- }
- }
- else
- {
- nameNode = BfNodeDynCast<BfIdentifierNode>(forEachStmt->mVariableName);
- if (nameNode != NULL)
- variableName = nameNode->ToString();
- }
- }
- if (variableName.IsEmpty())
- variableName = "_";
- BfModuleMethodInstance getNextMethodInst;
- BfType* nextEmbeddedType = NULL;
- BfTypedValue nextResult;
- if ((refItrInterface) || (itrInterface))
- {
- if (isRefExpression)
- {
- PopulateType(refItrInterface, BfPopulateType_Full_Force);
- getNextMethodInst = GetMethodByName(refItrInterface, "GetNextRef");
- }
- else
- {
- PopulateType(itrInterface, BfPopulateType_Full_Force);
- getNextMethodInst = GetMethodByName(itrInterface, "GetNext");
- }
- if (getNextMethodInst)
- {
- nextResult = BfTypedValue(CreateAlloca(getNextMethodInst.mMethodInstance->mReturnType), getNextMethodInst.mMethodInstance->mReturnType, true);
- if (nextResult.mType->IsGenericTypeInstance())
- {
- nextEmbeddedType = ((BfTypeInstance*)nextResult.mType)->mGenericTypeInfo->mTypeGenericArguments[0];
- }
- }
- else
- {
- InternalError("Failed to find GetNext");
- }
- }
- if (nextEmbeddedType == NULL)
- nextEmbeddedType = GetPrimitiveType(BfTypeCode_Var);
- BfLocalVariable* itrLocalDef = NULL;
- // Iterator local def
- if (itr)
- {
- BfLocalVariable* localDef = new BfLocalVariable();
- itrLocalDef = localDef;
- localDef->mNameNode = nameNode;
- localDef->mName = variableName;
- localDef->mResolvedType = itr.mType;
- localDef->mAddr = itr.mValue;
- localDef->mAssignedKind = BfLocalVarAssignKind_Unconditional;
- localDef->mReadFromId = 0;
- localDef->Init();
- UpdateSrcPos(forEachStmt);
- CheckVariableDef(localDef);
- AddLocalVariableDef(localDef, true);
- }
- BfIRValue varInst;
- BfTypedValue varTypedVal;
- bool needsValCopy = true;
- BfType* origVarType = varType;
- // Local variable
- {
- if (!tupleBinds.IsEmpty())
- {
- BF_ASSERT(varType->IsTuple());
- auto tupleType = (BfTypeInstance*)varType;
- // Tuple binds
- needsValCopy = false;
- if (!nextResult)
- {
- varInst = CreateAlloca(varType);
- varTypedVal = BfTypedValue(varInst, varType, true);
- }
- // Local
- for (int idx = 0; idx < (int)tupleBinds.size(); idx++)
- {
- auto& tupleBind = tupleBinds[idx];
- BfLocalVariable* localDef = new BfLocalVariable();
- localDef->mNameNode = tupleBind.mNameNode;
- localDef->mName = tupleBind.mName;
- localDef->mResolvedType = tupleBind.mType;
- if (!needsValCopy)
- localDef->mResolvedType = CreateRefType(localDef->mResolvedType);
- localDef->mAddr = CreateAlloca(localDef->mResolvedType);
- localDef->mAssignedKind = BfLocalVarAssignKind_Unconditional;
- localDef->mReadFromId = 0;
- if ((isLet) || (forEachStmt->mReadOnlyToken != NULL))
- localDef->mIsReadOnly = true;
- localDef->Init();
- auto fieldInstance = &tupleType->mFieldInstances[idx];
- if (fieldInstance->mDataIdx >= 0)
- {
- auto tuplePtrType = CreatePointerType(varType);
- BfIRValue tuplePtr;
- if (nextResult)
- tuplePtr = mBfIRBuilder->CreateBitCast(nextResult.mValue, mBfIRBuilder->MapType(tuplePtrType));
- else
- tuplePtr = mBfIRBuilder->CreateBitCast(varInst, mBfIRBuilder->MapType(tuplePtrType));
- auto valAddr = mBfIRBuilder->CreateInBoundsGEP(tuplePtr, 0, fieldInstance->mDataIdx);
- mBfIRBuilder->CreateAlignedStore(valAddr, localDef->mAddr, localDef->mResolvedType->mAlign);
- }
- UpdateSrcPos(forEachStmt);
- if ((itrLocalDef != NULL) && (idx == 0))
- {
- localDef->mLocalVarId = itrLocalDef->mLocalVarId;
- localDef->mIsShadow = true;
- }
- else
- {
- CheckVariableDef(localDef);
- }
- AddLocalVariableDef(localDef, true, false, BfIRValue(), BfIRInitType_NotNeeded_AliveOnDecl);
- }
- }
- else
- {
- // Normal case
- if ((nextResult) && (varType->IsComposite()) && (!varType->IsValuelessType()) && (!isRefExpression))
- {
- needsValCopy = false;
- varType = CreateRefType(varType);
- }
- // Local
- BfLocalVariable* localDef = new BfLocalVariable();
- localDef->mNameNode = nameNode;
- localDef->mName = variableName;
- localDef->mResolvedType = varType;
- if (!varType->IsValuelessType())
- varInst = CreateAlloca(varType);
- else
- varInst = mBfIRBuilder->GetFakeVal();
- localDef->mAddr = varInst;
- localDef->mAssignedKind = BfLocalVarAssignKind_Unconditional;
- localDef->mReadFromId = 0;
- if ((isLet) || (forEachStmt->mReadOnlyToken != NULL))
- localDef->mIsReadOnly = true;
- localDef->Init();
- if (!needsValCopy)
- {
- auto valAddr = mBfIRBuilder->CreateBitCast(nextResult.mValue, mBfIRBuilder->MapType(varType));
- mBfIRBuilder->CreateAlignedStore(valAddr, varInst, varType->mAlign);
- }
- UpdateSrcPos(forEachStmt);
- if (itrLocalDef != NULL)
- {
- localDef->mLocalVarId = itrLocalDef->mLocalVarId;
- localDef->mIsShadow = true;
- }
- else
- {
- CheckVariableDef(localDef);
- }
- AddLocalVariableDef(localDef, true, false, BfIRValue(), BfIRInitType_NotNeeded_AliveOnDecl);
- varTypedVal = BfTypedValue(varInst, varType, true);
- }
- }
- // Iterator
- if (itr)
- {
- if ((!isArray) && (!isSizedArray))
- {
- BfFunctionBindResult functionBindResult;
- BfExprEvaluator exprEvaluator(this);
- exprEvaluator.mFunctionBindResult = &functionBindResult;
- // Allow for "Dispose" not to exist
- SetAndRestoreValue<bool> prevIgnoreErrors(mIgnoreErrors, true);
- BfResolvedArgs resolvedArgs;
- exprEvaluator.mBfEvalExprFlags = (BfEvalExprFlags)(exprEvaluator.mBfEvalExprFlags | BfEvalExprFlags_NoAutoComplete);
- exprEvaluator.MatchMethod(forEachStmt->mCollectionExpression, NULL, itr, false, false, "Dispose", resolvedArgs, BfMethodGenericArguments());
- if (functionBindResult.mMethodInstance != NULL)
- {
- BfModuleMethodInstance moduleMethodInstance;
- moduleMethodInstance = BfModuleMethodInstance(functionBindResult.mMethodInstance, functionBindResult.mFunc);
- AddDeferredCall(moduleMethodInstance, functionBindResult.mIRArgs, mCurMethodState->mCurScope);
- }
- }
- }
- BfScopeData innerScopeData;
- if (forEachStmt->mLabelNode != NULL)
- innerScopeData.mLabelNode = forEachStmt->mLabelNode->mLabel;
- innerScopeData.mValueScopeStart = ValueScopeStart();
- mCurMethodState->AddScope(&innerScopeData);
- NewScopeState(true, false);
- innerScopeData.mIsLoop = true;
- if ((autoComplete != NULL) && (forEachStmt->mVariableTypeRef != NULL))
- autoComplete->CheckVarResolution(forEachStmt->mVariableTypeRef, origVarType);
- if (isArray || isSizedArray)
- mBfIRBuilder->CreateAlignedStore(GetConstValue(0), itr.mValue, itr.mType->mAlign);
- auto valueScopeStartInner = ValueScopeStart();
- // We may have a call in the loop body
- mCurMethodState->mMayNeedThisAccessCheck = true;
- auto condBB = mBfIRBuilder->CreateBlock("foreach.cond", true);
- auto bodyBB = mBfIRBuilder->CreateBlock("foreach.body");
- auto incBB = mBfIRBuilder->CreateBlock("foreach.inc");
- auto endBB = mBfIRBuilder->CreateBlock("foreach.end");
- BfBreakData breakData;
- breakData.mIRContinueBlock = incBB;
- breakData.mIRBreakBlock = endBB;
- breakData.mScope = &innerScopeData;
- breakData.mInnerValueScopeStart = valueScopeStartInner;
- breakData.mPrevBreakData = mCurMethodState->mBreakData;
- SetAndRestoreValue<BfBreakData*> prevBreakData(mCurMethodState->mBreakData, &breakData);
- mBfIRBuilder->CreateBr(condBB);
- mBfIRBuilder->SetInsertPoint(condBB);
- if (forEachStmt->mCollectionExpression != NULL)
- UpdateExprSrcPos(forEachStmt->mCollectionExpression);
- BfIRValue conditionValue;
- if (isSizedArray) // if (i < lengthof(array)
- {
- auto itrVal = mBfIRBuilder->CreateLoad(itr.mValue);
- auto arrayType = (BfSizedArrayType*)target.mType;
- PopulateType(arrayType, BfPopulateType_DataAndMethods);
- BfIRValue lengthVal = GetConstValue(arrayType->mElementCount);
- conditionValue = mBfIRBuilder->CreateCmpLT(itrVal, lengthVal, true);
- mBfIRBuilder->CreateCondBr(conditionValue, bodyBB, endBB);
- ValueScopeEnd(valueScopeStartInner);
- }
- else if (isArray) // if (i < array.mLength)
- {
- auto itrVal = mBfIRBuilder->CreateAlignedLoad(itr.mValue, itr.mType->mAlign);
- auto arrayType = (BfArrayType*)target.mType;
- PopulateType(arrayType);
- auto arrayBaseValue = mBfIRBuilder->CreateBitCast(target.mValue, mBfIRBuilder->MapType(arrayType->mBaseType, BfIRPopulateType_Full));
- int getLengthBitCount = arrayType->GetLengthBitCount();
- BfIRValue lengthVal;
- if (arrayType->mBaseType->mTypeFailed)
- {
- AssertErrorState();
- if (getLengthBitCount == 64)
- lengthVal = GetConstValue64(0);
- else
- lengthVal = GetConstValue32(0);
- }
- else
- {
- auto fieldInst = GetFieldInstance(arrayType->mBaseType, 0, "mLength");
- if (fieldInst != NULL)
- {
- auto lengthValAddr = mBfIRBuilder->CreateInBoundsGEP(arrayBaseValue, 0, fieldInst->mDataIdx);
- lengthVal = mBfIRBuilder->CreateAlignedLoad(lengthValAddr, fieldInst->mResolvedType->mAlign);
- }
- }
- lengthVal = mBfIRBuilder->CreateNumericCast(lengthVal, true, BfTypeCode_IntPtr);
- conditionValue = mBfIRBuilder->CreateCmpLT(itrVal, lengthVal, true);
- mBfIRBuilder->CreateCondBr(conditionValue, bodyBB, endBB);
- ValueScopeEnd(valueScopeStartInner);
- }
- else // if (itr.MoveNext())
- {
- if (!itr)
- {
- if (!isVarEnumerator)
- AssertErrorState();
- mBfIRBuilder->CreateBr(endBB);
- }
- else if (!getNextMethodInst)
- {
- AssertErrorState();
- mBfIRBuilder->CreateBr(endBB);
- }
- else
- {
- BfExprEvaluator exprEvaluator(this);
- auto itrTypeInstance = itr.mType->ToTypeInstance();
- SizedArray<BfResolvedArg, 0> resolvedArgs;
- BfMethodMatcher methodMatcher(forEachStmt->mCollectionExpression, this, getNextMethodInst.mMethodInstance, resolvedArgs, BfMethodGenericArguments());
- if (isRefExpression)
- methodMatcher.CheckType(refItrInterface, itr, false);
- else
- methodMatcher.CheckType(itrInterface, itr, false);
- methodMatcher.TryDevirtualizeCall(itr);
- exprEvaluator.mReceivingValue = &nextResult;
- auto retVal = exprEvaluator.CreateCall(&methodMatcher, itr);
- if (exprEvaluator.mReceivingValue != NULL)
- {
- if (mIsComptimeModule)
- {
- retVal = LoadValue(retVal);
- mBfIRBuilder->CreateStore(retVal.mValue, nextResult.mValue);
- }
- else
- AssertErrorState();
- }
- if ((retVal) && (!retVal.mType->IsVar()))
- {
- auto i8Result = ExtractValue(nextResult, NULL, 2);
- i8Result = LoadValue(i8Result);
- BF_ASSERT(i8Result.mType == GetPrimitiveType(BfTypeCode_Int8));
- conditionValue = mBfIRBuilder->CreateCmpEQ(i8Result.mValue, GetConstValue8(0));
- }
- else
- conditionValue = GetDefaultValue(GetPrimitiveType(BfTypeCode_Boolean));
- mBfIRBuilder->CreateCondBr(conditionValue, bodyBB, endBB);
- ValueScopeEnd(valueScopeStartInner);
- }
- }
- mBfIRBuilder->AddBlock(bodyBB);
- mBfIRBuilder->SetInsertPoint(bodyBB);
- if (!varTypedVal)
- {
- // Nothing to do...
- }
- else if (isSizedArray) // val = array[i]
- {
- auto itrVal = mBfIRBuilder->CreateLoad(itr.mValue);
- auto arrayType = (BfSizedArrayType*)target.mType;
- BfType* ptrType = CreatePointerType(arrayType->mElementType);
- BfTypedValue arrayItem;
- if (arrayType->mElementType->IsValuelessType())
- {
- arrayItem = GetDefaultTypedValue(arrayType->mElementType);
- }
- else
- {
- target = MakeAddressable(target);
- arrayItem = BfTypedValue(CreateIndexedValue(arrayType->mElementType, target.mValue, itrVal, true), arrayType->mElementType, true);
- if (isRefExpression)
- arrayItem = BfTypedValue(arrayItem.mValue, CreateRefType(arrayItem.mType));
- }
- arrayItem = Cast(forEachStmt->mCollectionExpression, arrayItem, varType, BfCastFlags_Explicit);
- if ((arrayItem) && (!arrayItem.mValue.IsFake()))
- {
- arrayItem = LoadValue(arrayItem);
- if (arrayItem)
- mBfIRBuilder->CreateStore(arrayItem.mValue, varInst);
- }
- }
- else if (isArray) // val = array[i]
- {
- auto itrVal = mBfIRBuilder->CreateLoad(itr.mValue);
- BfTypedValueExpression typedValueExpr;
- typedValueExpr.Init(BfTypedValue(itrVal, itrType));
- BfExprEvaluator exprEvaluator(this);
- SizedArray<BfExpression*, 1> indices;
- indices.push_back(&typedValueExpr);
- BfSizedArray<BfExpression*> sizedArgExprs(indices);
- BfResolvedArgs argValues(&sizedArgExprs);
- exprEvaluator.ResolveArgValues(argValues);
- bool boundsCheck = mCompiler->mOptions.mRuntimeChecks;
- auto typeOptions = GetTypeOptions();
- if (typeOptions != NULL)
- boundsCheck = typeOptions->Apply(boundsCheck, BfOptionFlags_RuntimeChecks);
- BfMethodMatcher methodMatcher(forEachStmt->mVariableName, this, "get__", argValues.mResolvedArgs, BfMethodGenericArguments());
- methodMatcher.mMethodType = BfMethodType_PropertyGetter;
- methodMatcher.CheckType(target.mType->ToTypeInstance(), target, false);
- if (methodMatcher.mBestMethodDef == NULL)
- {
- Fail("Failed to find indexer method in array", forEachStmt);
- }
- else
- {
- methodMatcher.mCheckedKind = boundsCheck ? BfCheckedKind_Checked : BfCheckedKind_Unchecked;
- BfTypedValue arrayItem = exprEvaluator.CreateCall(&methodMatcher, target);
- if ((varInst) && (arrayItem))
- {
- if (isRefExpression)
- arrayItem = BfTypedValue(arrayItem.mValue, CreateRefType(arrayItem.mType));
- else if (!arrayItem.mType->IsComposite())
- arrayItem = LoadValue(arrayItem);
- arrayItem = Cast(forEachStmt->mCollectionExpression, arrayItem, varType, BfCastFlags_Explicit);
- arrayItem = LoadValue(arrayItem);
- if ((arrayItem) && (!arrayItem.mType->IsValuelessType()))
- mBfIRBuilder->CreateStore(arrayItem.mValue, varInst);
- }
- }
- }
- else
- {
- if (!itr)
- {
- if (!isVarEnumerator)
- AssertErrorState();
- }
- else if (mCompiler->IsAutocomplete())
- {
- // If we don't do this shortcut, we can end up creating temporary "boxed" objects
- }
- else
- {
- if (nextEmbeddedType->IsVar())
- {
- AssertErrorState();
- }
- else if (needsValCopy)
- {
- auto nextVal = BfTypedValue(mBfIRBuilder->CreateBitCast(nextResult.mValue, mBfIRBuilder->MapType(CreatePointerType(nextEmbeddedType))), nextEmbeddedType, true);
- if (isRefExpression)
- {
- if (nextVal.mType->IsPointer())
- nextVal = BfTypedValue(nextVal.mValue, CreateRefType(nextVal.mType->GetUnderlyingType()), true);
- }
- nextVal = Cast(forEachStmt->mCollectionExpression, nextVal, varType, BfCastFlags_Explicit);
- nextVal = LoadValue(nextVal);
- if ((nextVal) && (!nextVal.mType->IsValuelessType()))
- mBfIRBuilder->CreateAlignedStore(nextVal.mValue, varInst, nextVal.mType->mAlign);
- }
- }
- }
- if (forEachStmt->mEmbeddedStatement != NULL)
- {
- VisitEmbeddedStatement(forEachStmt->mEmbeddedStatement);
- }
- if (!mCurMethodState->mLeftBlockUncond)
- {
- ValueScopeEnd(valueScopeStartInner);
- mBfIRBuilder->CreateBr(incBB);
- }
- mBfIRBuilder->AddBlock(incBB);
- mBfIRBuilder->SetInsertPoint(incBB);
- if (isArray || isSizedArray)
- {
- auto val = mBfIRBuilder->CreateLoad(itr.mValue);
- auto result = mBfIRBuilder->CreateAdd(val, GetConstValue(1));
- mBfIRBuilder->CreateStore(result, itr.mValue);
- }
- else
- {
- // Nothing to do
- }
- mBfIRBuilder->CreateBr(condBB);
- mBfIRBuilder->AddBlock(endBB);
- mBfIRBuilder->SetInsertPoint(endBB);
- if ((itrLocalDef != NULL) && (itrLocalDef->mDbgVarInst) && (IsTargetingBeefBackend()))
- {
- // If this shadows another enumerator variable then we need to explicitly mark the end of this one
- mBfIRBuilder->DbgLifetimeEnd(itrLocalDef->mDbgVarInst);
- }
- // The 'return' may have been inside the block, which may not have been entered if preconditions were not met
- mCurMethodState->SetHadReturn(false);
- mCurMethodState->mLeftBlockUncond = false;
- mCurMethodState->mLeftBlockCond = false;
- RestoreScopeState();
- RestoreScopeState();
- }
- void BfModule::Visit(BfDeferStatement* deferStmt)
- {
- if (deferStmt->mTargetNode == NULL)
- {
- AssertErrorState();
- return;
- }
- //TODO: Why in the world didn't we want to be able to step onto a defer statement?
- // We only want the breakpoint to hit on execution of the defer, not on insertion of it
- //SetAndRestoreValue<bool> prevSetIllegalSrcPos(mSetIllegalSrcPosition, true);
- UpdateSrcPos(deferStmt);
- EmitEnsureInstructionAt();
- BfScopeData* scope = NULL;
- auto scopeNameNode = deferStmt->GetScopeNameNode();
- if (deferStmt->mScopeToken != NULL)
- {
- if (deferStmt->mScopeToken->GetToken() == BfToken_Scope)
- scope = mCurMethodState->mCurScope->GetTargetable();
- else
- scope = &mCurMethodState->mHeadScope;
- }
- else if (scopeNameNode != NULL)
- {
- scope = FindScope(scopeNameNode, true);
- if (scope == NULL)
- {
- AssertErrorState();
- // The scope doesn't exist, continue with the current scope so we still get an evaluation of the deferred code
- scope = mCurMethodState->mCurScope;
- }
- }
- else
- scope = mCurMethodState->mCurScope;
- if ((mCompiler->mResolvePassData != NULL) && (mCompiler->mResolvePassData->mAutoComplete != NULL))
- {
- auto targetIdentifier = BfNodeDynCast<BfIdentifierNode>(deferStmt->mScopeName);
- if ((deferStmt->mScopeName == NULL) || (targetIdentifier != NULL))
- mCompiler->mResolvePassData->mAutoComplete->CheckLabel(targetIdentifier, deferStmt->mColonToken, scope);
- }
- if ((scope == mCurMethodState->mCurScope) && (scope->mCloseNode == NULL))
- {
- auto parser = deferStmt->GetParser();
- if ((parser == NULL) || (!parser->mIsEmitted))
- Warn(0, "This defer will immediately execute. Consider specifying a wider scope target such as 'defer::'", deferStmt->mDeferToken);
- }
- if (auto block = BfNodeDynCast<BfBlock>(deferStmt->mTargetNode))
- {
- if (deferStmt->mBind != NULL)
- {
- Array<BfDeferredCapture> captures;
- for (auto identifier : deferStmt->mBind->mParams)
- {
- BfDeferredCapture deferredCapture;
- deferredCapture.mName = identifier->ToString();
- deferredCapture.mValue = CreateValueFromExpression(identifier);
- if (deferredCapture.mValue)
- {
- captures.push_back(deferredCapture);
- }
- }
- AddDeferredBlock(block, scope, &captures);
- }
- else
- AddDeferredBlock(block, scope);
- }
- else if (auto exprStmt = BfNodeDynCast<BfExpressionStatement>(deferStmt->mTargetNode))
- {
- BfDeferCallData deferCallData;
- deferCallData.mRefNode = exprStmt->mExpression;
- deferCallData.mScopeAlloc = scope;
- BfExprEvaluator expressionEvaluator(this);
- expressionEvaluator.mDeferCallData = &deferCallData;
- expressionEvaluator.VisitChild(exprStmt->mExpression);
- if (mCurMethodState->mPendingNullConditional != NULL)
- FlushNullConditional(expressionEvaluator.mResult, true);
- }
- else if (auto deleteStmt = BfNodeDynCast<BfDeleteStatement>(deferStmt->mTargetNode))
- {
- if (deleteStmt->mExpression == NULL)
- {
- AssertErrorState();
- return;
- }
- auto val = CreateValueFromExpression(deleteStmt->mExpression);
- if (!val)
- return;
- if (mCompiler->IsAutocomplete())
- return;
- bool isGenericParam = false;
- auto checkType = val.mType;
- if (val.mType->IsGenericParam())
- {
- isGenericParam = true;
- auto genericParamInst = GetGenericParamInstance((BfGenericParamType*)val.mType);
- if (genericParamInst->mGenericParamFlags & BfGenericParamFlag_Delete)
- return;
- if (genericParamInst->mTypeConstraint != NULL)
- checkType = genericParamInst->mTypeConstraint;
- }
- bool isAppendDelete = false;
- BfTypedValue customAllocator;
- if (deleteStmt->mAllocExpr != NULL)
- {
- if (auto expr = BfNodeDynCast<BfExpression>(deleteStmt->mAllocExpr))
- customAllocator = CreateValueFromExpression(expr);
- else if (auto tokenNode = BfNodeDynCast<BfTokenNode>(deleteStmt->mAllocExpr))
- {
- if (tokenNode->mToken == BfToken_Append)
- isAppendDelete = true;
- }
- }
- auto internalType = ResolveTypeDef(mCompiler->mInternalTypeDef);
- PopulateType(checkType);
- if (checkType->IsVar())
- return;
- if ((!checkType->IsObjectOrInterface()) && (!checkType->IsPointer()))
- {
- VisitChild(deferStmt->mTargetNode);
- Fail(StrFormat("Cannot delete a value of type '%s'", TypeToString(val.mType).c_str()), deferStmt->mTargetNode);
- return;
- }
- if (isGenericParam)
- return;
- bool isDtorOnly = false;
- if (customAllocator.mType == GetPrimitiveType(BfTypeCode_NullPtr))
- {
- if (!checkType->IsObjectOrInterface())
- Warn(0, "Type '%' has no destructor, so delete:null has no effect", deleteStmt->mExpression);
- }
- else if (customAllocator)
- {
- BfFunctionBindResult functionBindResult;
- functionBindResult.mWantsArgs = true;
- auto customAllocTypeInst = customAllocator.mType->ToTypeInstance();
- if ((checkType->IsObjectOrInterface()) && (customAllocTypeInst != NULL) && (customAllocTypeInst->mTypeDef->GetMethodByName("FreeObject") != NULL))
- {
- BfTypedValueExpression typedValueExpr;
- typedValueExpr.Init(val);
- typedValueExpr.mRefNode = deleteStmt->mAllocExpr;
- BfExprEvaluator exprEvaluator(this);
- SizedArray<BfExpression*, 2> argExprs;
- argExprs.push_back(&typedValueExpr);
- BfSizedArray<BfExpression*> sizedArgExprs(argExprs);
- BfResolvedArgs argValues(&sizedArgExprs);
- exprEvaluator.ResolveArgValues(argValues);
- exprEvaluator.mNoBind = true;
- exprEvaluator.mFunctionBindResult = &functionBindResult;
- exprEvaluator.MatchMethod(deleteStmt->mAllocExpr, NULL, customAllocator, false, false, "FreeObject", argValues, BfMethodGenericArguments());
- }
- else
- {
- auto voidPtrType = GetPrimitiveType(BfTypeCode_NullPtr);
- auto ptrValue = BfTypedValue(mBfIRBuilder->CreateBitCast(val.mValue, mBfIRBuilder->MapType(voidPtrType)), voidPtrType);
- BfTypedValueExpression typedValueExpr;
- typedValueExpr.Init(ptrValue);
- BfExprEvaluator exprEvaluator(this);
- SizedArray<BfExpression*, 2> argExprs;
- argExprs.push_back(&typedValueExpr);
- BfSizedArray<BfExpression*> sizedArgExprs(argExprs);
- BfResolvedArgs argValues(&sizedArgExprs);
- exprEvaluator.ResolveArgValues(argValues);
- exprEvaluator.mNoBind = true;
- exprEvaluator.mFunctionBindResult = &functionBindResult;
- exprEvaluator.MatchMethod(deleteStmt->mAllocExpr, NULL, customAllocator, false, false, "Free", argValues, BfMethodGenericArguments());
- }
- if (functionBindResult.mMethodInstance != NULL)
- {
- AddDeferredCall(BfModuleMethodInstance(functionBindResult.mMethodInstance, functionBindResult.mFunc), functionBindResult.mIRArgs, scope, deleteStmt, true);
- }
- }
- if (checkType->IsObjectOrInterface())
- {
- auto objectType = mContext->mBfObjectType;
- PopulateType(objectType);
- BfMethodInstance* methodInstance = objectType->mVirtualMethodTable[mCompiler->GetVTableMethodOffset() + 0].mImplementingMethod;
- BF_ASSERT(methodInstance->mMethodDef->mName == "~this");
- SizedArray<BfIRValue, 1> llvmArgs;
- llvmArgs.push_back(mBfIRBuilder->CreateBitCast(val.mValue, mBfIRBuilder->MapType(objectType)));
- if (!customAllocator)
- {
- if ((mCompiler->mOptions.mEnableRealtimeLeakCheck) && (!mIsComptimeModule))
- {
- auto moduleMethodInstance = GetInternalMethod("Dbg_MarkObjectDeleted");
- AddDeferredCall(moduleMethodInstance, llvmArgs, scope, deleteStmt, false, true);
- }
- else
- {
- auto moduleMethodInstance = GetInternalMethod("Free");
- SizedArray<BfIRValue, 1> llvmArgs;
- llvmArgs.push_back(mBfIRBuilder->CreateBitCast(val.mValue, mBfIRBuilder->GetPrimitiveType(BfTypeCode_NullPtr)));
- AddDeferredCall(moduleMethodInstance, llvmArgs, scope, deleteStmt, false, true);
- }
- }
- auto moduleMethodInstance = GetMethodInstance(objectType, methodInstance->mMethodDef, BfTypeVector());
- AddDeferredCall(moduleMethodInstance, llvmArgs, scope, deleteStmt, false, true);
- if ((mCompiler->mOptions.mObjectHasDebugFlags) && (!mIsComptimeModule))
- {
- auto moduleMethodInstance = GetMethodByName(internalType->ToTypeInstance(), (deleteStmt->mTargetTypeToken != NULL) ? "Dbg_ObjectPreCustomDelete" : "Dbg_ObjectPreDelete");
- AddDeferredCall(moduleMethodInstance, llvmArgs, scope, deleteStmt, false, true);
- }
- }
- else
- {
- if ((!customAllocator) && (!isAppendDelete))
- {
- val = LoadValue(val);
- BfModuleMethodInstance moduleMethodInstance;
- if ((mCompiler->mOptions.mDebugAlloc) && (!mIsComptimeModule))
- moduleMethodInstance = GetMethodByName(internalType->ToTypeInstance(), "Dbg_RawFree");
- else
- moduleMethodInstance = GetMethodByName(internalType->ToTypeInstance(), "Free");
- SizedArray<BfIRValue, 1> llvmArgs;
- llvmArgs.push_back(mBfIRBuilder->CreateBitCast(val.mValue, mBfIRBuilder->GetPrimitiveType(BfTypeCode_NullPtr)));
- AddDeferredCall(moduleMethodInstance, llvmArgs, scope, deleteStmt, false, true);
- }
- }
- }
- else
- {
- AssertErrorState();
- VisitChild(deferStmt->mTargetNode);
- }
- }
- void BfModule::Visit(BfBlock* block)
- {
- VisitEmbeddedStatement(block);
- }
- void BfModule::Visit(BfUnscopedBlock* block)
- {
- VisitEmbeddedStatement(block, NULL, BfEmbeddedStatementFlags_Unscoped);
- }
- void BfModule::Visit(BfLabeledBlock* labeledBlock)
- {
- VisitEmbeddedStatement(labeledBlock);
- }
- void BfModule::Visit(BfRootNode* rootNode)
- {
- VisitMembers(rootNode);
- }
- void BfModule::Visit(BfInlineAsmStatement* asmStmt)
- {
- #if 0
- enum RegClobberFlags //CDH TODO add support for mmx/xmm/fpst etc (how are these signified in LLVM? check LangRef inline asm docs clobber list info)
- {
- // please keep eax through edx in alphabetical order (grep $BYTEREGS for why)
- REGCLOBBERF_EAX = (1 << 0),
- REGCLOBBERF_EBX = (1 << 1),
- REGCLOBBERF_ECX = (1 << 2),
- REGCLOBBERF_EDX = (1 << 3),
- REGCLOBBERF_ESI = (1 << 4),
- REGCLOBBERF_EDI = (1 << 5),
- REGCLOBBERF_ESP = (1 << 6),
- REGCLOBBERF_EBP = (1 << 7),
- REGCLOBBERF_XMM0 = (1 << 8),
- REGCLOBBERF_XMM1 = (1 << 9),
- REGCLOBBERF_XMM2 = (1 << 10),
- REGCLOBBERF_XMM3 = (1 << 11),
- REGCLOBBERF_XMM4 = (1 << 12),
- REGCLOBBERF_XMM5 = (1 << 13),
- REGCLOBBERF_XMM6 = (1 << 14),
- REGCLOBBERF_XMM7 = (1 << 15),
- REGCLOBBERF_FPST0 = (1 << 16),
- REGCLOBBERF_FPST1 = (1 << 17),
- REGCLOBBERF_FPST2 = (1 << 18),
- REGCLOBBERF_FPST3 = (1 << 19),
- REGCLOBBERF_FPST4 = (1 << 20),
- REGCLOBBERF_FPST5 = (1 << 21),
- REGCLOBBERF_FPST6 = (1 << 22),
- REGCLOBBERF_FPST7 = (1 << 23),
- REGCLOBBERF_MM0 = (1 << 24),
- REGCLOBBERF_MM1 = (1 << 25),
- REGCLOBBERF_MM2 = (1 << 26),
- REGCLOBBERF_MM3 = (1 << 27),
- REGCLOBBERF_MM4 = (1 << 28),
- REGCLOBBERF_MM5 = (1 << 29),
- REGCLOBBERF_MM6 = (1 << 30),
- REGCLOBBERF_MM7 = (1 << 31),
- };
- const char* regClobberNames[] = { "eax", "ebx", "ecx", "edx", "esi", "edi", "esp", "ebp", nullptr }; // must be in same order as flags
- unsigned long regClobberFlags = 0;
- std::function<bool(const StringImpl&, bool)> matchRegFunc = [this, ®ClobberNames, ®ClobberFlags](const StringImpl& name, bool isClobber)
- {
- bool found = false;
- int nameLen = name.length();
- if (nameLen == 3)
- {
- if ((name[0] == 's') && (name[1] == 't') && (name[2] >= '0') && (name[2] <= '7'))
- {
- // st# regs (unparenthesized at this point)
- if (isClobber)
- regClobberFlags |= (REGCLOBBERF_FPST0 << (name[2] - '0'));
- found = true;
- }
- else if ((name[0] == 'm') && (name[1] == 'm') && (name[2] >= '0') && (name[2] <= '7'))
- {
- // mm regs
- if (isClobber)
- regClobberFlags |= (REGCLOBBERF_MM0 << (name[2] - '0'));
- found = true;
- }
- else
- {
- // dword regs
- for (int iRegCheck = 0; regClobberNames[iRegCheck] != nullptr; ++iRegCheck)
- {
- if (!strcmp(name.c_str(), regClobberNames[iRegCheck]))
- {
- if (isClobber)
- regClobberFlags |= (1 << iRegCheck);
- found = true;
- break;
- }
- }
- }
- }
- else if (nameLen == 2)
- {
- // word & byte regs
- for (int iRegCheck = 0; regClobberNames[iRegCheck] != nullptr; ++iRegCheck)
- {
- if (!strcmp(name.c_str(), regClobberNames[iRegCheck] + 1)) // skip leading 'e'
- {
- if (isClobber)
- regClobberFlags |= (1 << iRegCheck);
- found = true;
- break;
- }
- }
- if (!found)
- {
- // check for byte regs for eax through edx (e.g. al, ah, bl, bh....)
- if ((nameLen == 2) && (name[0] >= 'a') && (name[0] <= 'd') && ((name[1] == 'l') || (name[1] == 'h')))
- {
- if (isClobber)
- regClobberFlags |= (1 << (name[0] - 'a'));// $BYTEREGS this is why we want alphabetical order
- found = true;
- }
- }
- }
- else if ((nameLen == 4) && (name[0] == 'x') && (name[1] == 'm') && (name[2] == 'm') && (name[3] >= '0') && (name[3] <= '7'))
- {
- // xmm regs
- if (isClobber)
- regClobberFlags |= (REGCLOBBERF_XMM0 << (name[3] - '0'));
- found = true;
- }
- return found;
- };
- int asmInstCount = (int)asmStmt->mInstructions.size();
- typedef std::map<String, int> StrToVarIndexMap;
- StrToVarIndexMap strToVarIndexMap;
- if (mCompiler->IsAutocomplete())
- {
- // auto-complete "fast-pass" just to eliminate unused/unassigned variable yellow warning flashes
- for (int iInst=0; iInst<asmInstCount; ++iInst)
- {
- auto instNode = asmStmt->mInstructions[iInst];
- BfInlineAsmInstruction::AsmInst& asmInst = instNode->mAsmInst;
- bool hasLabel = !asmInst.mLabel.empty();
- bool hasOpCode = !asmInst.mOpCode.empty();
- if (hasLabel || hasOpCode) // check against blank lines
- {
- if (hasOpCode) // check against label-only lines (which still get written out, but don't do any other processing)
- {
- int argCount = (int)asmInst.mArgs.size();
- for (int iArg=0; iArg<argCount; ++iArg)
- {
- BfInlineAsmInstruction::AsmArg* arg = &asmInst.mArgs[iArg];
- if (arg->mType == BfInlineAsmInstruction::AsmArg::ARGTYPE_IntReg)
- {
- bool found = matchRegFunc(arg->mReg, false);
- if (!found)
- {
- StrToVarIndexMap::iterator it = strToVarIndexMap.find(arg->mReg);
- if (it == strToVarIndexMap.end())
- {
- for (int i = 0; i < (int) mCurMethodState->mLocals.size(); i++)
- {
- auto& checkLocal = mCurMethodState->mLocals[i];
- if (checkLocal.mName == arg->mReg)
- {
- // if you access a variable in asm, we suppress any warnings related to used or assigned, regardless of usage
- checkLocal.mIsReadFrom = true;
- checkLocal.mAssignedKind = BfLocalVarAssignKind_Unconditional;
- found = true;
- break;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- return;
- }
- int debugLocOffset = 0;
- if (!asmStmt->mInstructions.empty())
- debugLocOffset = asmStmt->mInstructions.front()->GetSrcStart() - asmStmt->GetSrcStart();
- UpdateSrcPos(asmStmt, true, debugLocOffset);
- mCurMethodState->mInHeadScope = false;
- BfScopeData prevScope = mCurMethodState->mCurScope;
- mCurMethodState->mCurScope->mPrevScope = &prevScope;
- NewScopeState();
- bool failed = false;
- if (!mCpu)
- mCpu = new Beefy::X86Cpu();
- //const char* srcAsmText = "nop\nnop\n\n\nmov eax, i\ninc eax\nmov i, eax\n_emit 0x0F\n_emit 0xC7\n_emit 0xF0\n\n\nnop\nnop"; //CDH TODO extract from actual lexical text block
- //const char* srcAsmText = "nop\nnop\n\n\nmov eax, i\ninc eax\nmov i, eax\nrdrand eax\n\n\nnop\nnop"; //CDH TODO extract from actual lexical text block
- //String srcAsmTextStr(&asmStmt->mParser->mSrc[asmStmt->mSrcStart], asmStmt->mSrcEnd - asmStmt->mSrcStart);
- //const char* srcAsmText = srcAsmTextStr.c_str();
- String dstAsmText;
- String constraintStr, clobberStr;
- int constraintCount = 0;
- bool hasMemoryClobber = false;
- Array<Type*> paramTypes;
- SizedArray<Value*, 1> llvmArgs;
- int lastDebugLine = -1;
- int curDebugLineDeltaValue = 0, curDebugLineDeltaRunCount = 0;
- String debugLineSequenceStr;
- int isFirstDebugLine = 1;
- auto maybeEmitDebugLineRun = [&curDebugLineDeltaValue, &curDebugLineDeltaRunCount, &debugLineSequenceStr, &isFirstDebugLine]()
- {
- if (curDebugLineDeltaRunCount > 0)
- {
- for (int i=isFirstDebugLine; i<2; ++i)
- {
- int value = i ? curDebugLineDeltaValue : curDebugLineDeltaRunCount;
- String encodedValue;
- EncodeULEB32(value, encodedValue);
- if (encodedValue.length() > 1)
- debugLineSequenceStr += String("$") + encodedValue + "$";
- else
- debugLineSequenceStr += encodedValue;
- }
- curDebugLineDeltaRunCount = 0;
- isFirstDebugLine = 0;
- }
- };
- auto mangledLabelName = [&asmStmt](const StringImpl& labelName, int numericLabel) -> String
- {
- return StrFormat("%d", numericLabel);
- //return String(".") + labelName;
- //return StrFormat("%s_%p_%d", labelName.c_str(), asmStmt->mSource, asmStmt->mSrcStart); // suffix label name with location information to make it block-specific (since labels get external linkage)
- };
- typedef std::pair<String, int> LabelPair;
- std::unordered_map<String, LabelPair> labelNames;
- // pre-scan instructions for label names
- for (int iInst=0; iInst<asmInstCount; ++iInst)
- {
- auto instNode = asmStmt->mInstructions[iInst];
- BfInlineAsmInstruction::AsmInst& asmInst = instNode->mAsmInst;
- if (!asmInst.mLabel.empty())
- {
- if (labelNames.find(asmInst.mLabel) != labelNames.end())
- {
- Fail(StrFormat("Label \"%s\" already defined in asm block", asmInst.mLabel.c_str()), instNode, true);
- failed = true;
- }
- else
- {
- String mangledLabel(mangledLabelName(asmInst.mLabel, instNode->GetSrcStart()));
- labelNames[asmInst.mLabel] = LabelPair(mangledLabel, instNode->GetSrcStart());
- asmInst.mLabel = mangledLabel;
- }
- }
- }
- for (int iInst=0; iInst<asmInstCount; ++iInst)
- {
- auto instNode = asmStmt->mInstructions[iInst];
- BfInlineAsmInstruction::AsmInst& asmInst = instNode->mAsmInst;
- bool hasLabel = !asmInst.mLabel.empty();
- bool hasOpCode = !asmInst.mOpCode.empty();
- if (hasLabel || hasOpCode) // check against blank lines
- {
- if (hasOpCode) // check against label-only lines (which still get written out, but don't do any other processing)
- {
- int argCount = (int)asmInst.mArgs.size();
- // reasonable defaults for clobber info
- int clobberCount = 1; // destination is usually first arg in Intel syntax
- bool mayClobberMem = true; // we only care about this when it gets turned to false by GetClobbersForMnemonic (no operand form of the instruction clobbers mem)
- // pseudo-ops
- if (asmInst.mOpCode == "_emit")
- {
- asmInst.mOpCode = ".byte";
- }
- else
- {
- Array<int> opcodes;
- if (!mCpu->GetOpcodesForMnemonic(asmInst.mOpCode, opcodes))
- {
- Fail(StrFormat("Unrecognized instruction mnemonic \"%s\"", asmInst.mOpCode.c_str()), instNode, true);
- failed = true;
- }
- else
- {
- Array<int> implicitClobbers;
- mCpu->GetClobbersForMnemonic(asmInst.mOpCode, argCount, implicitClobbers, clobberCount, mayClobberMem);
- for (int iClobberReg : implicitClobbers)
- {
- String regName = CPURegisters::GetRegisterName(iClobberReg);
- std::transform(regName.begin(), regName.end(), regName.begin(), ::tolower);
- matchRegFunc(regName, true);
- }
- }
- }
- String fakeLabel; // used when running label-using instructions through LLVM semantic pre-check
- for (int iArg=0; iArg<argCount; ++iArg)
- {
- BfInlineAsmInstruction::AsmArg* arg = &asmInst.mArgs[iArg];
- if (arg->mType == BfInlineAsmInstruction::AsmArg::ARGTYPE_IntReg)
- {
- bool isClobber = (iArg < clobberCount);
- bool found = matchRegFunc(arg->mReg, isClobber);
- if (!found)
- {
- StrToVarIndexMap::iterator it = strToVarIndexMap.find(arg->mReg);
- if (it != strToVarIndexMap.end())
- {
- arg->mReg = StrFormat("$%d", it->second);
- if (isClobber)
- mayClobberMem = true;
- found = true;
- }
- else
- {
- for (int i = 0; i < (int) mCurMethodState->mLocals.size(); i++)
- {
- auto& checkLocal = mCurMethodState->mLocals[i];
- if (checkLocal.mName == arg->mReg)
- {
- BfIRValue testValue = checkLocal.mAddr;
- llvmArgs.push_back(testValue);
- paramTypes.push_back(testValue->getType());
- arg->mReg = StrFormat("$%d", constraintCount);//CDH TODO does this need size qualifiers for "dword ptr $0" or whatever?
- strToVarIndexMap[checkLocal.mName] = constraintCount;
- constraintStr += "=*m,";
- ++constraintCount;
- if (isClobber)
- mayClobberMem = true;
- // if you access a variable in asm, we suppress any warnings related to used or assigned, regardless of usage
- checkLocal.mIsReadFrom = true;
- checkLocal.mAssignedKind = BfLocalVarAssignKind_Unconditional;
- found = true;
- break;
- }
- }
- }
- }
- if (!found)
- {
- auto labelIt = labelNames.find(arg->mReg);
- if (labelIt != labelNames.end())
- {
- arg->mReg = labelIt->second.first;
- if (labelIt->second.second <= instNode->GetSrcStart())
- {
- fakeLabel = arg->mReg;
- arg->mReg += "b";
- }
- else
- arg->mReg += "f";
- }
- else
- {
- Fail(StrFormat("Unrecognized variable \"%s\"", arg->mReg.c_str()), instNode, true);
- failed = true;
- }
- }
- }
- else if (arg->mType == BfInlineAsmInstruction::AsmArg::ARGTYPE_FloatReg)
- {
- //CDH individual reg clobber is probably insufficient for fp regs since it's stack-based; without deeper knowledge of how individual instructions
- // manipulate the FP stack, the safest approach is to clobber all FP regs as soon as one of them is involved
- //bool isClobber = (iArg == 0); // destination is first arg in Intel syntax
- //bool found = matchRegFunc(StrFormat("st%d", arg->mInt), isClobber);
- //BF_ASSERT(found);
- for (int iRegCheck=0; iRegCheck<8; ++iRegCheck)
- regClobberFlags |= (REGCLOBBERF_FPST0 << iRegCheck);
- }
- else if (arg->mType == BfInlineAsmInstruction::AsmArg::ARGTYPE_Memory)
- {
- bool isClobber = (iArg < clobberCount);
- // check regs for clobber flags
- /*
- //CDH TODO do we need to set clobber flags for regs that are used *indirectly* like this? Actually I don't think so; commenting out for now
- if (!arg->mReg.empty())
- matchRegFunc(arg->mReg, isClobber);
- if (!arg->mAdjReg.empty())
- matchRegFunc(arg->mAdjReg, isClobber);
- */
- if (isClobber)
- mayClobberMem = true;
- if (!arg->mMemberSuffix.empty())
- {
- //CDH TODO add member support once I know the right way to look up struct member offsets. Once we know the offset,
- // add it to arg->mInt, and set ARGMEMF_ImmediateDisp if it's not set already (member support is just used as an offset)
- Fail("Member suffix syntax is not yet supported", instNode, true);
- failed = true;
- }
- }
- }
- if (mayClobberMem)
- hasMemoryClobber = true;
- //debugLineSequenceStr += StrFormat("%d_", asmInst.mDebugLine);
- int curDebugLine = asmInst.mDebugLine;
- int debugLineDelta = (lastDebugLine > 0) ? curDebugLine - lastDebugLine : curDebugLine;
- lastDebugLine = curDebugLine;
- //String encodedDebugLineDelta;
- //EncodeULEB32(debugLineDelta, encodedDebugLineDelta);
- //debugLineSequenceStr += encodedDebugLineDelta + "_";
- if (curDebugLineDeltaValue != debugLineDelta)
- {
- maybeEmitDebugLineRun();
- curDebugLineDeltaValue = debugLineDelta;
- }
- ++curDebugLineDeltaRunCount;
- // run instruction through LLVM for better semantic errors (can be slow in debug; feel free to comment out this scopeData if it's intolerable; the errors will still be caught at compile time)
- //if (false)
- {
- BfInlineAsmInstruction::AsmInst tempAsmInst(asmInst);
- tempAsmInst.mLabel = fakeLabel;
- for (auto & arg : tempAsmInst.mArgs)
- {
- if ((arg.mType == BfInlineAsmInstruction::AsmArg::ARGTYPE_IntReg) && !arg.mReg.empty() && (arg.mReg[0] == '$'))
- {
- // if we've rewritten a local variable instruction arg to use a $-prefixed input, we can't pass that to LLVM
- // at this stage as it won't recognize it; the actual compilation would have changed all these to use actual
- // memory operand syntax first. However, those changes all work down in LLVM to printIntelMemReference inside
- // of X86AsmPrinter.cpp, and that always results in a [bracketed] memory access string no matter what, which
- // means for our semantic checking purposes here it's sufficient to just use "[eax]" for all such cases,
- // rather than go through an even more expensive setup & teardown process to use the AsmPrinter itself.
- arg.mType = BfInlineAsmInstruction::AsmArg::ARGTYPE_Memory;
- arg.mMemFlags = BfInlineAsmInstruction::AsmArg::ARGMEMF_BaseReg;
- arg.mReg = "eax";
- }
- }
- String llvmError;
- if (!mCpu->ParseInlineAsmInstructionLLVM(tempAsmInst.ToString(), llvmError))
- {
- Fail(StrFormat("Inline asm error: %s", llvmError.c_str()), instNode, true);
- failed = true;
- }
- }
- }
- dstAsmText += asmInst.ToString();
- dstAsmText += "\n";
- }
- }
- maybeEmitDebugLineRun(); // leftovers
- if (failed)
- {
- RestoreScopeState(&prevScope);
- return;
- }
- // prepare constraints/clobbers
- {
- for (int iRegCheck = 0; regClobberNames[iRegCheck] != nullptr; ++iRegCheck)
- {
- if (regClobberFlags & (1 << iRegCheck))
- clobberStr += StrFormat("~{%s},", regClobberNames[iRegCheck]);
- }
- for (int iRegCheck=0; iRegCheck<8; ++iRegCheck)
- {
- if (regClobberFlags & (REGCLOBBERF_XMM0 << iRegCheck))
- clobberStr += StrFormat("~{xmm%d},", iRegCheck);
- if (regClobberFlags & (REGCLOBBERF_FPST0 << iRegCheck))
- clobberStr += StrFormat("~{fp%d},~{st(%d)},", iRegCheck, iRegCheck); // both fp# and st(#) are listed in X86RegisterInfo.td
- if (regClobberFlags & (REGCLOBBERF_MM0 << iRegCheck))
- clobberStr += StrFormat("~{mm%d},", iRegCheck);
- }
- // add wrapping instructions to preserve certain regs (e.g. ESI), due to LLVM bypassing register allocator when choosing a base register
- //CDH TODO currently I'm only shielding against ESI stompage; people generally know not to mess with ESP & EBP, but ESI is still a "general" reg and should be allowed to be clobbered
- //if (regClobberFlags & REGCLOBBERF_ESI)
- //{
- //CDH TODO Bah! This doesn't actually work, because if you do any local variable access after mutating ESI, the variable substitution could have generated a base address dependency
- // on ESI which will not expect it to have changed, e.g. "mov esi, var\ninc esi\nmov var, esi\n" dies if "var" gets internally rewritten to "[esi + displacement]". What to do? Hmm.
- //dstAsmText = String("push esi\n") + dstAsmText + String("pop esi\n");
- //}
- if (hasMemoryClobber)
- clobberStr += "~{memory},";
- clobberStr += "~{dirflag},~{fpsr},~{flags}";
- constraintStr += clobberStr;
- }
- bool wantsDIData = (mBfIRBuilder->DbgHasInfo()) && (!mCurMethodInstance->mIsUnspecialized) && (mHasFullDebugInfo);
- if (wantsDIData)
- {
- static int sVarNum = 0;
- String varName(StrFormat("__asmLines_%d.%s", ++sVarNum, debugLineSequenceStr.c_str()));
- auto varType = GetPrimitiveType(BfTypeCode_Int32);
- auto allocaInst = mBfIRBuilder->CreateAlloca(varType->mLLVMType, 0, varName + ".addr");
- allocaInst->setAlignment(varType->mAlign);
- //paramVar->mAddr = allocaInst;
- auto varValue = GetConstValue(0, varType);
- auto diVariable = mDIBuilder->createAutoVariable(mCurMethodState->mCurScope->mDIScope,
- varName.c_str(), mCurFilePosition.mFileInstance->mDIFile, mCurFilePosition.mCurLine, varType->mDIType/*, true*/);
- //auto varValue = llvm::ConstantInt::getTrue(*mLLVMContext);
- //auto varValue = GetDefaultValue(varType);
- //auto varValue = CreateGlobalConstValue(varName, llvm::ConstantInt::getTrue(*mLLVMContext), true);
- //auto varValue = AllocGlobalVariable(*mIRModule, diType->getType(), false, GlobalValue::ExternalLinkage, llvm::ConstantInt::getTrue(*mLLVMContext), varName.c_str());
- //auto diVariable = mDIBuilder->createGlobalVariable(mCurMethodState->mCurScope->mDIScope, varName.c_str(), "", mCurFilePosition.mFileInstance->mDIFile, mCurFilePosition.mCurLine, diType, false, varValue);
- //BasicBlock* block = mBfIRBuilder->GetInsertBlock();
- //auto declareVar = mDIBuilder->insertDeclare(varValue, diVariable, mBfIRBuilder->GetInsertBlock());
- auto declareVar = mDIBuilder->insertDeclare(allocaInst, diVariable, mDIBuilder->createExpression(),
- mIRBuilder->getCurrentDebugLocation(), mBfIRBuilder->GetInsertBlock());
- //auto declareVar = mDIBuilder->insertDbgValueIntrinsic(varValue, 0, diVariable, mBfIRBuilder->GetInsertBlock());
- declareVar->setDebugLoc(mIRBuilder->getCurrentDebugLocation());
- }
- /*
- BfIRValue testValue = NULL;
- for (int i = 0; i < (int) mCurMethodState->mLocals.size(); i++)
- {
- auto& checkLocal = mCurMethodState->mLocals[i];
- if (checkLocal.mName == "i")
- {
- testValue = checkLocal.mAddr;
- break;
- }
- }
- */
- //BF_ASSERT((testValue != NULL) && "Need local variable \"i\"");
- //if (testValue != NULL)
- {
- //Type* voidPtrType = Type::getInt8PtrTy(*mLLVMContext);
- //if (mContext->mAsmObjectCheckFuncType == NULL)
- //{
- //Array<Type*> paramTypes;
- //paramTypes.push_back(voidPtrType);
- //mContext->mAsmObjectCheckFuncType = FunctionType::get(Type::getVoidTy(*mLLVMContext), paramTypes, false);
- //}
- FunctionType* funcType = FunctionType::get(Type::getVoidTy(*mLLVMContext), paramTypes, false);
- //SizedArray<Value*, 1> llvmArgs;
- //llvmArgs.push_back(testValue);
- //CDH REMOVE NOTE
- //generates IR (e.g.):
- // call void asm sideeffect "#4\0Anop\0Anop\0Amovl %eax, %eax\0Anop\0Anop", "~{cc},~{dirflag},~{fpsr},~{flags},~{eax}"() #0, !dbg !492
- static int asmIdx = 0;
- asmIdx++;
- String asmStr = StrFormat("#%d\n", asmIdx) +
- //"nop\nnop\nmovl $0, %eax\nincl %eax\nmovl %eax, $0\nmovl $$0, %ecx\nmovl $$0, %esp\nnop\nnop";
- //"nop\nnop\nmovl ($0), %eax\nincl %eax\nmovl %eax, ($0)\nmovl $$0, %ecx\nmovl $$0, %esp\nnop\nnop";
- //"nop\nnop\nmovl %eax, %eax\nmovl $$0, %ecx\nmovl $$0, %esp\nnop\nnop";
- //"nop\nnop\nmovl %eax, %eax\nnop\nnop";
- //"nop\nnop\n.byte 0x0F\n.byte 0xC7\n.byte 0xF0\nmov eax, 7\nmov ecx, 0\ncpuid\nmov eax, dword ptr $0\ninc eax\nmov dword ptr $0, eax\nmov ecx, 0\nmov esp, 0\nnop\nnop"; // rdrand test
- dstAsmText;
- llvm::InlineAsm* inlineAsm = llvm::InlineAsm::get(funcType,
- //asmStr.c_str(), "~{r},~{cc},~{dirflag},~{fpsr},~{flags},~{eax},~{memory},~{esi},~{esp}", true,
- //asmStr.c_str(), "~{cc},~{dirflag},~{fpsr},~{flags},~{memory},~{ecx},~{esp}", true,
- //DOES NOT WORK (mem not written back to from reg:
- //asmStr.c_str(), "+r,~{cc},~{dirflag},~{fpsr},~{flags},~{memory},~{eax},~{ecx},~{esp}", true,
- //asmStr.c_str(), "+rm,~{cc},~{dirflag},~{fpsr},~{flags},~{memory},~{eax},~{ecx},~{esp}", true,
- asmStr.c_str(), constraintStr.c_str(), true,
- false, /*llvm::InlineAsm::AD_ATT*/llvm::InlineAsm::AD_Intel);
- llvm::CallInst* callInst = mIRBuilder->CreateCall(inlineAsm, llvmArgs);
- //llvm::CallInst* callInst = mIRBuilder->CreateCall(inlineAsm);
- callInst->addAttribute(llvm::AttributeSet::FunctionIndex, llvm::Attribute::NoUnwind);
- }
- RestoreScopeState(&prevScope);
- #endif
- }
|