| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296 |
- /**
- * MojoShader; generate shader programs from bytecode of compiled
- * Direct3D shaders.
- *
- * Please see the file LICENSE.txt in the source's root directory.
- *
- * This file written by Ryan C. Gordon.
- */
- // !!! FIXME: this needs to be split into separate source files:
- // !!! FIXME: parse, AST, IR, etc. The problem is we need to deal with the
- // !!! FIXME: "Context" struct being passed around everywhere.
- #define __MOJOSHADER_INTERNAL__ 1
- #include "mojoshader_internal.h"
- #if DEBUG_COMPILER_PARSER
- #define LEMON_SUPPORT_TRACING 1
- #endif
- // !!! FIXME: I'd like to lose this. It's really inefficient. Just keep a
- // !!! FIXME: (tail) on these list structures instead?
- #define REVERSE_LINKED_LIST(typ, head) { \
- if ((head) && (head->next)) { \
- typ *tmp = NULL; \
- typ *tmp1 = NULL; \
- while (head != NULL) { \
- tmp = head; \
- head = head->next; \
- tmp->next = tmp1; \
- tmp1 = tmp; \
- } \
- head = tmp; \
- } \
- }
- static inline int operator_is_unary(const MOJOSHADER_astNodeType op)
- {
- return ( (op > MOJOSHADER_AST_OP_START_RANGE_UNARY) &&
- (op < MOJOSHADER_AST_OP_END_RANGE_UNARY) );
- } // operator_is_unary
- static inline int operator_is_binary(const MOJOSHADER_astNodeType op)
- {
- return ( (op > MOJOSHADER_AST_OP_START_RANGE_BINARY) &&
- (op < MOJOSHADER_AST_OP_END_RANGE_BINARY) );
- } // operator_is_binary
- static inline int operator_is_ternary(const MOJOSHADER_astNodeType op)
- {
- return ( (op > MOJOSHADER_AST_OP_START_RANGE_TERNARY) &&
- (op < MOJOSHADER_AST_OP_END_RANGE_TERNARY) );
- } // operator_is_ternary
- typedef union TokenData
- {
- int64 i64;
- double dbl;
- const char *string;
- const MOJOSHADER_astDataType *datatype;
- } TokenData;
- // This tracks data types and variables, and notes when they enter/leave scope.
- typedef struct SymbolScope
- {
- const char *symbol;
- const MOJOSHADER_astDataType *datatype;
- int index; // unique positive value within a function, negative if global.
- int referenced; // non-zero if something looked for this symbol (so we know it's used).
- struct SymbolScope *next;
- } SymbolScope;
- typedef struct SymbolMap
- {
- HashTable *hash;
- SymbolScope *scope;
- } SymbolMap;
- typedef struct LoopLabels
- {
- int start; // loop's start label during IR build.
- int end; // loop's end label during IR build.
- struct LoopLabels *prev;
- } LoopLabels;
- // Compile state, passed around all over the place.
- typedef struct Context
- {
- int isfail;
- int out_of_memory;
- MOJOSHADER_malloc malloc;
- MOJOSHADER_free free;
- void *malloc_data;
- ErrorList *errors;
- ErrorList *warnings;
- StringCache *strcache;
- const char *sourcefile; // current source file that we're parsing.
- unsigned int sourceline; // current line in sourcefile that we're parsing.
- SymbolMap usertypes;
- SymbolMap variables;
- MOJOSHADER_astNode *ast; // Abstract Syntax Tree
- const char *source_profile;
- int is_func_scope; // non-zero if semantic analysis is in function scope.
- int loop_count;
- int switch_count;
- int var_index; // next variable index for current function.
- int global_var_index; // next variable index for global scope.
- int user_func_index; // next function index for user-defined functions.
- int intrinsic_func_index; // next function index for intrinsic functions.
- MOJOSHADER_irStatement **ir; // intermediate representation.
- int ir_label_count; // next unused IR label index.
- int ir_temp_count; // next unused IR temporary value index.
- int ir_end; // current function's end label during IR build.
- int ir_ret; // temp that holds current function's retval during IR build.
- LoopLabels *ir_loop; // nested loop boundary labels during IR build.
- // Cache intrinsic types for fast lookup and consistent pointer values.
- MOJOSHADER_astDataType dt_none;
- MOJOSHADER_astDataType dt_bool;
- MOJOSHADER_astDataType dt_int;
- MOJOSHADER_astDataType dt_uint;
- MOJOSHADER_astDataType dt_float;
- MOJOSHADER_astDataType dt_float_snorm;
- MOJOSHADER_astDataType dt_float_unorm;
- MOJOSHADER_astDataType dt_half;
- MOJOSHADER_astDataType dt_double;
- MOJOSHADER_astDataType dt_string;
- MOJOSHADER_astDataType dt_sampler1d;
- MOJOSHADER_astDataType dt_sampler2d;
- MOJOSHADER_astDataType dt_sampler3d;
- MOJOSHADER_astDataType dt_samplercube;
- MOJOSHADER_astDataType dt_samplerstate;
- MOJOSHADER_astDataType dt_samplercompstate;
- MOJOSHADER_astDataType dt_buf_bool;
- MOJOSHADER_astDataType dt_buf_int;
- MOJOSHADER_astDataType dt_buf_uint;
- MOJOSHADER_astDataType dt_buf_half;
- MOJOSHADER_astDataType dt_buf_float;
- MOJOSHADER_astDataType dt_buf_double;
- MOJOSHADER_astDataType dt_buf_float_snorm;
- MOJOSHADER_astDataType dt_buf_float_unorm;
- Buffer *garbage; // this is sort of hacky.
- } Context;
- // !!! FIXME: cut and paste between every damned source file follows...
- // !!! FIXME: We need to make some sort of ContextBase that applies to all
- // !!! FIXME: files and move this stuff to mojoshader_common.c ...
- // Convenience functions for allocators...
- static inline void out_of_memory(Context *ctx)
- {
- ctx->isfail = ctx->out_of_memory = 1;
- } // out_of_memory
- static inline void *Malloc(Context *ctx, const size_t len)
- {
- void *retval = ctx->malloc((int) len, ctx->malloc_data);
- if (retval == NULL)
- out_of_memory(ctx);
- return retval;
- } // Malloc
- static inline char *StrDup(Context *ctx, const char *str)
- {
- char *retval = (char *) Malloc(ctx, strlen(str) + 1);
- if (retval != NULL)
- strcpy(retval, str);
- return retval;
- } // StrDup
- static inline void Free(Context *ctx, void *ptr)
- {
- ctx->free(ptr, ctx->malloc_data);
- } // Free
- static void *MallocBridge(int bytes, void *data)
- {
- return Malloc((Context *) data, (size_t) bytes);
- } // MallocBridge
- static void FreeBridge(void *ptr, void *data)
- {
- Free((Context *) data, ptr);
- } // FreeBridge
- static void failf(Context *ctx, const char *fmt, ...) ISPRINTF(2,3);
- static void failf(Context *ctx, const char *fmt, ...)
- {
- ctx->isfail = 1;
- if (ctx->out_of_memory)
- return;
- va_list ap;
- va_start(ap, fmt);
- errorlist_add_va(ctx->errors, ctx->sourcefile, ctx->sourceline, fmt, ap);
- va_end(ap);
- } // failf
- static inline void fail(Context *ctx, const char *reason)
- {
- failf(ctx, "%s", reason);
- } // fail
- static void warnf(Context *ctx, const char *fmt, ...) ISPRINTF(2,3);
- static void warnf(Context *ctx, const char *fmt, ...)
- {
- if (ctx->out_of_memory)
- return;
- va_list ap;
- va_start(ap, fmt);
- errorlist_add_va(ctx->warnings, ctx->sourcefile, ctx->sourceline, fmt, ap);
- va_end(ap);
- } // warnf
- static inline void warn(Context *ctx, const char *reason)
- {
- warnf(ctx, "%s", reason);
- } // warn
- static inline int isfail(const Context *ctx)
- {
- return ctx->isfail;
- } // isfail
- static void symbolmap_nuke(const void *k, const void *v, void *d) {/*no-op*/}
- static int create_symbolmap(Context *ctx, SymbolMap *map)
- {
- // !!! FIXME: should compare string pointer, with string in cache.
- map->scope = NULL;
- map->hash = hash_create(ctx, hash_hash_string, hash_keymatch_string,
- symbolmap_nuke, 1, MallocBridge, FreeBridge, ctx);
- return (map->hash != NULL);
- } // create_symbolmap
- static int datatypes_match(const MOJOSHADER_astDataType *a,
- const MOJOSHADER_astDataType *b)
- {
- int i;
- if (a == b)
- return 1;
- else if (a->type != b->type)
- return 0;
- switch (a->type)
- {
- case MOJOSHADER_AST_DATATYPE_STRUCT:
- if (a->structure.member_count != b->structure.member_count)
- return 0;
- for (i = 0; i < a->structure.member_count; i++)
- {
- if (!datatypes_match(a->structure.members[i].datatype,
- b->structure.members[i].datatype))
- return 0;
- // stringcache'd, pointer compare is safe.
- else if (a->structure.members[i].identifier !=
- b->structure.members[i].identifier)
- return 0;
- } // for
- return 1;
- case MOJOSHADER_AST_DATATYPE_ARRAY:
- if (a->array.elements != b->array.elements)
- return 0;
- else if (!datatypes_match(a->array.base, b->array.base))
- return 0;
- return 1;
- case MOJOSHADER_AST_DATATYPE_VECTOR:
- if (a->vector.elements != b->vector.elements)
- return 0;
- else if (!datatypes_match(a->vector.base, b->vector.base))
- return 0;
- return 1;
- case MOJOSHADER_AST_DATATYPE_MATRIX:
- if (a->matrix.rows != b->matrix.rows)
- return 0;
- else if (a->matrix.columns != b->matrix.columns)
- return 0;
- else if (!datatypes_match(a->matrix.base, b->matrix.base))
- return 0;
- return 1;
- case MOJOSHADER_AST_DATATYPE_BUFFER:
- return datatypes_match(a->buffer.base, b->buffer.base);
- case MOJOSHADER_AST_DATATYPE_FUNCTION:
- if (a->function.num_params != b->function.num_params)
- return 0;
- else if (a->function.intrinsic != b->function.intrinsic)
- return 0;
- else if (!datatypes_match(a->function.retval, b->function.retval))
- return 0;
- for (i = 0; i < a->function.num_params; i++)
- {
- if (!datatypes_match(a->function.params[i], b->function.params[i]))
- return 0;
- } // for
- return 1;
- case MOJOSHADER_AST_DATATYPE_USER:
- return 0; // pointers must match, this clearly didn't.
- default:
- assert(0 && "unexpected case");
- return 0;
- } // switch
- return 0;
- } // datatypes_match
- static void push_symbol(Context *ctx, SymbolMap *map, const char *sym,
- const MOJOSHADER_astDataType *dt, const int index,
- const int check_dupes)
- {
- if (ctx->out_of_memory)
- return;
- // Decide if this symbol is defined, and if it's in the current scope.
- SymbolScope *item = NULL;
- const void *value = NULL;
- if ((check_dupes) && (sym != NULL) && (hash_find(map->hash, sym, &value)))
- {
- // check the current scope for a dupe.
- // !!! FIXME: note current scope's starting index, see if found
- // !!! FIXME: item is < index (and thus, a previous scope).
- item = map->scope;
- while ((item) && (item->symbol))
- {
- if ( ((const void *) item) == value )
- {
- failf(ctx, "Symbol '%s' already defined", sym);
- return;
- } // if
- item = item->next;
- } // while
- } // if
- // Add the symbol to our map and scope stack.
- item = (SymbolScope *) Malloc(ctx, sizeof (SymbolScope));
- if (item == NULL)
- return;
- if (sym != NULL) // sym can be NULL if we're pushing a new scope.
- {
- if (hash_insert(map->hash, sym, item) == -1)
- {
- Free(ctx, item);
- return;
- } // if
- } // if
- item->symbol = sym; // cached strings, don't copy.
- item->index = index;
- item->datatype = dt;
- item->referenced = 0;
- item->next = map->scope;
- map->scope = item;
- } // push_symbol
- static void push_usertype(Context *ctx, const char *sym, const MOJOSHADER_astDataType *dt)
- {
- if (sym != NULL)
- {
- MOJOSHADER_astDataType *userdt;
- userdt = (MOJOSHADER_astDataType *) Malloc(ctx, sizeof (*userdt));
- if (userdt != NULL)
- {
- // !!! FIXME: this is hacky.
- if (!buffer_append(ctx->garbage, &userdt, sizeof (userdt)))
- {
- Free(ctx, userdt);
- return;
- } // if
- userdt->type = MOJOSHADER_AST_DATATYPE_USER;
- userdt->user.details = dt;
- userdt->user.name = sym;
- dt = userdt;
- } // if
- } // if
- push_symbol(ctx, &ctx->usertypes, sym, dt, 0, 1);
- } // push_usertype
- static inline void push_variable(Context *ctx, const char *sym, const MOJOSHADER_astDataType *dt)
- {
- int idx = 0;
- if (sym != NULL)
- {
- // leave space for individual member indexes. The IR will need this.
- int additional = 0;
- if (dt->type == MOJOSHADER_AST_DATATYPE_STRUCT)
- additional = dt->structure.member_count;
- if (ctx->is_func_scope)
- {
- idx = ++ctx->var_index; // these are positive.
- ctx->var_index += additional;
- } // if
- else
- {
- idx = --ctx->global_var_index; // these are negative.
- ctx->global_var_index -= additional;
- } // else
- } // if
- push_symbol(ctx, &ctx->variables, sym, dt, idx, 1);
- } // push_variable
- static int push_function(Context *ctx, const char *sym,
- const MOJOSHADER_astDataType *dt,
- const int just_declare)
- {
- // we don't have any reason to support nested functions at the moment,
- // so this would be a bug.
- assert(!ctx->is_func_scope);
- assert(dt->type == MOJOSHADER_AST_DATATYPE_FUNCTION);
- // Functions are always global, so no need to search scopes.
- // Functions overload, though, so we have to continue iterating to
- // see if it matches anything.
- const void *value = NULL;
- void *iter = NULL;
- while (hash_iter(ctx->variables.hash, sym, &value, &iter))
- {
- // !!! FIXME: this breaks if you predeclare a function.
- // !!! FIXME: (a declare AFTER defining works, though.)
- // there's already something called this.
- SymbolScope *item = (SymbolScope *) value;
- if (datatypes_match(dt, item->datatype))
- {
- if (!just_declare)
- failf(ctx, "Function '%s' already defined.", sym);
- return item->index;
- } // if
- } // while
- int idx = 0;
- if ((sym != NULL) && (dt != NULL))
- {
- if (!dt->function.intrinsic)
- idx = ++ctx->user_func_index; // these are positive.
- else
- idx = --ctx->intrinsic_func_index; // these are negative.
- } // if
- // push_symbol() doesn't check dupes, because we just did.
- push_symbol(ctx, &ctx->variables, sym, dt, idx, 0);
- return idx;
- } // push_function
- static inline void push_scope(Context *ctx)
- {
- push_usertype(ctx, NULL, NULL);
- push_variable(ctx, NULL, NULL);
- } // push_scope
- static void pop_symbol(Context *ctx, SymbolMap *map)
- {
- SymbolScope *item = map->scope;
- if (!item)
- return;
- if (item->symbol)
- hash_remove(map->hash, item->symbol);
- map->scope = item->next;
- Free(ctx, item);
- } // pop_symbol
- static void pop_symbol_scope(Context *ctx, SymbolMap *map)
- {
- while ((map->scope) && (map->scope->symbol))
- pop_symbol(ctx, map);
- assert(map->scope != NULL);
- assert(map->scope->symbol == NULL);
- pop_symbol(ctx, map);
- } // pop_symbol_scope
- static inline void pop_scope(Context *ctx)
- {
- pop_symbol_scope(ctx, &ctx->usertypes);
- pop_symbol_scope(ctx, &ctx->variables);
- } // push_scope
- static const MOJOSHADER_astDataType *find_symbol(Context *ctx, SymbolMap *map, const char *sym, int *_index)
- {
- const void *_item = NULL;
- hash_find(map->hash, sym, &_item);
- SymbolScope *item = (SymbolScope *) _item;
- if (item != NULL)
- {
- item->referenced++;
- if (_index != NULL)
- *_index = item->index;
- } // if
- return item ? item->datatype : NULL;
- } // find_symbol
- static inline const MOJOSHADER_astDataType *find_usertype(Context *ctx, const char *sym)
- {
- return find_symbol(ctx, &ctx->usertypes, sym, NULL);
- } // find_usertype
- static inline const MOJOSHADER_astDataType *find_variable(Context *ctx, const char *sym, int *_index)
- {
- return find_symbol(ctx, &ctx->variables, sym, _index);
- } // find_variable
- static void destroy_symbolmap(Context *ctx, SymbolMap *map)
- {
- while (map->scope)
- pop_symbol(ctx, map);
- hash_destroy(map->hash);
- } // destroy_symbolmap
- static const MOJOSHADER_astDataType *new_datatype_vector(Context *ctx,
- const MOJOSHADER_astDataType *dt,
- const int columns)
- {
- MOJOSHADER_astDataType *retval;
- retval = (MOJOSHADER_astDataType *) Malloc(ctx, sizeof (*retval));
- if (retval == NULL)
- return NULL;
- // !!! FIXME: this is hacky.
- // !!! FIXME: I'd like to cache these anyhow and reuse types.
- if (!buffer_append(ctx->garbage, &retval, sizeof (retval)))
- {
- Free(ctx, retval);
- return NULL;
- } // if
- if ((columns < 1) || (columns > 4))
- fail(ctx, "Vector must have between 1 and 4 elements");
- retval->type = MOJOSHADER_AST_DATATYPE_VECTOR;
- retval->vector.base = dt;
- retval->vector.elements = columns;
- return retval;
- } // new_datatype_vector
- static const MOJOSHADER_astDataType *new_datatype_matrix(Context *ctx,
- const MOJOSHADER_astDataType *dt,
- const int rows, const int columns)
- {
- MOJOSHADER_astDataType *retval;
- // !!! FIXME: allocate enough for a matrix, but we need to cleanup things that copy without checking for subsize.
- retval = (MOJOSHADER_astDataType *) Malloc(ctx, sizeof (*retval));
- if (retval == NULL)
- return NULL;
- // !!! FIXME: this is hacky.
- // !!! FIXME: I'd like to cache these anyhow and reuse types.
- if (!buffer_append(ctx->garbage, &retval, sizeof (retval)))
- {
- Free(ctx, retval);
- return NULL;
- } // if
- if ((rows < 1) || (rows > 4))
- fail(ctx, "Matrix must have between 1 and 4 rows");
- if ((columns < 1) || (columns > 4))
- fail(ctx, "Matrix must have between 1 and 4 columns");
- retval->type = MOJOSHADER_AST_DATATYPE_MATRIX;
- retval->matrix.base = dt;
- retval->matrix.rows = rows;
- retval->matrix.columns = columns;
- return retval;
- } // new_datatype_matrix
- // !!! FIXME: move this to mojoshader_ast.c
- // !!! FIXME: new_* and delete_* should take an allocator, not a context.
- // These functions are mostly for construction and cleanup of nodes in the
- // parse tree. Mostly this is simple allocation and initialization, so we
- // can do as little in the lemon code as possible, and then sort it all out
- // afterwards.
- #define NEW_AST_NODE(retval, cls, typ) \
- cls *retval = (cls *) Malloc(ctx, sizeof (cls)); \
- do { \
- if (retval == NULL) { return NULL; } \
- retval->ast.type = typ; \
- retval->ast.filename = ctx->sourcefile; \
- retval->ast.line = ctx->sourceline; \
- } while (0)
- #define DELETE_AST_NODE(cls) do { \
- if (!cls) return; \
- } while (0)
- static void delete_compilation_unit(Context*, MOJOSHADER_astCompilationUnit*);
- static void delete_statement(Context *ctx, MOJOSHADER_astStatement *stmt);
- static MOJOSHADER_astExpression *new_identifier_expr(Context *ctx,
- const char *string)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astExpressionIdentifier,
- MOJOSHADER_AST_OP_IDENTIFIER);
- retval->datatype = NULL;
- retval->identifier = string; // cached; don't copy string.
- retval->index = 0;
- return (MOJOSHADER_astExpression *) retval;
- } // new_identifier_expr
- static MOJOSHADER_astExpression *new_callfunc_expr(Context *ctx,
- const char *identifier,
- MOJOSHADER_astArguments *args)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astExpressionCallFunction,
- MOJOSHADER_AST_OP_CALLFUNC);
- MOJOSHADER_astExpression *expr = new_identifier_expr(ctx, identifier);
- retval->datatype = NULL;
- retval->identifier = (MOJOSHADER_astExpressionIdentifier *) expr;
- retval->args = args;
- return (MOJOSHADER_astExpression *) retval;
- } // new_callfunc_expr
- static MOJOSHADER_astExpression *new_constructor_expr(Context *ctx,
- const MOJOSHADER_astDataType *dt,
- MOJOSHADER_astArguments *args)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astExpressionConstructor,
- MOJOSHADER_AST_OP_CONSTRUCTOR);
- retval->datatype = dt;
- retval->args = args;
- return (MOJOSHADER_astExpression *) retval;
- } // new_constructor_expr
- static MOJOSHADER_astExpression *new_cast_expr(Context *ctx,
- const MOJOSHADER_astDataType *dt,
- MOJOSHADER_astExpression *operand)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astExpressionCast, MOJOSHADER_AST_OP_CAST);
- retval->datatype = dt;
- retval->operand = operand;
- return (MOJOSHADER_astExpression *) retval;
- } // new_cast_expr
- static MOJOSHADER_astExpression *new_unary_expr(Context *ctx,
- const MOJOSHADER_astNodeType op,
- MOJOSHADER_astExpression *operand)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astExpressionUnary, op);
- assert(operator_is_unary(op));
- retval->datatype = NULL;
- retval->operand = operand;
- return (MOJOSHADER_astExpression *) retval;
- } // new_unary_expr
- static MOJOSHADER_astExpression *new_binary_expr(Context *ctx,
- const MOJOSHADER_astNodeType op,
- MOJOSHADER_astExpression *left,
- MOJOSHADER_astExpression *right)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astExpressionBinary, op);
- assert(operator_is_binary(op));
- retval->datatype = NULL;
- retval->left = left;
- retval->right = right;
- return (MOJOSHADER_astExpression *) retval;
- } // new_binary_expr
- static MOJOSHADER_astExpression *new_ternary_expr(Context *ctx,
- const MOJOSHADER_astNodeType op,
- MOJOSHADER_astExpression *left,
- MOJOSHADER_astExpression *center,
- MOJOSHADER_astExpression *right)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astExpressionTernary, op);
- assert(operator_is_ternary(op));
- assert(op == MOJOSHADER_AST_OP_CONDITIONAL);
- retval->datatype = &ctx->dt_bool;
- retval->left = left;
- retval->center = center;
- retval->right = right;
- return (MOJOSHADER_astExpression *) retval;
- } // new_ternary_expr
- static MOJOSHADER_astExpression *new_deref_struct_expr(Context *ctx,
- MOJOSHADER_astExpression *identifier,
- const char *member)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astExpressionDerefStruct,
- MOJOSHADER_AST_OP_DEREF_STRUCT);
- retval->datatype = NULL;
- retval->identifier = identifier;
- retval->member = member; // cached; don't copy string.
- retval->isswizzle = 0; // may change during semantic analysis.
- retval->member_index = 0; // set during semantic analysis.
- return (MOJOSHADER_astExpression *) retval;
- } // new_deref_struct_expr
- static MOJOSHADER_astExpression *new_literal_int_expr(Context *ctx,
- const int value)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astExpressionIntLiteral,
- MOJOSHADER_AST_OP_INT_LITERAL);
- retval->datatype = &ctx->dt_int;
- retval->value = value;
- return (MOJOSHADER_astExpression *) retval;
- } // new_literal_int_expr
- static MOJOSHADER_astExpression *new_literal_float_expr(Context *ctx,
- const double dbl)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astExpressionFloatLiteral,
- MOJOSHADER_AST_OP_FLOAT_LITERAL);
- retval->datatype = &ctx->dt_float;
- retval->value = dbl;
- return (MOJOSHADER_astExpression *) retval;
- } // new_literal_float_expr
- static MOJOSHADER_astExpression *new_literal_string_expr(Context *ctx,
- const char *string)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astExpressionStringLiteral,
- MOJOSHADER_AST_OP_STRING_LITERAL);
- retval->datatype = &ctx->dt_string;
- retval->string = string; // cached; don't copy string.
- return (MOJOSHADER_astExpression *) retval;
- } // new_literal_string_expr
- static MOJOSHADER_astExpression *new_literal_boolean_expr(Context *ctx,
- const int value)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astExpressionBooleanLiteral,
- MOJOSHADER_AST_OP_BOOLEAN_LITERAL);
- retval->datatype = &ctx->dt_bool;
- retval->value = value;
- return (MOJOSHADER_astExpression *) retval;
- } // new_literal_boolean_expr
- static void delete_arguments(Context *ctx, MOJOSHADER_astArguments *args);
- static void delete_expr(Context *ctx, MOJOSHADER_astExpression *_expr)
- {
- MOJOSHADER_astNode *expr = (MOJOSHADER_astNode *) _expr;
- DELETE_AST_NODE(expr);
- if (expr->ast.type == MOJOSHADER_AST_OP_CAST)
- delete_expr(ctx, expr->cast.operand);
- else if (expr->ast.type == MOJOSHADER_AST_OP_CONSTRUCTOR)
- delete_arguments(ctx, expr->constructor.args);
- else if (expr->ast.type == MOJOSHADER_AST_OP_DEREF_STRUCT)
- delete_expr(ctx, expr->derefstruct.identifier);
- else if (operator_is_unary(expr->ast.type))
- delete_expr(ctx, expr->unary.operand);
- else if (operator_is_binary(expr->ast.type))
- {
- delete_expr(ctx, expr->binary.left);
- delete_expr(ctx, expr->binary.right);
- } // else if
- else if (operator_is_ternary(expr->ast.type))
- {
- delete_expr(ctx, expr->ternary.left);
- delete_expr(ctx, expr->ternary.center);
- delete_expr(ctx, expr->ternary.right);
- } // else if
- else if (expr->ast.type == MOJOSHADER_AST_OP_CALLFUNC)
- {
- delete_expr(ctx, (MOJOSHADER_astExpression*)expr->callfunc.identifier);
- delete_arguments(ctx, expr->callfunc.args);
- } // else if
- // rest of operators don't have extra data to free.
- Free(ctx, expr);
- } // delete_expr
- static MOJOSHADER_astArguments *new_argument(Context *ctx,
- MOJOSHADER_astExpression *arg)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astArguments, MOJOSHADER_AST_ARGUMENTS);
- retval->argument = arg;
- retval->next = NULL;
- return retval;
- } // new_argument
- static void delete_arguments(Context *ctx, MOJOSHADER_astArguments *args)
- {
- DELETE_AST_NODE(args);
- delete_arguments(ctx, args->next);
- delete_expr(ctx, args->argument);
- Free(ctx, args);
- } // delete_arguments
- static MOJOSHADER_astFunctionParameters *new_function_param(Context *ctx,
- const MOJOSHADER_astInputModifier inputmod,
- const MOJOSHADER_astDataType *dt,
- const char *identifier, const char *semantic,
- const MOJOSHADER_astInterpolationModifier interpmod,
- MOJOSHADER_astExpression *initializer)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astFunctionParameters,
- MOJOSHADER_AST_FUNCTION_PARAMS);
- retval->datatype = dt;
- retval->input_modifier = inputmod;
- retval->identifier = identifier;
- retval->semantic = semantic;
- retval->interpolation_modifier = interpmod;
- retval->initializer = initializer;
- retval->next = NULL;
- return retval;
- } // new_function_param
- static void delete_function_params(Context *ctx,
- MOJOSHADER_astFunctionParameters *params)
- {
- DELETE_AST_NODE(params);
- delete_function_params(ctx, params->next);
- delete_expr(ctx, params->initializer);
- Free(ctx, params);
- } // delete_function_params
- static MOJOSHADER_astFunctionSignature *new_function_signature(Context *ctx,
- const MOJOSHADER_astDataType *dt,
- const char *identifier,
- MOJOSHADER_astFunctionParameters *params)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astFunctionSignature,
- MOJOSHADER_AST_FUNCTION_SIGNATURE);
- retval->datatype = dt;
- retval->identifier = identifier;
- retval->params = params;
- retval->storage_class = MOJOSHADER_AST_FNSTORECLS_NONE;
- retval->semantic = NULL;
- return retval;
- } // new_function_signature
- static void delete_function_signature(Context *ctx,
- MOJOSHADER_astFunctionSignature *sig)
- {
- DELETE_AST_NODE(sig);
- delete_function_params(ctx, sig->params);
- Free(ctx, sig);
- } // delete_function_signature
- static MOJOSHADER_astCompilationUnit *new_function(Context *ctx,
- MOJOSHADER_astFunctionSignature *declaration,
- MOJOSHADER_astStatement *definition)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitFunction,
- MOJOSHADER_AST_COMPUNIT_FUNCTION);
- retval->next = NULL;
- retval->declaration = declaration;
- retval->definition = definition;
- retval->index = 0;
- return (MOJOSHADER_astCompilationUnit *) retval;
- } // new_function
- static void delete_function(Context *ctx,
- MOJOSHADER_astCompilationUnitFunction *unitfn)
- {
- DELETE_AST_NODE(unitfn);
- delete_compilation_unit(ctx, unitfn->next);
- delete_function_signature(ctx, unitfn->declaration);
- delete_statement(ctx, unitfn->definition);
- Free(ctx, unitfn);
- } // delete_function
- static MOJOSHADER_astScalarOrArray *new_scalar_or_array(Context *ctx,
- const char *ident, const int isvec,
- MOJOSHADER_astExpression *dim)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astScalarOrArray,
- MOJOSHADER_AST_SCALAR_OR_ARRAY);
- retval->identifier = ident;
- retval->isarray = isvec;
- retval->dimension = dim;
- return retval;
- } // new_scalar_or_array
- static void delete_scalar_or_array(Context *ctx,MOJOSHADER_astScalarOrArray *s)
- {
- DELETE_AST_NODE(s);
- delete_expr(ctx, s->dimension);
- Free(ctx, s);
- } // delete_scalar_or_array
- static MOJOSHADER_astTypedef *new_typedef(Context *ctx, const int isconst,
- const MOJOSHADER_astDataType *dt,
- MOJOSHADER_astScalarOrArray *soa)
- {
- // we correct this datatype to the final version during semantic analysis.
- NEW_AST_NODE(retval, MOJOSHADER_astTypedef, MOJOSHADER_AST_TYPEDEF);
- retval->datatype = dt;
- retval->isconst = isconst;
- retval->details = soa;
- return retval;
- } // new_typedef
- static void delete_typedef(Context *ctx, MOJOSHADER_astTypedef *td)
- {
- DELETE_AST_NODE(td);
- delete_scalar_or_array(ctx, td->details);
- Free(ctx, td);
- } // delete_typedef
- static MOJOSHADER_astPackOffset *new_pack_offset(Context *ctx,
- const char *a, const char *b)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astPackOffset, MOJOSHADER_AST_PACK_OFFSET);
- retval->ident1 = a;
- retval->ident2 = b;
- return retval;
- } // new_pack_offset
- static void delete_pack_offset(Context *ctx, MOJOSHADER_astPackOffset *o)
- {
- DELETE_AST_NODE(o);
- Free(ctx, o);
- } // delete_pack_offset
- static MOJOSHADER_astVariableLowLevel *new_variable_lowlevel(Context *ctx,
- MOJOSHADER_astPackOffset *po,
- const char *reg)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astVariableLowLevel,
- MOJOSHADER_AST_VARIABLE_LOWLEVEL);
- retval->packoffset = po;
- retval->register_name = reg;
- return retval;
- } // new_variable_lowlevel
- static void delete_variable_lowlevel(Context *ctx,
- MOJOSHADER_astVariableLowLevel *vll)
- {
- DELETE_AST_NODE(vll);
- delete_pack_offset(ctx, vll->packoffset);
- Free(ctx, vll);
- } // delete_variable_lowlevel
- static MOJOSHADER_astAnnotations *new_annotation(Context *ctx,
- const MOJOSHADER_astDataType *dt,
- MOJOSHADER_astExpression *initializer)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astAnnotations, MOJOSHADER_AST_ANNOTATION);
- retval->datatype = dt;
- retval->initializer = initializer;
- retval->next = NULL;
- return retval;
- } // new_annotation
- static void delete_annotation(Context *ctx, MOJOSHADER_astAnnotations *annos)
- {
- DELETE_AST_NODE(annos);
- delete_annotation(ctx, annos->next);
- delete_expr(ctx, annos->initializer);
- Free(ctx, annos);
- } // delete_annotation
- static MOJOSHADER_astVariableDeclaration *new_variable_declaration(
- Context *ctx, MOJOSHADER_astScalarOrArray *soa,
- const char *semantic,
- MOJOSHADER_astAnnotations *annotations,
- MOJOSHADER_astExpression *init,
- MOJOSHADER_astVariableLowLevel *vll)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astVariableDeclaration,
- MOJOSHADER_AST_VARIABLE_DECLARATION);
- retval->datatype = NULL;
- retval->attributes = 0;
- retval->anonymous_datatype = NULL;
- retval->details = soa;
- retval->semantic = semantic;
- retval->annotations = annotations;
- retval->initializer = init;
- retval->lowlevel = vll;
- retval->next = NULL;
- return retval;
- } // new_variable_declaration
- static void delete_variable_declaration(Context *ctx,
- MOJOSHADER_astVariableDeclaration *dcl)
- {
- DELETE_AST_NODE(dcl);
- delete_variable_declaration(ctx, dcl->next);
- delete_scalar_or_array(ctx, dcl->details);
- delete_annotation(ctx, dcl->annotations);
- delete_expr(ctx, dcl->initializer);
- delete_variable_lowlevel(ctx, dcl->lowlevel);
- Free(ctx, dcl);
- } // delete_variable_declaration
- static MOJOSHADER_astCompilationUnit *new_global_variable(Context *ctx,
- MOJOSHADER_astVariableDeclaration *decl)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitVariable,
- MOJOSHADER_AST_COMPUNIT_VARIABLE);
- retval->next = NULL;
- retval->declaration = decl;
- return (MOJOSHADER_astCompilationUnit *) retval;
- } // new_global_variable
- static void delete_global_variable(Context *ctx,
- MOJOSHADER_astCompilationUnitVariable *var)
- {
- DELETE_AST_NODE(var);
- delete_compilation_unit(ctx, var->next);
- delete_variable_declaration(ctx, var->declaration);
- Free(ctx, var);
- } // delete_global_variable
- static MOJOSHADER_astCompilationUnit *new_global_typedef(Context *ctx,
- MOJOSHADER_astTypedef *td)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitTypedef,
- MOJOSHADER_AST_COMPUNIT_TYPEDEF);
- retval->next = NULL;
- retval->type_info = td;
- return (MOJOSHADER_astCompilationUnit *) retval;
- } // new_global_typedef
- static void delete_global_typedef(Context *ctx,
- MOJOSHADER_astCompilationUnitTypedef *unit)
- {
- DELETE_AST_NODE(unit);
- delete_compilation_unit(ctx, unit->next);
- delete_typedef(ctx, unit->type_info);
- Free(ctx, unit);
- } // delete_global_typedef
- static MOJOSHADER_astStructMembers *new_struct_member(Context *ctx,
- MOJOSHADER_astScalarOrArray *soa,
- const char *semantic)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astStructMembers,
- MOJOSHADER_AST_STRUCT_MEMBER);
- retval->datatype = NULL;
- retval->semantic = semantic;
- retval->details = soa;
- retval->interpolation_mod = MOJOSHADER_AST_INTERPMOD_NONE;
- retval->next = NULL;
- return retval;
- } // new_struct_member
- static void delete_struct_member(Context *ctx,
- MOJOSHADER_astStructMembers *member)
- {
- DELETE_AST_NODE(member);
- delete_struct_member(ctx, member->next);
- delete_scalar_or_array(ctx, member->details);
- Free(ctx, member);
- } // delete_struct_member
- static MOJOSHADER_astStructDeclaration *new_struct_declaration(Context *ctx,
- const char *name,
- MOJOSHADER_astStructMembers *members)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astStructDeclaration,
- MOJOSHADER_AST_STRUCT_DECLARATION);
- retval->datatype = NULL;
- retval->name = name;
- retval->members = members;
- return retval;
- } // new_struct_declaration
- static void delete_struct_declaration(Context *ctx,
- MOJOSHADER_astStructDeclaration *decl)
- {
- DELETE_AST_NODE(decl);
- delete_struct_member(ctx, decl->members);
- Free(ctx, decl);
- } // delete_struct_declaration
- static MOJOSHADER_astCompilationUnit *new_global_struct(Context *ctx,
- MOJOSHADER_astStructDeclaration *sd)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitStruct,
- MOJOSHADER_AST_COMPUNIT_STRUCT);
- retval->next = NULL;
- retval->struct_info = sd;
- return (MOJOSHADER_astCompilationUnit *) retval;
- } // new_global_struct
- static void delete_global_struct(Context *ctx,
- MOJOSHADER_astCompilationUnitStruct *unit)
- {
- DELETE_AST_NODE(unit);
- delete_compilation_unit(ctx, unit->next);
- delete_struct_declaration(ctx, unit->struct_info);
- Free(ctx, unit);
- } // delete_global_struct
- static void delete_compilation_unit(Context *ctx,
- MOJOSHADER_astCompilationUnit *unit)
- {
- if (!unit) return;
- // it's important to not recurse too deeply here, since you may have
- // thousands of items in this linked list (each line of a massive
- // function, for example). To avoid this, we iterate the list here,
- // deleting all children and making them think they have no reason
- // to recurse in their own delete methods.
- // Please note that everyone should _try_ to delete their "next" member,
- // just in case, but hopefully this cleaned it out.
- MOJOSHADER_astCompilationUnit *i = unit->next;
- unit->next = NULL;
- while (i)
- {
- MOJOSHADER_astCompilationUnit *next = i->next;
- i->next = NULL;
- delete_compilation_unit(ctx, i);
- i = next;
- } // while
- switch (unit->ast.type)
- {
- #define DELETE_UNIT(typ, cls, fn) \
- case MOJOSHADER_AST_COMPUNIT_##typ: delete_##fn(ctx, (cls *) unit); break;
- DELETE_UNIT(FUNCTION, MOJOSHADER_astCompilationUnitFunction, function);
- DELETE_UNIT(TYPEDEF, MOJOSHADER_astCompilationUnitTypedef, global_typedef);
- DELETE_UNIT(VARIABLE, MOJOSHADER_astCompilationUnitVariable, global_variable);
- DELETE_UNIT(STRUCT, MOJOSHADER_astCompilationUnitStruct, global_struct);
- #undef DELETE_UNIT
- default: assert(0 && "missing cleanup code"); break;
- } // switch
- // don't free (unit) here, the class-specific functions do it.
- } // delete_compilation_unit
- static MOJOSHADER_astStatement *new_typedef_statement(Context *ctx,
- MOJOSHADER_astTypedef *td)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astTypedefStatement,
- MOJOSHADER_AST_STATEMENT_TYPEDEF);
- retval->next = NULL;
- retval->type_info = td;
- return (MOJOSHADER_astStatement *) retval;
- } // new_typedef_statement
- static void delete_typedef_statement(Context *ctx,
- MOJOSHADER_astTypedefStatement *stmt)
- {
- DELETE_AST_NODE(stmt);
- delete_statement(ctx, stmt->next);
- delete_typedef(ctx, stmt->type_info);
- Free(ctx, stmt);
- } // delete_typedef_statement
- static MOJOSHADER_astStatement *new_return_statement(Context *ctx,
- MOJOSHADER_astExpression *expr)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astReturnStatement,
- MOJOSHADER_AST_STATEMENT_RETURN);
- retval->next = NULL;
- retval->expr = expr;
- return (MOJOSHADER_astStatement *) retval;
- } // new_return_statement
- static void delete_return_statement(Context *ctx,
- MOJOSHADER_astReturnStatement *stmt)
- {
- DELETE_AST_NODE(stmt);
- delete_statement(ctx, stmt->next);
- delete_expr(ctx, stmt->expr);
- Free(ctx, stmt);
- } // delete_return_statement
- static MOJOSHADER_astStatement *new_block_statement(Context *ctx,
- MOJOSHADER_astStatement *stmts)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astBlockStatement,
- MOJOSHADER_AST_STATEMENT_BLOCK);
- retval->next = NULL;
- retval->statements = stmts;
- return (MOJOSHADER_astStatement *) retval;
- } // new_block_statement
- static void delete_block_statement(Context *ctx,
- MOJOSHADER_astBlockStatement *stmt)
- {
- DELETE_AST_NODE(stmt);
- delete_statement(ctx, stmt->statements);
- delete_statement(ctx, stmt->next);
- Free(ctx, stmt);
- } // delete_statement_block
- static MOJOSHADER_astStatement *new_for_statement(Context *ctx,
- MOJOSHADER_astVariableDeclaration *decl,
- MOJOSHADER_astExpression *initializer,
- MOJOSHADER_astExpression *looptest,
- MOJOSHADER_astExpression *counter,
- MOJOSHADER_astStatement *statement)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astForStatement,
- MOJOSHADER_AST_STATEMENT_FOR);
- retval->next = NULL;
- retval->unroll = -1;
- retval->var_decl = decl;
- retval->initializer = initializer;
- retval->looptest = looptest;
- retval->counter = counter;
- retval->statement = statement;
- return (MOJOSHADER_astStatement *) retval;
- } // new_for_statement
- static void delete_for_statement(Context *ctx,MOJOSHADER_astForStatement *stmt)
- {
- DELETE_AST_NODE(stmt);
- delete_statement(ctx, stmt->next);
- delete_variable_declaration(ctx, stmt->var_decl);
- delete_expr(ctx, stmt->initializer);
- delete_expr(ctx, stmt->looptest);
- delete_expr(ctx, stmt->counter);
- delete_statement(ctx, stmt->statement);
- Free(ctx, stmt);
- } // delete_for_statement
- static MOJOSHADER_astStatement *new_do_statement(Context *ctx,
- const int unroll,
- MOJOSHADER_astStatement *stmt,
- MOJOSHADER_astExpression *expr)
- {
- NEW_AST_NODE(retval,MOJOSHADER_astDoStatement,MOJOSHADER_AST_STATEMENT_DO);
- retval->next = NULL;
- retval->unroll = unroll;
- retval->expr = expr;
- retval->statement = stmt;
- return (MOJOSHADER_astStatement *) retval;
- } // new_do_statement
- static void delete_do_statement(Context *ctx, MOJOSHADER_astDoStatement *stmt)
- {
- DELETE_AST_NODE(stmt);
- delete_statement(ctx, stmt->next);
- delete_statement(ctx, stmt->statement);
- delete_expr(ctx, stmt->expr);
- Free(ctx, stmt);
- } // delete_do_statement
- static MOJOSHADER_astStatement *new_while_statement(Context *ctx,
- const int unroll,
- MOJOSHADER_astExpression *expr,
- MOJOSHADER_astStatement *stmt)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astWhileStatement,
- MOJOSHADER_AST_STATEMENT_WHILE);
- retval->next = NULL;
- retval->unroll = unroll;
- retval->expr = expr;
- retval->statement = stmt;
- return (MOJOSHADER_astStatement *) retval;
- } // new_while_statement
- static void delete_while_statement(Context *ctx,
- MOJOSHADER_astWhileStatement *stmt)
- {
- DELETE_AST_NODE(stmt);
- delete_statement(ctx, stmt->next);
- delete_statement(ctx, stmt->statement);
- delete_expr(ctx, stmt->expr);
- Free(ctx, stmt);
- } // delete_while_statement
- static MOJOSHADER_astStatement *new_if_statement(Context *ctx,
- const int attr,
- MOJOSHADER_astExpression *expr,
- MOJOSHADER_astStatement *stmt,
- MOJOSHADER_astStatement *elsestmt)
- {
- NEW_AST_NODE(retval,MOJOSHADER_astIfStatement,MOJOSHADER_AST_STATEMENT_IF);
- retval->next = NULL;
- retval->attributes = attr;
- retval->expr = expr;
- retval->statement = stmt;
- retval->else_statement = elsestmt;
- return (MOJOSHADER_astStatement *) retval;
- } // new_if_statement
- static void delete_if_statement(Context *ctx, MOJOSHADER_astIfStatement *stmt)
- {
- DELETE_AST_NODE(stmt);
- delete_statement(ctx, stmt->next);
- delete_expr(ctx, stmt->expr);
- delete_statement(ctx, stmt->statement);
- delete_statement(ctx, stmt->else_statement);
- Free(ctx, stmt);
- } // delete_if_statement
- static MOJOSHADER_astSwitchCases *new_switch_case(Context *ctx,
- MOJOSHADER_astExpression *expr,
- MOJOSHADER_astStatement *stmt)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astSwitchCases, MOJOSHADER_AST_SWITCH_CASE);
- retval->expr = expr;
- retval->statement = stmt;
- retval->next = NULL;
- return retval;
- } // new_switch_case
- static void delete_switch_case(Context *ctx, MOJOSHADER_astSwitchCases *sc)
- {
- DELETE_AST_NODE(sc);
- delete_switch_case(ctx, sc->next);
- delete_expr(ctx, sc->expr);
- delete_statement(ctx, sc->statement);
- Free(ctx, sc);
- } // delete_switch_case
- static MOJOSHADER_astStatement *new_empty_statement(Context *ctx)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astEmptyStatement,
- MOJOSHADER_AST_STATEMENT_EMPTY);
- retval->next = NULL;
- return (MOJOSHADER_astStatement *) retval;
- } // new_empty_statement
- static void delete_empty_statement(Context *ctx,
- MOJOSHADER_astEmptyStatement *stmt)
- {
- DELETE_AST_NODE(stmt);
- delete_statement(ctx, stmt->next);
- Free(ctx, stmt);
- } // delete_empty_statement
- static MOJOSHADER_astStatement *new_break_statement(Context *ctx)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astBreakStatement,
- MOJOSHADER_AST_STATEMENT_BREAK);
- retval->next = NULL;
- return (MOJOSHADER_astStatement *) retval;
- } // new_break_statement
- static void delete_break_statement(Context *ctx,
- MOJOSHADER_astBreakStatement *stmt)
- {
- DELETE_AST_NODE(stmt);
- delete_statement(ctx, stmt->next);
- Free(ctx, stmt);
- } // delete_break_statement
- static MOJOSHADER_astStatement *new_continue_statement(Context *ctx)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astContinueStatement,
- MOJOSHADER_AST_STATEMENT_CONTINUE);
- retval->next = NULL;
- return (MOJOSHADER_astStatement *) retval;
- } // new_continue_statement
- static void delete_continue_statement(Context *ctx,
- MOJOSHADER_astContinueStatement *stmt)
- {
- DELETE_AST_NODE(stmt);
- delete_statement(ctx, stmt->next);
- Free(ctx, stmt);
- } // delete_continue_statement
- static MOJOSHADER_astStatement *new_discard_statement(Context *ctx)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astDiscardStatement,
- MOJOSHADER_AST_STATEMENT_DISCARD);
- retval->next = NULL;
- return (MOJOSHADER_astStatement *) retval;
- } // new_discard_statement
- static void delete_discard_statement(Context *ctx,
- MOJOSHADER_astDiscardStatement *stmt)
- {
- DELETE_AST_NODE(stmt);
- delete_statement(ctx, stmt->next);
- Free(ctx, stmt);
- } // delete_discard_statement
- static MOJOSHADER_astStatement *new_expr_statement(Context *ctx,
- MOJOSHADER_astExpression *expr)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astExpressionStatement,
- MOJOSHADER_AST_STATEMENT_EXPRESSION);
- retval->next = NULL;
- retval->expr = expr;
- return (MOJOSHADER_astStatement *) retval;
- } // new_expr_statement
- static void delete_expr_statement(Context *ctx,
- MOJOSHADER_astExpressionStatement *stmt)
- {
- DELETE_AST_NODE(stmt);
- delete_statement(ctx, stmt->next);
- delete_expr(ctx, stmt->expr);
- Free(ctx, stmt);
- } // delete_expr_statement
- static MOJOSHADER_astStatement *new_switch_statement(Context *ctx,
- const int attr,
- MOJOSHADER_astExpression *expr,
- MOJOSHADER_astSwitchCases *cases)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astSwitchStatement,
- MOJOSHADER_AST_STATEMENT_SWITCH);
- retval->next = NULL;
- retval->attributes = attr;
- retval->expr = expr;
- retval->cases = cases;
- return (MOJOSHADER_astStatement *) retval;
- } // new_switch_statement
- static void delete_switch_statement(Context *ctx,
- MOJOSHADER_astSwitchStatement *stmt)
- {
- DELETE_AST_NODE(stmt);
- delete_expr(ctx, stmt->expr);
- delete_switch_case(ctx, stmt->cases);
- Free(ctx, stmt);
- } // delete_switch_statement
- static MOJOSHADER_astStatement *new_struct_statement(Context *ctx,
- MOJOSHADER_astStructDeclaration *sd)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astStructStatement,
- MOJOSHADER_AST_STATEMENT_STRUCT);
- retval->next = NULL;
- retval->struct_info = sd;
- return (MOJOSHADER_astStatement *) retval;
- } // new_struct_statement
- static void delete_struct_statement(Context *ctx,
- MOJOSHADER_astStructStatement *stmt)
- {
- DELETE_AST_NODE(stmt);
- delete_statement(ctx, stmt->next);
- delete_struct_declaration(ctx, stmt->struct_info);
- Free(ctx, stmt);
- } // delete_struct_statement
- static MOJOSHADER_astStatement *new_vardecl_statement(Context *ctx,
- MOJOSHADER_astVariableDeclaration *vd)
- {
- NEW_AST_NODE(retval, MOJOSHADER_astVarDeclStatement,
- MOJOSHADER_AST_STATEMENT_VARDECL);
- retval->next = NULL;
- retval->declaration = vd;
- return (MOJOSHADER_astStatement *) retval;
- } // new_vardecl_statement
- static void delete_vardecl_statement(Context *ctx,
- MOJOSHADER_astVarDeclStatement *stmt)
- {
- DELETE_AST_NODE(stmt);
- delete_statement(ctx, stmt->next);
- delete_variable_declaration(ctx, stmt->declaration);
- Free(ctx, stmt);
- } // delete_vardecl_statement
- static void delete_statement(Context *ctx, MOJOSHADER_astStatement *stmt)
- {
- if (!stmt) return;
- // it's important to not recurse too deeply here, since you may have
- // thousands of items in this linked list (each line of a massive
- // function, for example). To avoid this, we iterate the list here,
- // deleting all children and making them think they have no reason
- // to recurse in their own delete methods.
- // Please note that everyone should _try_ to delete their "next" member,
- // just in case, but hopefully this cleaned it out.
- MOJOSHADER_astStatement *i = stmt->next;
- stmt->next = NULL;
- while (i)
- {
- MOJOSHADER_astStatement *next = i->next;
- i->next = NULL;
- delete_statement(ctx, i);
- i = next;
- } // while
- switch (stmt->ast.type)
- {
- #define DELETE_STATEMENT(typ, cls, fn) \
- case MOJOSHADER_AST_STATEMENT_##typ: \
- delete_##fn##_statement(ctx, (cls *) stmt); break;
- DELETE_STATEMENT(BLOCK, MOJOSHADER_astBlockStatement, block);
- DELETE_STATEMENT(EMPTY, MOJOSHADER_astEmptyStatement, empty);
- DELETE_STATEMENT(IF, MOJOSHADER_astIfStatement, if);
- DELETE_STATEMENT(SWITCH, MOJOSHADER_astSwitchStatement, switch);
- DELETE_STATEMENT(EXPRESSION, MOJOSHADER_astExpressionStatement, expr);
- DELETE_STATEMENT(FOR, MOJOSHADER_astForStatement, for);
- DELETE_STATEMENT(DO, MOJOSHADER_astDoStatement, do);
- DELETE_STATEMENT(WHILE, MOJOSHADER_astWhileStatement, while);
- DELETE_STATEMENT(RETURN, MOJOSHADER_astReturnStatement, return);
- DELETE_STATEMENT(BREAK, MOJOSHADER_astBreakStatement, break);
- DELETE_STATEMENT(CONTINUE, MOJOSHADER_astContinueStatement, continue);
- DELETE_STATEMENT(DISCARD, MOJOSHADER_astDiscardStatement, discard);
- DELETE_STATEMENT(TYPEDEF, MOJOSHADER_astTypedefStatement, typedef);
- DELETE_STATEMENT(STRUCT, MOJOSHADER_astStructStatement, struct);
- DELETE_STATEMENT(VARDECL, MOJOSHADER_astVarDeclStatement, vardecl);
- #undef DELETE_STATEMENT
- default: assert(0 && "missing cleanup code"); break;
- } // switch
- // don't free (stmt) here, the class-specific functions do it.
- } // delete_statement
- static const MOJOSHADER_astDataType *get_usertype(const Context *ctx,
- const char *token)
- {
- const void *value; // search all scopes.
- if (!hash_find(ctx->usertypes.hash, token, &value))
- return NULL;
- return value ? ((SymbolScope *) value)->datatype : NULL;
- } // get_usertype
- // This is where the actual parsing happens. It's Lemon-generated!
- #define __MOJOSHADER_HLSL_COMPILER__ 1
- #include "mojoshader_parser_hlsl.h"
- #if 0
- static int expr_is_constant(MOJOSHADER_astExpression *expr)
- {
- const MOJOSHADER_astNodeType op = expr->ast.type;
- if (operator_is_unary(op))
- return expr_is_constant(expr->unary.operand);
- else if (operator_is_binary(op))
- {
- return ( expr_is_constant(expr->binary.left) &&
- expr_is_constant(expr->binary.right) );
- } // else if
- else if (operator_is_ternary(op))
- {
- return ( expr_is_constant(expr->ternary.left) &&
- expr_is_constant(expr->ternary.center) &&
- expr_is_constant(expr->ternary.right) );
- } // else if
- return ( (op == MOJOSHADER_AST_OP_INT_LITERAL) ||
- (op == MOJOSHADER_AST_OP_FLOAT_LITERAL) ||
- (op == MOJOSHADER_AST_OP_STRING_LITERAL) ||
- (op == MOJOSHADER_AST_OP_BOOLEAN_LITERAL) );
- } // expr_is_constant
- #endif
- typedef struct AstCalcData
- {
- int isflt;
- union
- {
- double f;
- int64 i;
- } value;
- } AstCalcData;
- // returns 0 if this expression is non-constant, 1 if it is.
- // calculation results land in (data).
- static int calc_ast_const_expr(Context *ctx, void *_expr, AstCalcData *data)
- {
- const MOJOSHADER_astNode *expr = (MOJOSHADER_astNode *) _expr;
- const MOJOSHADER_astNodeType op = expr->ast.type;
- ctx->sourcefile = expr->ast.filename;
- ctx->sourceline = expr->ast.line;
- if (operator_is_unary(op))
- {
- if (!calc_ast_const_expr(ctx, expr->unary.operand, data))
- return 0;
- if (data->isflt)
- {
- switch (op)
- {
- case MOJOSHADER_AST_OP_NEGATE:
- data->value.f = -data->value.f;
- return 1;
- case MOJOSHADER_AST_OP_NOT:
- data->value.f = !data->value.f;
- return 1;
- case MOJOSHADER_AST_OP_COMPLEMENT:
- fail(ctx, "integer operation on floating point value");
- return 0;
- case MOJOSHADER_AST_OP_CAST:
- // !!! FIXME: this should work, but it's complicated.
- assert(0 && "write me");
- return 0;
- default: break;
- } // switch
- } // if
- else // integer version
- {
- switch (op)
- {
- case MOJOSHADER_AST_OP_NEGATE:
- data->value.i = -data->value.i;
- return 1;
- case MOJOSHADER_AST_OP_NOT:
- data->value.i = !data->value.i;
- return 1;
- case MOJOSHADER_AST_OP_COMPLEMENT:
- data->value.i = ~data->value.i;
- return 1;
- case MOJOSHADER_AST_OP_CAST:
- // !!! FIXME: this should work, but it's complicated.
- assert(0 && "write me");
- return 0;
- default: break;
- } // switch
- } // else
- assert(0 && "unhandled operation?");
- return 0;
- } // if
- else if (operator_is_binary(op))
- {
- AstCalcData subdata2;
- if ( (!calc_ast_const_expr(ctx, expr->binary.left, data)) ||
- (!calc_ast_const_expr(ctx, expr->binary.right, &subdata2)) )
- return 0;
- // upgrade to float if either operand is float.
- if ((data->isflt) || (subdata2.isflt))
- {
- if (!data->isflt) data->value.f = (double) data->value.i;
- if (!subdata2.isflt) subdata2.value.f = (double) subdata2.value.i;
- data->isflt = subdata2.isflt = 1;
- } // if
- switch (op)
- {
- // gcc doesn't handle commas here, either (fails to parse!).
- case MOJOSHADER_AST_OP_COMMA:
- case MOJOSHADER_AST_OP_ASSIGN:
- case MOJOSHADER_AST_OP_MULASSIGN:
- case MOJOSHADER_AST_OP_DIVASSIGN:
- case MOJOSHADER_AST_OP_MODASSIGN:
- case MOJOSHADER_AST_OP_ADDASSIGN:
- case MOJOSHADER_AST_OP_SUBASSIGN:
- case MOJOSHADER_AST_OP_LSHIFTASSIGN:
- case MOJOSHADER_AST_OP_RSHIFTASSIGN:
- case MOJOSHADER_AST_OP_ANDASSIGN:
- case MOJOSHADER_AST_OP_XORASSIGN:
- case MOJOSHADER_AST_OP_ORASSIGN:
- return 0; // assignment is non-constant.
- default: break;
- } // switch
- if (data->isflt)
- {
- switch (op)
- {
- case MOJOSHADER_AST_OP_MULTIPLY:
- data->value.f *= subdata2.value.f;
- return 1;
- case MOJOSHADER_AST_OP_DIVIDE:
- data->value.f /= subdata2.value.f;
- return 1;
- case MOJOSHADER_AST_OP_ADD:
- data->value.f += subdata2.value.f;
- return 1;
- case MOJOSHADER_AST_OP_SUBTRACT:
- data->value.f -= subdata2.value.f;
- return 1;
- case MOJOSHADER_AST_OP_LESSTHAN:
- data->isflt = 0;
- data->value.i = data->value.f < subdata2.value.f;
- return 1;
- case MOJOSHADER_AST_OP_GREATERTHAN:
- data->isflt = 0;
- data->value.i = data->value.f > subdata2.value.f;
- return 1;
- case MOJOSHADER_AST_OP_LESSTHANOREQUAL:
- data->isflt = 0;
- data->value.i = data->value.f <= subdata2.value.f;
- return 1;
- case MOJOSHADER_AST_OP_GREATERTHANOREQUAL:
- data->isflt = 0;
- data->value.i = data->value.f >= subdata2.value.f;
- return 1;
- case MOJOSHADER_AST_OP_EQUAL:
- data->isflt = 0;
- data->value.i = data->value.f == subdata2.value.f;
- return 1;
- case MOJOSHADER_AST_OP_NOTEQUAL:
- data->isflt = 0;
- data->value.i = data->value.f != subdata2.value.f;
- return 1;
- case MOJOSHADER_AST_OP_LOGICALAND:
- data->isflt = 0;
- data->value.i = data->value.f && subdata2.value.f;
- return 1;
- case MOJOSHADER_AST_OP_LOGICALOR:
- data->isflt = 0;
- data->value.i = data->value.f || subdata2.value.f;
- return 1;
- case MOJOSHADER_AST_OP_LSHIFT:
- case MOJOSHADER_AST_OP_RSHIFT:
- case MOJOSHADER_AST_OP_MODULO:
- case MOJOSHADER_AST_OP_BINARYAND:
- case MOJOSHADER_AST_OP_BINARYXOR:
- case MOJOSHADER_AST_OP_BINARYOR:
- fail(ctx, "integer operation on floating point value");
- return 0;
- default: break;
- } // switch
- } // if
- else // integer version.
- {
- switch (op)
- {
- case MOJOSHADER_AST_OP_MULTIPLY:
- data->value.i *= subdata2.value.i;
- return 1;
- case MOJOSHADER_AST_OP_DIVIDE:
- data->value.i /= subdata2.value.i;
- return 1;
- case MOJOSHADER_AST_OP_ADD:
- data->value.i += subdata2.value.i;
- return 1;
- case MOJOSHADER_AST_OP_SUBTRACT:
- data->value.i -= subdata2.value.i;
- return 1;
- case MOJOSHADER_AST_OP_LESSTHAN:
- data->value.i = data->value.i < subdata2.value.i;
- return 1;
- case MOJOSHADER_AST_OP_GREATERTHAN:
- data->value.i = data->value.i > subdata2.value.i;
- return 1;
- case MOJOSHADER_AST_OP_LESSTHANOREQUAL:
- data->value.i = data->value.i <= subdata2.value.i;
- return 1;
- case MOJOSHADER_AST_OP_GREATERTHANOREQUAL:
- data->value.i = data->value.i >= subdata2.value.i;
- return 1;
- case MOJOSHADER_AST_OP_EQUAL:
- data->value.i = data->value.i == subdata2.value.i;
- return 1;
- case MOJOSHADER_AST_OP_NOTEQUAL:
- data->value.i = data->value.i != subdata2.value.i;
- return 1;
- case MOJOSHADER_AST_OP_LOGICALAND:
- data->value.i = data->value.i && subdata2.value.i;
- return 1;
- case MOJOSHADER_AST_OP_LOGICALOR:
- data->value.i = data->value.i || subdata2.value.i;
- return 1;
- case MOJOSHADER_AST_OP_LSHIFT:
- data->value.i = data->value.i << subdata2.value.i;
- return 1;
- case MOJOSHADER_AST_OP_RSHIFT:
- data->value.i = data->value.i >> subdata2.value.i;
- return 1;
- case MOJOSHADER_AST_OP_MODULO:
- data->value.i = data->value.i % subdata2.value.i;
- return 1;
- case MOJOSHADER_AST_OP_BINARYAND:
- data->value.i = data->value.i & subdata2.value.i;
- return 1;
- case MOJOSHADER_AST_OP_BINARYXOR:
- data->value.i = data->value.i ^ subdata2.value.i;
- return 1;
- case MOJOSHADER_AST_OP_BINARYOR:
- data->value.i = data->value.i | subdata2.value.i;
- return 1;
- default: break;
- } // switch
- } // else
- assert(0 && "unhandled operation?");
- return 0;
- } // else if
- else if (operator_is_ternary(op))
- {
- AstCalcData subdata2;
- AstCalcData subdata3;
- assert(op == MOJOSHADER_AST_OP_CONDITIONAL); // only one we have.
- if ( (!calc_ast_const_expr(ctx, expr->ternary.left, data)) ||
- (!calc_ast_const_expr(ctx, expr->ternary.center, &subdata2)) ||
- (!calc_ast_const_expr(ctx, expr->ternary.right, &subdata3)) )
- return 0;
- // first operand should be bool (for the one ternary operator we have).
- if (data->isflt)
- {
- data->isflt = 0;
- data->value.i = (int64) subdata3.value.f;
- } // if
- // upgrade to float if either operand is float.
- if ((subdata2.isflt) || (subdata3.isflt))
- {
- if (!subdata2.isflt) subdata2.value.f = (double) subdata2.value.i;
- if (!subdata3.isflt) subdata3.value.f = (double) subdata3.value.i;
- subdata2.isflt = subdata3.isflt = 1;
- } // if
- data->isflt = subdata2.isflt;
- if (data->isflt)
- data->value.f = data->value.i ? subdata2.value.f : subdata3.value.f;
- else
- data->value.i = data->value.i ? subdata2.value.i : subdata3.value.i;
- return 1;
- } // else if
- else // not an operator? See if this is a literal value.
- {
- switch (op)
- {
- case MOJOSHADER_AST_OP_INT_LITERAL:
- data->isflt = 0;
- data->value.i = expr->intliteral.value;
- return 1;
- case MOJOSHADER_AST_OP_FLOAT_LITERAL:
- data->isflt = 1;
- data->value.f = expr->floatliteral.value;
- return 1;
- case MOJOSHADER_AST_OP_BOOLEAN_LITERAL:
- data->isflt = 0;
- data->value.i = expr->boolliteral.value ? 1 : 0;
- return 1;
- default: break;
- } // switch
- } // switch
- return 0; // not constant, or unhandled.
- } // calc_ast_const_expr
- static const MOJOSHADER_astDataType *reduce_datatype(Context *ctx, const MOJOSHADER_astDataType *dt)
- {
- const MOJOSHADER_astDataType *retval = dt;
- while (retval && retval->type == MOJOSHADER_AST_DATATYPE_USER)
- {
- // !!! FIXME: Ugh, const removal.
- MOJOSHADER_astDataTypeUser *user = (MOJOSHADER_astDataTypeUser *) &retval->user;
- if (user->details->type == MOJOSHADER_AST_DATATYPE_NONE)
- {
- // Take this opportunity to fix up some usertype stubs that were
- // left over from the parse phase. You HAVE to catch these in the
- // right scope, so be aggressive about calling reduce_datatype()
- // as soon as things come into view!
- user->details = get_usertype(ctx, user->name);
- assert(user->details != NULL);
- } // if
- retval = user->details;
- } // while
- return retval;
- } // reduce_datatype
- static inline const MOJOSHADER_astDataType *sanitize_datatype(Context *ctx, const MOJOSHADER_astDataType *dt)
- {
- reduce_datatype(ctx, dt);
- return dt;
- } // sanitize_datatype
- static const MOJOSHADER_astDataType *build_function_datatype(Context *ctx,
- const MOJOSHADER_astDataType *rettype,
- const int paramcount,
- const MOJOSHADER_astDataType **params,
- const int intrinsic)
- {
- if ( ((paramcount > 0) && (params == NULL)) ||
- ((paramcount == 0) && (params != NULL)) )
- return NULL;
- // !!! FIXME: this is hacky.
- const MOJOSHADER_astDataType **dtparams;
- void *ptr = Malloc(ctx, sizeof (*params) * paramcount);
- if (ptr == NULL)
- return NULL;
- if (!buffer_append(ctx->garbage, &ptr, sizeof (ptr)))
- {
- Free(ctx, ptr);
- return NULL;
- } // if
- dtparams = (const MOJOSHADER_astDataType **) ptr;
- memcpy(dtparams, params, sizeof (*params) * paramcount);
- ptr = Malloc(ctx, sizeof (MOJOSHADER_astDataType));
- if (ptr == NULL)
- return NULL;
- if (!buffer_append(ctx->garbage, &ptr, sizeof (ptr)))
- {
- Free(ctx, ptr);
- return NULL;
- } // if
- MOJOSHADER_astDataType *dt = (MOJOSHADER_astDataType *) ptr;
- dt->type = MOJOSHADER_AST_DATATYPE_FUNCTION;
- dt->function.retval = rettype;
- dt->function.params = dtparams;
- dt->function.num_params = paramcount;
- dt->function.intrinsic = intrinsic;
- return dt;
- } // build_function_datatype
- static const MOJOSHADER_astDataType *build_datatype(Context *ctx,
- const int isconst,
- const MOJOSHADER_astDataType *dt,
- MOJOSHADER_astScalarOrArray *soa)
- {
- MOJOSHADER_astDataType *retval = NULL;
- assert( (soa->isarray && soa->dimension) ||
- (!soa->isarray && !soa->dimension) );
- sanitize_datatype(ctx, dt);
- // see if we can just reuse the exist datatype.
- if (!soa->isarray)
- {
- const int c1 = (dt->type & MOJOSHADER_AST_DATATYPE_CONST) != 0;
- const int c2 = (isconst != 0);
- if (c1 == c2)
- return dt; // reuse existing datatype!
- } // if
- retval = (MOJOSHADER_astDataType *) Malloc(ctx, sizeof (*retval));
- if (retval == NULL)
- return NULL;
- // !!! FIXME: this is hacky.
- if (!buffer_append(ctx->garbage, &retval, sizeof (retval)))
- {
- Free(ctx, retval);
- return NULL;
- } // if
- if (!soa->isarray)
- {
- assert(soa->dimension == NULL);
- memcpy(retval, dt, sizeof (MOJOSHADER_astDataType));
- if (isconst)
- retval->type = (MOJOSHADER_astDataTypeType)((unsigned)retval->type | MOJOSHADER_AST_DATATYPE_CONST);
- else
- retval->type = (MOJOSHADER_astDataTypeType)((unsigned)retval->type & ~MOJOSHADER_AST_DATATYPE_CONST);
- return retval;
- } // if
- retval->type = MOJOSHADER_AST_DATATYPE_ARRAY;
- retval->array.base = dt;
- if (soa->dimension == NULL)
- {
- retval->array.elements = -1;
- return retval;
- } // if
- // Run the expression to verify it's constant and produces a positive int.
- AstCalcData data;
- data.isflt = 0;
- data.value.i = 0;
- retval->array.elements = 16; // sane default for failure.
- const int ok = calc_ast_const_expr(ctx, soa->dimension, &data);
- // reset error position.
- ctx->sourcefile = soa->ast.filename;
- ctx->sourceline = soa->ast.line;
- if (!ok)
- fail(ctx, "array dimensions not constant");
- else if (data.isflt)
- fail(ctx, "array dimensions not integer");
- else if (data.value.i < 0)
- fail(ctx, "array dimensions negative");
- else
- retval->array.elements = data.value.i;
- return retval;
- } // build_datatype
- static void require_numeric_datatype(Context *ctx,
- const MOJOSHADER_astDataType *datatype)
- {
- datatype = reduce_datatype(ctx, datatype);
- if (datatype->type == MOJOSHADER_AST_DATATYPE_VECTOR)
- datatype = reduce_datatype(ctx, datatype->vector.base);
- else if (datatype->type == MOJOSHADER_AST_DATATYPE_MATRIX)
- datatype = reduce_datatype(ctx, datatype->matrix.base);
- switch (datatype->type)
- {
- case MOJOSHADER_AST_DATATYPE_BOOL:
- case MOJOSHADER_AST_DATATYPE_INT:
- case MOJOSHADER_AST_DATATYPE_UINT:
- case MOJOSHADER_AST_DATATYPE_HALF:
- case MOJOSHADER_AST_DATATYPE_FLOAT:
- case MOJOSHADER_AST_DATATYPE_DOUBLE:
- return;
- default: break;
- } // switch
- fail(ctx, "Expected numeric type"); // !!! FIXME: fmt.
- // !!! FIXME: replace AST node with an AST_OP_INT_LITERAL zero, keep going.
- } // require_numeric_datatype
- static void require_integer_datatype(Context *ctx,
- const MOJOSHADER_astDataType *datatype)
- {
- datatype = reduce_datatype(ctx, datatype);
- switch (datatype->type)
- {
- case MOJOSHADER_AST_DATATYPE_INT:
- case MOJOSHADER_AST_DATATYPE_UINT:
- return;
- default: break;
- } // switch
- fail(ctx, "Expected integer type"); // !!! FIXME: fmt.
- // !!! FIXME: replace AST node with an AST_OP_INT_LITERAL zero, keep going.
- } // require_integer_datatype
- static void require_boolean_datatype(Context *ctx,
- const MOJOSHADER_astDataType *datatype)
- {
- datatype = reduce_datatype(ctx, datatype);
- switch (datatype->type)
- {
- case MOJOSHADER_AST_DATATYPE_BOOL:
- case MOJOSHADER_AST_DATATYPE_INT:
- case MOJOSHADER_AST_DATATYPE_UINT:
- return;
- default: break;
- } // switch
- fail(ctx, "Expected boolean type"); // !!! FIXME: fmt.
- // !!! FIXME: replace AST node with an AST_OP_BOOLEAN_LITERAL false, keep going.
- } // require_numeric_datatype
- static void require_array_datatype(Context *ctx,
- const MOJOSHADER_astDataType *datatype)
- {
- datatype = reduce_datatype(ctx, datatype);
- if (datatype->type == MOJOSHADER_AST_DATATYPE_ARRAY)
- return;
- fail(ctx, "expected array");
- // !!! FIXME: delete array dereference for further processing.
- } // require_array_datatype
- static void require_struct_datatype(Context *ctx,
- const MOJOSHADER_astDataType *datatype)
- {
- datatype = reduce_datatype(ctx, datatype);
- if (datatype->type == MOJOSHADER_AST_DATATYPE_STRUCT)
- return;
- fail(ctx, "expected struct");
- // !!! FIXME: delete struct dereference for further processing.
- } // require_struct_datatype
- static int require_function_datatype(Context *ctx,
- const MOJOSHADER_astDataType *datatype)
- {
- datatype = reduce_datatype(ctx, datatype);
- if ((!datatype) || (datatype->type != MOJOSHADER_AST_DATATYPE_FUNCTION))
- {
- fail(ctx, "expected function");
- return 0;
- } // if
- return 1;
- } // require_function_datatype
- // Extract the individual element type from an array datatype.
- static const MOJOSHADER_astDataType *array_element_datatype(Context *ctx,
- const MOJOSHADER_astDataType *datatype)
- {
- datatype = reduce_datatype(ctx, datatype);
- assert(datatype->type == MOJOSHADER_AST_DATATYPE_ARRAY);
- return datatype->array.base;
- } // array_element_datatype
- // This tests two datatypes to see if they are compatible, and adds cast
- // operator nodes to the AST if the program was relying on implicit
- // casts between then. Will fail() if the datatypes can't be coerced
- // with a cast at all. (left) can be NULL to say that its datatype is
- // set in stone (an lvalue, for example). No other NULLs are allowed.
- // Returns final datatype used once implicit casting is complete.
- // The datatypes must be pointers from the string cache.
- static const MOJOSHADER_astDataType *add_type_coercion(Context *ctx,
- MOJOSHADER_astExpression **left,
- const MOJOSHADER_astDataType *_ldatatype,
- MOJOSHADER_astExpression **right,
- const MOJOSHADER_astDataType *_rdatatype)
- {
- // !!! FIXME: this whole function is probably naive at best.
- const MOJOSHADER_astDataType *ldatatype = reduce_datatype(ctx, _ldatatype);
- const MOJOSHADER_astDataType *rdatatype = reduce_datatype(ctx, _rdatatype);
- if (ldatatype == rdatatype)
- return ldatatype; // they already match, so we're done.
- struct {
- const MOJOSHADER_astDataTypeType type;
- const int bits;
- const int is_unsigned;
- const int floating;
- } typeinf[] = {
- { MOJOSHADER_AST_DATATYPE_BOOL, 1, 1, 0 },
- { MOJOSHADER_AST_DATATYPE_HALF, 16, 0, 1 },
- { MOJOSHADER_AST_DATATYPE_INT, 32, 0, 0 },
- { MOJOSHADER_AST_DATATYPE_UINT, 32, 1, 0 },
- { MOJOSHADER_AST_DATATYPE_FLOAT, 32, 0, 1 },
- { MOJOSHADER_AST_DATATYPE_DOUBLE, 64, 0, 1 },
- };
- int lvector = 0;
- int lmatrix = 0;
- int l = STATICARRAYLEN(typeinf);
- if (ldatatype != NULL)
- {
- MOJOSHADER_astDataTypeType type = ldatatype->type;
- if (type == MOJOSHADER_AST_DATATYPE_VECTOR)
- {
- lvector = 1;
- type = ldatatype->vector.base->type;
- } // if
- else if (type == MOJOSHADER_AST_DATATYPE_MATRIX)
- {
- lmatrix = 1;
- type = ldatatype->matrix.base->type;
- } // if
- for (l = 0; l < STATICARRAYLEN(typeinf); l++)
- {
- if (typeinf[l].type == type)
- break;
- } // for
- } // if
- int rvector = 0;
- int rmatrix = 0;
- int r = STATICARRAYLEN(typeinf);
- if (rdatatype != NULL)
- {
- MOJOSHADER_astDataTypeType type = rdatatype->type;
- if (type == MOJOSHADER_AST_DATATYPE_VECTOR)
- {
- rvector = 1;
- type = rdatatype->vector.base->type;
- } // if
- else if (type == MOJOSHADER_AST_DATATYPE_MATRIX)
- {
- rmatrix = 1;
- type = rdatatype->matrix.base->type;
- } // if
- for (r = 0; r < STATICARRAYLEN(typeinf); r++)
- {
- if (typeinf[r].type == type)
- break;
- } // for
- } // if
- enum { CHOOSE_NEITHER, CHOOSE_LEFT, CHOOSE_RIGHT } choice = CHOOSE_NEITHER;
- if ((l < STATICARRAYLEN(typeinf)) && (r < STATICARRAYLEN(typeinf)))
- {
- if (left == NULL)
- choice = CHOOSE_LEFT; // we need to force to the lvalue.
- else if (lmatrix && !rmatrix)
- choice = CHOOSE_LEFT;
- else if (!lmatrix && rmatrix)
- choice = CHOOSE_RIGHT;
- else if (lvector && !rvector)
- choice = CHOOSE_LEFT;
- else if (!lvector && rvector)
- choice = CHOOSE_RIGHT;
- else if (typeinf[l].bits > typeinf[r].bits)
- choice = CHOOSE_LEFT;
- else if (typeinf[l].bits < typeinf[r].bits)
- choice = CHOOSE_RIGHT;
- else if (typeinf[l].floating && !typeinf[r].floating)
- choice = CHOOSE_LEFT;
- else if (!typeinf[l].floating && typeinf[r].floating)
- choice = CHOOSE_RIGHT;
- else if (typeinf[l].is_unsigned && !typeinf[r].is_unsigned)
- choice = CHOOSE_LEFT;
- else if (!typeinf[l].is_unsigned && typeinf[r].is_unsigned)
- choice = CHOOSE_RIGHT;
- } // if
- if (choice == CHOOSE_LEFT)
- {
- *right = new_cast_expr(ctx, _ldatatype, *right);
- return _ldatatype;
- } // if
- else if (choice == CHOOSE_RIGHT)
- {
- *left = new_cast_expr(ctx, _rdatatype, *left);
- return _rdatatype;
- } // else if
- assert(choice == CHOOSE_NEITHER);
- fail(ctx, "incompatible data types");
- // Ditch original (*right), force a literal value that matches
- // ldatatype, so further processing is normalized.
- // !!! FIXME: force (right) to match (left).
- delete_expr(ctx, *right);
- *right = new_cast_expr(ctx, _ldatatype, new_literal_int_expr(ctx, 0));
- return ldatatype;
- } // add_type_coercion
- static int is_swizzle_str(const char *str, const int veclen)
- {
- int i;
- int is_xyzw = 0;
- int is_rgba = 0;
- assert(*str != '\0'); // can this actually happen?
- for (i = 0; i < veclen; i++, str++)
- {
- const char ch = *str;
- if (ch == '\0')
- break;
- else if ((ch == 'x') || (ch == 'y') || (ch == 'z') || (ch == 'w'))
- is_xyzw = 1;
- else if ((ch == 'r') || (ch == 'g') || (ch == 'b') || (ch == 'a'))
- is_rgba = 1;
- } // for
- if (*str != '\0') // must be end of string here.
- return 0; // not a swizzle.
- return ((is_rgba + is_xyzw) == 1); // can only be one or the other.
- } // is_swizzle_str
- static int datatype_size(const MOJOSHADER_astDataType *dt)
- {
- switch (dt->type)
- {
- case MOJOSHADER_AST_DATATYPE_BOOL: return 1;
- case MOJOSHADER_AST_DATATYPE_INT: return 4;
- case MOJOSHADER_AST_DATATYPE_UINT: return 4;
- case MOJOSHADER_AST_DATATYPE_FLOAT: return 4;
- case MOJOSHADER_AST_DATATYPE_FLOAT_SNORM: return 4;
- case MOJOSHADER_AST_DATATYPE_FLOAT_UNORM: return 4;
- case MOJOSHADER_AST_DATATYPE_HALF: return 2;
- case MOJOSHADER_AST_DATATYPE_DOUBLE: return 8;
- return 1;
- default:
- assert(0 && "Maybe should have used reduce_datatype()?");
- return 0;
- } // switch
- } // datatype_size
- static inline int is_scalar_datatype(const MOJOSHADER_astDataType *dt)
- {
- switch (dt->type)
- {
- case MOJOSHADER_AST_DATATYPE_BOOL:
- case MOJOSHADER_AST_DATATYPE_INT:
- case MOJOSHADER_AST_DATATYPE_UINT:
- case MOJOSHADER_AST_DATATYPE_FLOAT:
- case MOJOSHADER_AST_DATATYPE_FLOAT_SNORM:
- case MOJOSHADER_AST_DATATYPE_FLOAT_UNORM:
- case MOJOSHADER_AST_DATATYPE_HALF:
- case MOJOSHADER_AST_DATATYPE_DOUBLE:
- return 1;
- default:
- return 0;
- } // switch
- } // is_scalar_datatype
- static inline int is_float_datatype(const MOJOSHADER_astDataType *dt)
- {
- switch (dt->type)
- {
- case MOJOSHADER_AST_DATATYPE_FLOAT: return 1;
- case MOJOSHADER_AST_DATATYPE_FLOAT_SNORM: return 1;
- case MOJOSHADER_AST_DATATYPE_FLOAT_UNORM: return 1;
- default: return 0;
- } // switch
- } // is_float_datatype
- static int datatype_elems(Context *ctx, const MOJOSHADER_astDataType *dt)
- {
- dt = reduce_datatype(ctx, dt);
- switch (dt->type)
- {
- case MOJOSHADER_AST_DATATYPE_VECTOR:
- return dt->vector.elements;
- case MOJOSHADER_AST_DATATYPE_MATRIX:
- return dt->matrix.rows * dt->matrix.columns;
- default:
- return 1;
- } // switch
- } // datatype_elems
- static const MOJOSHADER_astDataType *datatype_base(Context *ctx, const MOJOSHADER_astDataType *dt)
- {
- dt = reduce_datatype(ctx, dt);
- if (dt == NULL)
- return dt;
- switch (dt->type)
- {
- case MOJOSHADER_AST_DATATYPE_VECTOR:
- dt = dt->vector.base;
- break;
- case MOJOSHADER_AST_DATATYPE_MATRIX:
- dt = dt->matrix.base;
- break;
- case MOJOSHADER_AST_DATATYPE_BUFFER:
- dt = dt->buffer.base;
- break;
- case MOJOSHADER_AST_DATATYPE_ARRAY:
- dt = dt->array.base;
- break;
- default: break;
- } // switch
- return dt;
- } // datatype_base
- typedef enum
- {
- DT_MATCH_INCOMPATIBLE, // flatly incompatible
- DT_MATCH_COMPATIBLE_DOWNCAST, // would have to lose precision
- DT_MATCH_COMPATIBLE_UPCAST, // would have to gain precision
- DT_MATCH_COMPATIBLE, // can cast to without serious change.
- DT_MATCH_PERFECT // identical datatype.
- } DatatypeMatch;
- static DatatypeMatch compatible_arg_datatype(Context *ctx,
- const MOJOSHADER_astDataType *arg,
- const MOJOSHADER_astDataType *param)
- {
- // The matching rules for HLSL function overloading, as far as I can
- // tell from experimenting with Microsoft's compiler, seem to be this:
- //
- // - All parameters of a function must match what the caller specified
- // after possible type promotion via the following rules.
- // - If the number of arguments and the number of parameters don't match,
- // that overload is immediately rejected.
- // - Each overloaded function is given a score that is the sum of the
- // "worth" of each parameter vs the caller's arguments
- // (see DatatypeMatch). The higher the score, the more favorable this
- // function overload would be.
- // - If there is a tie for highest score between two or more function
- // overloads, we declare that function call to be ambiguous and fail().
- // - Scalars can be promoted to vectors to make a parameter match.
- // - Scalars can promote to other scalars (short to int, etc).
- // - Datatypes can downcast, but should generate a warning.
- // (calling void fn(float x); as fn((double)1.0) should warn).
- // - Vectors may NOT be extend (a float2 can't implicity extend to a
- // float4).
- // - Vectors with the same elements can promote (a half2 can become
- // a float2). Downcasting between vectors with the same number of
- // elements is allowed.
- // - A perfect match of all params will be favored over any functions
- // that only match if type promotion is applied (given a perfect match
- // of all parameters, we'll stop looking for other matches).
- if (datatypes_match(arg, param))
- return DT_MATCH_PERFECT; // that was easy.
- arg = reduce_datatype(ctx, arg);
- param = reduce_datatype(ctx, param);
- int do_base_test = 0;
- if (is_scalar_datatype(arg))
- do_base_test = 1; // we let these all go through for now.
- else if (arg->type == param->type)
- {
- if (arg->type == MOJOSHADER_AST_DATATYPE_VECTOR)
- do_base_test = (arg->vector.elements == param->vector.elements);
- else if (arg->type == MOJOSHADER_AST_DATATYPE_MATRIX)
- {
- do_base_test =
- ((arg->matrix.rows == param->matrix.rows) &&
- (arg->matrix.columns == param->matrix.columns));
- } // if
- } // if
- if (do_base_test)
- {
- arg = datatype_base(ctx, arg);
- param = datatype_base(ctx, param);
- const int argsize = datatype_size(arg);
- const int paramsize = datatype_size(param);
- const int argfloat = is_float_datatype(arg);
- const int paramfloat = is_float_datatype(param);
- if (argfloat && !paramfloat)
- return DT_MATCH_COMPATIBLE_DOWNCAST; // always loss of precision.
- else if (argfloat && !paramfloat)
- {
- if (argsize < paramsize)
- return DT_MATCH_COMPATIBLE_UPCAST;
- else
- return DT_MATCH_COMPATIBLE_DOWNCAST; // loss of precision.
- } // else if
- else if (argsize == paramsize)
- return DT_MATCH_COMPATIBLE;
- else if (argsize < paramsize)
- return DT_MATCH_COMPATIBLE_UPCAST;
- else /* if (argsize > paramsize) */
- return DT_MATCH_COMPATIBLE_DOWNCAST;
- } // if
- return DT_MATCH_INCOMPATIBLE;
- } // compatible_arg_datatype
- static const MOJOSHADER_astDataType *type_check_ast(Context *ctx, void *_ast);
- // !!! FIXME: this function sucks.
- static const MOJOSHADER_astDataType *match_func_to_call(Context *ctx,
- MOJOSHADER_astExpressionCallFunction *ast)
- {
- SymbolScope *best = NULL; // best choice we find.
- int best_score = 0;
- MOJOSHADER_astExpressionIdentifier *ident = ast->identifier;
- const char *sym = ident->identifier;
- const void *value = NULL;
- void *iter = NULL;
- int argcount = 0;
- MOJOSHADER_astArguments *args = ast->args;
- while (args != NULL)
- {
- argcount++;
- type_check_ast(ctx, args->argument);
- args = args->next;
- } // while;
- // we do some tapdancing to handle function overloading here.
- int match = 0;
- while (hash_iter(ctx->variables.hash, sym, &value, &iter))
- {
- SymbolScope *item = (SymbolScope *) value;
- const MOJOSHADER_astDataType *dt = item->datatype;
- dt = reduce_datatype(ctx, dt);
- // there's a locally-scoped symbol with this name? It takes precedence.
- if (dt->type != MOJOSHADER_AST_DATATYPE_FUNCTION)
- return dt;
- const MOJOSHADER_astDataTypeFunction *dtfn = (MOJOSHADER_astDataTypeFunction *) dt;
- const int perfect = argcount * ((int) DT_MATCH_PERFECT);
- int score = 0;
- if (argcount == dtfn->num_params) // !!! FIXME: default args.
- {
- args = ast->args;
- int i;
- for (i = 0; i < argcount; i++)
- {
- assert(args != NULL);
- dt = args->argument->datatype;
- args = args->next;
- const DatatypeMatch compatible = compatible_arg_datatype(ctx, dt, dtfn->params[i]);
- if (compatible == DT_MATCH_INCOMPATIBLE)
- {
- args = NULL;
- score = 0;
- break;
- } // if
- score += (int) compatible;
- } // for
- if (args != NULL)
- score = 0; // too many arguments supplied. No match.
- } // else
- if (score == 0) // incompatible.
- continue;
- else if (score == perfect) // perfection! stop looking!
- {
- match = 1; // ignore all other compatible matches.
- best = item;
- break;
- } // if
- else if (score >= best_score) // compatible, but not perfect, match.
- {
- if (score == best_score)
- {
- match++;
- // !!! FIXME: list each possible function in a fail(),
- // !!! FIXME: but you can't actually fail() here, since
- // !!! FIXME: this may cease to be ambiguous if we get
- // !!! FIXME: a better match on a later overload.
- } // if
- else if (score > best_score)
- {
- match = 1; // reset the ambiguousness count.
- best = item;
- best_score = score;
- } // if
- } // else if
- } // while
- if (match > 1)
- {
- assert(best != NULL);
- failf(ctx, "Ambiguous function call to '%s'", sym);
- } // if
- if (best == NULL)
- {
- assert(match == 0);
- assert(best_score == 0);
- // !!! FIXME: ident->datatype = ?
- failf(ctx, "No matching function named '%s'", sym);
- } // if
- else
- {
- ident->datatype = reduce_datatype(ctx, best->datatype);
- ident->index = best->index;
- } // else
- return ident->datatype;
- } // match_func_to_call
- static const MOJOSHADER_astDataType *vectype_from_base(Context *ctx,
- const MOJOSHADER_astDataType *base,
- const int len)
- {
- assert(len > 0);
- assert(len <= 4);
- if (len == 1) // return "float" and not "float1"
- return base;
- const char *typestr = NULL;
- switch (base->type)
- {
- case MOJOSHADER_AST_DATATYPE_BOOL: typestr = "bool"; break;
- case MOJOSHADER_AST_DATATYPE_INT: typestr = "int"; break;
- case MOJOSHADER_AST_DATATYPE_UINT: typestr = "uint"; break;
- case MOJOSHADER_AST_DATATYPE_HALF: typestr = "half"; break;
- case MOJOSHADER_AST_DATATYPE_FLOAT: typestr = "float"; break;
- case MOJOSHADER_AST_DATATYPE_DOUBLE: typestr = "double"; break;
- default: assert(0 && "This shouldn't happen"); break;
- } // switch
- char buf[32];
- snprintf(buf, sizeof (buf), "%s%d", typestr, len);
- const MOJOSHADER_astDataType *datatype = get_usertype(ctx, buf);
- assert(datatype != NULL);
- return datatype;
- } // vectype_from_base
- // Go through the AST and make sure all datatypes check out okay. For datatypes
- // that are compatible but are relying on an implicit cast, we add explicit
- // casts to the AST here, so further processing doesn't have to worry about
- // type coercion.
- // For things that are incompatible, we generate errors and
- // then replace them with reasonable defaults so further processing can
- // continue (but code generation will be skipped due to errors).
- // This means further processing can assume the AST is sane and not have to
- // spend effort verifying it again.
- // This stage will also set every AST node's datatype field, if it is
- // meaningful to do so. This will allow conversion to IR to know what
- // type/size a given node is.
- static const MOJOSHADER_astDataType *type_check_ast(Context *ctx, void *_ast)
- {
- MOJOSHADER_astNode *ast = (MOJOSHADER_astNode *) _ast;
- const MOJOSHADER_astDataType *datatype = NULL;
- const MOJOSHADER_astDataType *datatype2 = NULL;
- const MOJOSHADER_astDataType *datatype3 = NULL;
- if ((!ast) || (ctx->out_of_memory))
- return NULL;
- // upkeep so we report correct error locations...
- ctx->sourcefile = ast->ast.filename;
- ctx->sourceline = ast->ast.line;
- switch (ast->ast.type)
- {
- case MOJOSHADER_AST_OP_POSTINCREMENT:
- case MOJOSHADER_AST_OP_POSTDECREMENT:
- case MOJOSHADER_AST_OP_PREINCREMENT:
- case MOJOSHADER_AST_OP_PREDECREMENT:
- case MOJOSHADER_AST_OP_COMPLEMENT:
- case MOJOSHADER_AST_OP_NEGATE:
- // !!! FIXME: must be lvalue.
- // !!! FIXME: bools must type-promote to ...int?
- // !!! FIXME: complement must not be float (...right?)
- datatype = type_check_ast(ctx, ast->unary.operand);
- require_numeric_datatype(ctx, datatype);
- ast->unary.datatype = datatype;
- return datatype;
- case MOJOSHADER_AST_OP_NOT:
- datatype = type_check_ast(ctx, ast->unary.operand);
- require_boolean_datatype(ctx, datatype);
- // !!! FIXME: coerce to bool here.
- ast->unary.datatype = &ctx->dt_bool;
- return datatype;
- case MOJOSHADER_AST_OP_DEREF_ARRAY:
- datatype = type_check_ast(ctx, ast->binary.left);
- datatype2 = type_check_ast(ctx, ast->binary.right);
- require_integer_datatype(ctx, datatype2);
- add_type_coercion(ctx, NULL, &ctx->dt_int, &ast->binary.right, datatype2);
- datatype = reduce_datatype(ctx, datatype);
- if (datatype->type == MOJOSHADER_AST_DATATYPE_VECTOR)
- {
- // !!! FIXME: if constant int, fail if not 0 >= value <= vecsize.
- ast->binary.datatype = datatype->vector.base;
- } // if
- else if (datatype->type == MOJOSHADER_AST_DATATYPE_MATRIX)
- {
- // !!! FIXME: if constant int, fail if not 0 >= value <= rowsize (colsize?).
- ast->binary.datatype = vectype_from_base(ctx, datatype->matrix.base, datatype->matrix.columns); // !!! FIXME: rows?
- }
- else
- {
- require_array_datatype(ctx, datatype);
- ast->binary.datatype = array_element_datatype(ctx, datatype);
- } // else
- return ast->binary.datatype;
- case MOJOSHADER_AST_OP_DEREF_STRUCT:
- {
- const char *member = ast->derefstruct.member;
- datatype = type_check_ast(ctx, ast->derefstruct.identifier);
- const MOJOSHADER_astDataType *reduced = reduce_datatype(ctx, datatype);
- // Is this a swizzle and not a struct deref?
- if (reduced->type == MOJOSHADER_AST_DATATYPE_VECTOR)
- {
- const int veclen = reduced->vector.elements;
- ast->derefstruct.isswizzle = 1;
- if (!is_swizzle_str(member, veclen))
- {
- fail(ctx, "invalid swizzle on vector");
- // force this to be sane for further processing.
- const char *sane_swiz = stringcache(ctx->strcache, "xyzw");
- member = ast->derefstruct.member = sane_swiz;
- } // if
- const int swizlen = (int) strlen(member);
- if (swizlen != veclen)
- datatype = vectype_from_base(ctx, reduced->vector.base, swizlen);
- ast->derefstruct.datatype = datatype;
- return ast->derefstruct.datatype;
- } // if
- // maybe this is an actual struct?
- // !!! FIXME: replace with an int or something if not.
- require_struct_datatype(ctx, reduced);
- // map member to datatype
- assert(ast->derefstruct.datatype == NULL);
- const MOJOSHADER_astDataTypeStructMember *mbrs = reduced->structure.members;
- int i;
- for (i = 0; i < reduced->structure.member_count; i++)
- {
- if (strcmp(mbrs[i].identifier, member) == 0)
- {
- ast->derefstruct.datatype = mbrs[i].datatype;
- ast->derefstruct.member_index = i;
- break;
- } // if
- } // for
- if (ast->derefstruct.datatype == NULL)
- {
- // !!! FIXME: replace with an int or something.
- failf(ctx, "Struct has no member named '%s'", member);
- } // if
- return ast->derefstruct.datatype;
- } // case
- case MOJOSHADER_AST_OP_COMMA:
- // evaluate and throw away left, return right.
- type_check_ast(ctx, ast->binary.left);
- ast->binary.datatype = type_check_ast(ctx, ast->binary.right);
- return ast->binary.datatype;
- case MOJOSHADER_AST_OP_MULTIPLY:
- case MOJOSHADER_AST_OP_DIVIDE:
- case MOJOSHADER_AST_OP_ADD:
- case MOJOSHADER_AST_OP_SUBTRACT:
- datatype = type_check_ast(ctx, ast->binary.left);
- datatype2 = type_check_ast(ctx, ast->binary.right);
- require_numeric_datatype(ctx, datatype);
- require_numeric_datatype(ctx, datatype2);
- ast->binary.datatype = add_type_coercion(ctx, &ast->binary.left,
- datatype, &ast->binary.right, datatype2);
- return ast->binary.datatype;
- case MOJOSHADER_AST_OP_LSHIFT:
- case MOJOSHADER_AST_OP_RSHIFT:
- case MOJOSHADER_AST_OP_MODULO:
- datatype = type_check_ast(ctx, ast->binary.left);
- datatype2 = type_check_ast(ctx, ast->binary.right);
- require_integer_datatype(ctx, datatype);
- require_integer_datatype(ctx, datatype2);
- ast->binary.datatype = add_type_coercion(ctx, &ast->binary.left,
- datatype, &ast->binary.right, datatype2);
- return ast->binary.datatype;
- case MOJOSHADER_AST_OP_LESSTHAN:
- case MOJOSHADER_AST_OP_GREATERTHAN:
- case MOJOSHADER_AST_OP_LESSTHANOREQUAL:
- case MOJOSHADER_AST_OP_GREATERTHANOREQUAL:
- case MOJOSHADER_AST_OP_NOTEQUAL:
- case MOJOSHADER_AST_OP_EQUAL:
- datatype = type_check_ast(ctx, ast->binary.left);
- datatype2 = type_check_ast(ctx, ast->binary.right);
- add_type_coercion(ctx, &ast->binary.left, datatype,
- &ast->binary.right, datatype2);
- ast->binary.datatype = &ctx->dt_bool;
- return ast->binary.datatype;
- case MOJOSHADER_AST_OP_BINARYAND:
- case MOJOSHADER_AST_OP_BINARYXOR:
- case MOJOSHADER_AST_OP_BINARYOR:
- datatype = type_check_ast(ctx, ast->binary.left);
- datatype2 = type_check_ast(ctx, ast->binary.right);
- require_integer_datatype(ctx, datatype);
- require_integer_datatype(ctx, datatype2);
- ast->binary.datatype = add_type_coercion(ctx, &ast->binary.left,
- datatype, &ast->binary.right, datatype2);
- return ast->binary.datatype;
- case MOJOSHADER_AST_OP_LOGICALAND:
- case MOJOSHADER_AST_OP_LOGICALOR:
- datatype = type_check_ast(ctx, ast->binary.left);
- datatype2 = type_check_ast(ctx, ast->binary.right);
- require_boolean_datatype(ctx, datatype);
- require_boolean_datatype(ctx, datatype2);
- // !!! FIXME: coerce each to bool here, separately.
- add_type_coercion(ctx, &ast->binary.left, datatype,
- &ast->binary.right, datatype2);
- ast->binary.datatype = &ctx->dt_bool;
- case MOJOSHADER_AST_OP_ASSIGN:
- case MOJOSHADER_AST_OP_MULASSIGN:
- case MOJOSHADER_AST_OP_DIVASSIGN:
- case MOJOSHADER_AST_OP_MODASSIGN:
- case MOJOSHADER_AST_OP_ADDASSIGN:
- case MOJOSHADER_AST_OP_SUBASSIGN:
- case MOJOSHADER_AST_OP_LSHIFTASSIGN:
- case MOJOSHADER_AST_OP_RSHIFTASSIGN:
- case MOJOSHADER_AST_OP_ANDASSIGN:
- case MOJOSHADER_AST_OP_XORASSIGN:
- case MOJOSHADER_AST_OP_ORASSIGN:
- // !!! FIXME: verify binary.left is an lvalue, or fail()!
- datatype = type_check_ast(ctx, ast->binary.left);
- datatype2 = type_check_ast(ctx, ast->binary.right);
- ast->binary.datatype = add_type_coercion(ctx, NULL, datatype,
- &ast->binary.right, datatype2);
- return ast->binary.datatype;
- case MOJOSHADER_AST_OP_CONDITIONAL:
- datatype = type_check_ast(ctx, ast->ternary.left);
- datatype2 = type_check_ast(ctx, ast->ternary.center);
- datatype3 = type_check_ast(ctx, ast->ternary.right);
- require_numeric_datatype(ctx, datatype);
- ast->ternary.datatype = add_type_coercion(ctx, &ast->ternary.center,
- datatype2, &ast->ternary.right, datatype3);
- return ast->ternary.datatype;
- case MOJOSHADER_AST_OP_IDENTIFIER:
- datatype = find_variable(ctx, ast->identifier.identifier, &ast->identifier.index);
- if (datatype == NULL)
- {
- fail(ctx, "Unknown identifier");
- // !!! FIXME: replace with a sane default, move on.
- datatype = &ctx->dt_int;
- } // if
- ast->identifier.datatype = datatype;
- return ast->identifier.datatype;
- case MOJOSHADER_AST_OP_INT_LITERAL:
- case MOJOSHADER_AST_OP_FLOAT_LITERAL:
- case MOJOSHADER_AST_OP_STRING_LITERAL:
- case MOJOSHADER_AST_OP_BOOLEAN_LITERAL:
- assert(ast->expression.datatype != NULL);
- return ast->expression.datatype; // already set up during parsing.
- case MOJOSHADER_AST_ARGUMENTS:
- assert(0 && "Should be done by MOJOSHADER_AST_OP_CALLFUNC/CONSTRUCTOR");
- return NULL;
- case MOJOSHADER_AST_OP_CALLFUNC:
- {
- datatype = match_func_to_call(ctx, &ast->callfunc);
- const MOJOSHADER_astDataType *reduced = reduce_datatype(ctx, datatype);
- // !!! FIXME: replace AST node with an int if this isn't a func.
- if (!require_function_datatype(ctx, reduced))
- {
- ast->callfunc.datatype = &ctx->dt_int;
- return ast->callfunc.datatype;
- } // if
- MOJOSHADER_astArguments *arg = ast->callfunc.args;
- int i;
- for (i = 0; i < reduced->function.num_params; i++)
- {
- if (arg == NULL) // !!! FIXME: check for default parameters, fill them in.
- {
- fail(ctx, "Too few arguments");
- // !!! FIXME: replace AST here.
- break;
- } // if
- datatype2 = arg->argument->datatype; // already type-checked.
- add_type_coercion(ctx, NULL, reduced->function.params[i],
- &arg->argument, datatype2);
- arg = arg->next;
- } // for
- assert(arg == NULL); // shouldn't have chosen func if too many args.
- ast->callfunc.datatype = reduced->function.retval;
- return ast->callfunc.datatype;
- } // case
- case MOJOSHADER_AST_OP_CONSTRUCTOR:
- {
- const MOJOSHADER_astDataType *reduced = reduce_datatype(ctx, ast->constructor.datatype);
- const MOJOSHADER_astDataType *base_dt = reduced;
- int num_params = 1;
- assert(reduced != NULL);
- switch (reduced->type)
- {
- case MOJOSHADER_AST_DATATYPE_VECTOR:
- num_params = reduced->vector.elements;
- base_dt = reduced->vector.base;
- break;
- case MOJOSHADER_AST_DATATYPE_MATRIX:
- num_params = reduced->matrix.rows * reduced->matrix.columns;
- base_dt = reduced->matrix.base;
- break;
- case MOJOSHADER_AST_DATATYPE_BOOL:
- case MOJOSHADER_AST_DATATYPE_INT:
- case MOJOSHADER_AST_DATATYPE_UINT:
- case MOJOSHADER_AST_DATATYPE_FLOAT:
- case MOJOSHADER_AST_DATATYPE_FLOAT_SNORM:
- case MOJOSHADER_AST_DATATYPE_FLOAT_UNORM:
- case MOJOSHADER_AST_DATATYPE_HALF:
- case MOJOSHADER_AST_DATATYPE_DOUBLE:
- case MOJOSHADER_AST_DATATYPE_STRING:
- num_params = 1;
- break;
- // !!! FIXME: can you construct a MOJOSHADER_AST_DATATYPE_STRUCT?
- // !!! FIXME: can you construct a MOJOSHADER_AST_DATATYPE_ARRAY?
- // !!! FIXME: can you construct a MOJOSHADER_AST_DATATYPE_BUFFER?
- default:
- fail(ctx, "Invalid type for constructor");
- delete_arguments(ctx, ast->constructor.args);
- ast->constructor.args = new_argument(ctx, new_literal_int_expr(ctx, 0));
- ast->constructor.datatype = &ctx->dt_int;
- return ast->constructor.datatype;
- } // switch
- assert(num_params > 0);
- MOJOSHADER_astArguments *arg = ast->constructor.args;
- MOJOSHADER_astArguments *prev = NULL;
- int i;
- for (i = 0; i < num_params; i++)
- {
- if (arg == NULL) // !!! FIXME: check for default parameters.
- {
- fail(ctx, "Too few arguments");
- // !!! FIXME: replace AST here.
- break;
- } // if
- datatype2 = type_check_ast(ctx, arg->argument);
- // "float4(float3(1,2,3),4)" is legal, so we need to see if
- // we're a vector, and jump that number of parameters instead
- // of doing type coercion.
- reduced = reduce_datatype(ctx, datatype2);
- if (reduced->type == MOJOSHADER_AST_DATATYPE_VECTOR)
- {
- // make sure things like float4(half3(1,2,3),1) convert that half3 to float3.
- const int count = reduced->vector.elements;
- datatype3 = vectype_from_base(ctx, base_dt, count);
- add_type_coercion(ctx, NULL, datatype3, &arg->argument, datatype2);
- i += count - 1;
- } // else
- else
- {
- add_type_coercion(ctx, NULL, base_dt, &arg->argument, datatype2);
- } // else
- prev = arg;
- arg = arg->next;
- } // for
- if (arg != NULL)
- {
- fail(ctx, "Too many arguments");
- // Process extra arguments then chop them out.
- MOJOSHADER_astArguments *argi;
- for (argi = arg; argi != NULL; argi = argi->next)
- type_check_ast(ctx, argi->argument);
- if (prev != NULL)
- prev->next = NULL;
- delete_arguments(ctx, arg);
- } // if
- return ast->constructor.datatype;
- } // case
- case MOJOSHADER_AST_OP_CAST:
- datatype = sanitize_datatype(ctx, ast->cast.datatype);
- datatype2 = type_check_ast(ctx, ast->cast.operand);
- // you still need type coercion, since you could do a wrong cast,
- // like "int x = (short) mychar;"
- add_type_coercion(ctx, NULL, datatype, &ast->cast.operand, datatype2);
- return datatype;
- case MOJOSHADER_AST_STATEMENT_BREAK:
- if ((ctx->loop_count == 0) && (ctx->switch_count == 0))
- fail(ctx, "Break outside loop or switch");
- // !!! FIXME: warn if unreachable statements follow?
- type_check_ast(ctx, ast->stmt.next);
- return NULL;
- case MOJOSHADER_AST_STATEMENT_CONTINUE:
- if (ctx->loop_count == 0)
- fail(ctx, "Continue outside loop");
- // !!! FIXME: warn if unreachable statements follow?
- type_check_ast(ctx, ast->stmt.next);
- return NULL;
- case MOJOSHADER_AST_STATEMENT_DISCARD:
- // !!! FIXME: warn if unreachable statements follow?
- type_check_ast(ctx, ast->stmt.next);
- return NULL;
- case MOJOSHADER_AST_STATEMENT_EMPTY:
- type_check_ast(ctx, ast->stmt.next);
- return NULL;
- case MOJOSHADER_AST_STATEMENT_EXPRESSION:
- // !!! FIXME: warn about expressions without a side-effect here?
- type_check_ast(ctx, ast->exprstmt.expr); // !!! FIXME: This is named badly...
- type_check_ast(ctx, ast->exprstmt.next);
- return NULL;
- case MOJOSHADER_AST_STATEMENT_IF:
- push_scope(ctx); // new scope for "if ((int x = blah()) != 0)"
- type_check_ast(ctx, ast->ifstmt.expr);
- type_check_ast(ctx, ast->ifstmt.statement);
- pop_scope(ctx);
- type_check_ast(ctx, ast->ifstmt.next);
- return NULL;
- case MOJOSHADER_AST_STATEMENT_TYPEDEF:
- type_check_ast(ctx, ast->typedefstmt.type_info);
- type_check_ast(ctx, ast->typedefstmt.next);
- return NULL;
- case MOJOSHADER_AST_STATEMENT_SWITCH:
- {
- ctx->switch_count++;
- MOJOSHADER_astSwitchCases *cases = ast->switchstmt.cases;
- // !!! FIXME: expr must be POD (no structs, arrays, etc!).
- datatype = type_check_ast(ctx, ast->switchstmt.expr);
- while (cases)
- {
- // !!! FIXME: case must be POD (no structs, arrays, etc!).
- datatype2 = type_check_ast(ctx, cases->expr);
- add_type_coercion(ctx, NULL, datatype,
- &cases->expr, datatype2);
- type_check_ast(ctx, cases->statement);
- cases = cases->next;
- } // while
- ctx->switch_count--;
- type_check_ast(ctx, ast->switchstmt.next);
- return NULL;
- } // case
- case MOJOSHADER_AST_SWITCH_CASE:
- assert(0 && "Should be done by MOJOSHADER_AST_STATEMENT_SWITCH.");
- return NULL;
- case MOJOSHADER_AST_STATEMENT_STRUCT:
- type_check_ast(ctx, ast->structstmt.struct_info);
- type_check_ast(ctx, ast->structstmt.next);
- return NULL;
- case MOJOSHADER_AST_STATEMENT_VARDECL:
- type_check_ast(ctx, ast->vardeclstmt.declaration);
- type_check_ast(ctx, ast->vardeclstmt.next);
- return NULL;
- case MOJOSHADER_AST_STATEMENT_BLOCK:
- push_scope(ctx); // new vars declared here live until '}'.
- type_check_ast(ctx, ast->blockstmt.statements);
- pop_scope(ctx);
- type_check_ast(ctx, ast->blockstmt.next);
- return NULL;
- case MOJOSHADER_AST_STATEMENT_FOR:
- ctx->loop_count++;
- push_scope(ctx); // new scope for "for (int x = 0; ...)"
- type_check_ast(ctx, ast->forstmt.var_decl);
- type_check_ast(ctx, ast->forstmt.initializer);
- type_check_ast(ctx, ast->forstmt.looptest);
- type_check_ast(ctx, ast->forstmt.counter);
- type_check_ast(ctx, ast->forstmt.statement);
- pop_scope(ctx);
- ctx->loop_count--;
- type_check_ast(ctx, ast->forstmt.next);
- return NULL;
- case MOJOSHADER_AST_STATEMENT_DO:
- ctx->loop_count++;
- // !!! FIXME: should there be a push_scope() here?
- type_check_ast(ctx, ast->dostmt.statement);
- push_scope(ctx); // new scope for "while ((int x = blah()) != 0)"
- type_check_ast(ctx, ast->dostmt.expr);
- pop_scope(ctx);
- ctx->loop_count--;
- type_check_ast(ctx, ast->dostmt.next);
- return NULL;
- case MOJOSHADER_AST_STATEMENT_WHILE:
- ctx->loop_count++;
- push_scope(ctx); // new scope for "while ((int x = blah()) != 0)"
- type_check_ast(ctx, ast->whilestmt.expr);
- type_check_ast(ctx, ast->whilestmt.statement);
- pop_scope(ctx);
- ctx->loop_count--;
- type_check_ast(ctx, ast->whilestmt.next);
- return NULL;
- case MOJOSHADER_AST_STATEMENT_RETURN:
- // !!! FIXME: type coercion to outer function's return type.
- // !!! FIXME: warn if unreachable statements follow?
- type_check_ast(ctx, ast->returnstmt.expr);
- type_check_ast(ctx, ast->returnstmt.next);
- return NULL;
- case MOJOSHADER_AST_COMPUNIT_FUNCTION:
- assert(!ctx->is_func_scope);
- // We have to tapdance here to make sure the function is in
- // the global scope, but it's parameters are pushed as variables
- // in the function's scope.
- datatype = type_check_ast(ctx, ast->funcunit.declaration);
- ast->funcunit.index = push_function(ctx,
- ast->funcunit.declaration->identifier,
- datatype, ast->funcunit.definition == NULL);
- // not just a declaration, but a full function definition?
- if (ast->funcunit.definition != NULL)
- {
- assert(ctx->loop_count == 0);
- assert(ctx->switch_count == 0);
- ctx->is_func_scope = 1;
- ctx->var_index = 0; // reset this every function.
- push_scope(ctx); // so function params are in function scope.
- // repush the parameters before checking the actual function.
- MOJOSHADER_astFunctionParameters *param;
- for (param = ast->funcunit.declaration->params; param; param = param->next)
- push_variable(ctx, param->identifier, param->datatype);
- type_check_ast(ctx, ast->funcunit.definition);
- pop_scope(ctx);
- ctx->is_func_scope = 0;
- assert(ctx->loop_count == 0);
- assert(ctx->switch_count == 0);
- } // else
- type_check_ast(ctx, ast->funcunit.next);
- return NULL;
- case MOJOSHADER_AST_COMPUNIT_TYPEDEF:
- type_check_ast(ctx, ast->typedefunit.type_info);
- type_check_ast(ctx, ast->typedefunit.next);
- return NULL;
- case MOJOSHADER_AST_COMPUNIT_STRUCT:
- type_check_ast(ctx, ast->structunit.struct_info);
- type_check_ast(ctx, ast->structunit.next);
- return NULL;
- case MOJOSHADER_AST_COMPUNIT_VARIABLE:
- type_check_ast(ctx, ast->varunit.declaration);
- type_check_ast(ctx, ast->varunit.next);
- return NULL;
- case MOJOSHADER_AST_SCALAR_OR_ARRAY:
- assert(0 && "Should be done by other AST nodes.");
- return NULL;
- case MOJOSHADER_AST_TYPEDEF:
- {
- MOJOSHADER_astScalarOrArray *soa = ast->typdef.details;
- datatype = get_usertype(ctx, soa->identifier);
- if (datatype != NULL)
- {
- fail(ctx, "typedef already defined");
- ast->typdef.datatype = datatype;
- return datatype;
- } // if
- datatype = build_datatype(ctx, ast->typdef.isconst,
- ast->typdef.datatype, soa);
- if (datatype == NULL)
- return NULL; // out of memory?
- push_usertype(ctx, soa->identifier, datatype);
- ast->typdef.datatype = datatype;
- return ast->typdef.datatype;
- } // case
- case MOJOSHADER_AST_FUNCTION_PARAMS:
- assert(0 && "Should be done by MOJOSHADER_AST_FUNCTION_SIGNATURE");
- case MOJOSHADER_AST_FUNCTION_SIGNATURE:
- {
- MOJOSHADER_astFunctionParameters *param;
- const MOJOSHADER_astDataType *dtparams[64];
- int i = 0;
- for (param = ast->funcsig.params; param; param = param->next)
- {
- assert(i <= STATICARRAYLEN(dtparams)); // laziness.
- sanitize_datatype(ctx, param->datatype);
- if (param->initializer != NULL)
- {
- datatype2 = type_check_ast(ctx, param->initializer);
- add_type_coercion(ctx, NULL, param->datatype,
- ¶m->initializer, datatype2);
- } // if
- dtparams[i] = param->datatype;
- i++;
- } // for
- ast->funcsig.datatype = build_function_datatype(ctx,
- ast->funcsig.datatype,
- i, dtparams, 0);
- return ast->funcsig.datatype;
- } // case
- case MOJOSHADER_AST_STRUCT_DECLARATION:
- {
- // !!! FIXME: We don't handle struct predeclaration at all right now
- // !!! FIXME: (neither does the grammar)...not only does that mean
- // !!! FIXME: you need to know the struct definition up front, but
- // !!! FIXME: you can't do "struct XXX *next;" for a self-referencing
- // !!! FIXME: linked list struct thing. This probably isn't a big
- // !!! FIXME: deal, as there aren't (CURRENTLY!) pointers in HLSL,
- // !!! FIXME: but you never know.
- const MOJOSHADER_astStructMembers *mbrs;
- // !!! FIXME: count this during parsing?
- int count = 0;
- mbrs = ast->structdecl.members;
- while (mbrs != NULL)
- {
- count++;
- mbrs = mbrs->next;
- } // while
- // !!! FIXME: this is hacky.
- MOJOSHADER_astDataTypeStructMember *dtmbrs;
- void *ptr = Malloc(ctx, sizeof (*dtmbrs) * count);
- if (ptr == NULL)
- return NULL;
- if (!buffer_append(ctx->garbage, &ptr, sizeof (ptr)))
- {
- Free(ctx, ptr);
- return NULL;
- } // if
- dtmbrs = (MOJOSHADER_astDataTypeStructMember *) ptr;
- ptr = Malloc(ctx, sizeof (MOJOSHADER_astDataType));
- if (ptr == NULL)
- return NULL;
- if (!buffer_append(ctx->garbage, &ptr, sizeof (ptr)))
- {
- Free(ctx, ptr);
- return NULL;
- } // if
- MOJOSHADER_astDataType *dt = (MOJOSHADER_astDataType *) ptr;
- mbrs = ast->structdecl.members;
- int i;
- for (i = 0; i < count; i++)
- {
- // !!! FIXME: current grammar forbids const keyword on struct members!
- dtmbrs[i].datatype = build_datatype(ctx, 0, mbrs->datatype, mbrs->details);
- dtmbrs[i].identifier = mbrs->details->identifier; // cached!
- mbrs = mbrs->next;
- } // for
- dt->structure.type = MOJOSHADER_AST_DATATYPE_STRUCT;
- dt->structure.members = dtmbrs;
- dt->structure.member_count = count;
- ast->structdecl.datatype = dt;
- // !!! FIXME: this shouldn't push for anonymous structs: "struct { int x; } myvar;"
- // !!! FIXME: but right now, the grammar is wrong and requires a name for the struct.
- push_usertype(ctx, ast->structdecl.name, ast->structdecl.datatype);
- return ast->structdecl.datatype;
- } // case
- case MOJOSHADER_AST_STRUCT_MEMBER:
- assert(0 && "Should be done by MOJOSHADER_AST_STRUCT_DECLARATION.");
- return NULL;
- case MOJOSHADER_AST_VARIABLE_DECLARATION:
- {
- MOJOSHADER_astVariableDeclaration *decl = &ast->vardecl;
- // this is true now, but we'll fill in ->datatype no matter what.
- assert((decl->datatype && !decl->anonymous_datatype) ||
- (!decl->datatype && decl->anonymous_datatype));
- // An anonymous struct? That AST node does the heavy lifting.
- if (decl->anonymous_datatype != NULL)
- datatype = type_check_ast(ctx, decl->anonymous_datatype);
- else
- {
- datatype = build_datatype(ctx, (decl->attributes & MOJOSHADER_AST_VARATTR_CONST) != 0,
- decl->datatype, decl->details);
- } // else
- while (decl != NULL)
- {
- decl->datatype = datatype;
- push_variable(ctx, decl->details->identifier, datatype);
- if (decl->initializer != NULL)
- {
- datatype2 = type_check_ast(ctx, decl->initializer);
- add_type_coercion(ctx, NULL, datatype, &decl->initializer, datatype2);
- } // if
- type_check_ast(ctx, decl->annotations);
- type_check_ast(ctx, decl->lowlevel);
- decl = decl->next;
- } // while
- return datatype;
- } // case
- case MOJOSHADER_AST_ANNOTATION:
- {
- MOJOSHADER_astAnnotations *anno = &ast->annotations;
- while (anno)
- {
- type_check_ast(ctx, anno->initializer);
- anno = anno->next;
- } // while
- return NULL;
- } // case
- case MOJOSHADER_AST_PACK_OFFSET:
- case MOJOSHADER_AST_VARIABLE_LOWLEVEL:
- return NULL; // no-op (for now, at least).
- default:
- assert(0 && "unexpected type");
- } // switch
- return NULL;
- } // type_check_ast
- static inline void semantic_analysis(Context *ctx)
- {
- type_check_ast(ctx, ctx->ast);
- } // semantic_analysis
- // !!! FIXME: isn't this a cut-and-paste of somewhere else?
- static inline int64 strtoi64(const char *str, unsigned int len)
- {
- int64 retval = 0;
- int64 mult = 1;
- int i = 0;
- while ((len) && (*str == ' '))
- {
- str++;
- len--;
- } // while
- if ((len) && (*str == '-'))
- {
- mult = -1;
- str++;
- len--;
- } // if
- while (i < len)
- {
- const char ch = str[i];
- if ((ch < '0') || (ch > '9'))
- break;
- i++;
- } // while
- while (--i >= 0)
- {
- const char ch = str[i];
- retval += ((int64) (ch - '0')) * mult;
- mult *= 10;
- } // while
- return retval;
- } // strtoi64
- // !!! FIXME: isn't this a cut-and-paste of somewhere else?
- static inline double strtodouble(const char *_str, unsigned int len)
- {
- // !!! FIXME: laziness prevails.
- char *str = (char *) alloca(len+1);
- memcpy(str, _str, len);
- str[len] = '\0';
- return strtod(str, NULL);
- } // strtodouble
- #if 0
- // This does not check correctness (POSITIONT993842 passes, etc).
- static int is_semantic(const Context *ctx, const char *token,
- const unsigned int tokenlen)
- {
- static const char *names[] = {
- "BINORMAL", "BLENDINDICES", "BLENDWEIGHT",
- "COLOR", "NORMAL", "POSITION", "POSITIONT", "PSIZE", "TANGENT",
- "TEXCOORD", "FOG", "TESSFACTOR", "TEXCOORD", "VFACE", "VPOS",
- "DEPTH", NULL
- };
- // !!! FIXME: DX10 has SV_* ("System Value Semantics").
- const char **i;
- for (i = names; *i; i++)
- {
- const char *name = *i;
- const size_t namelen = strlen(name);
- if (tokenlen < namelen)
- continue;
- else if (memcmp(token, name, namelen) != 0)
- continue;
- for (name += namelen; *name; name++)
- {
- if ((*name < '0') || (*name > '9'))
- break;
- } // for
- if (*name == '\0')
- return 1;
- } // for
- return 0;
- } // is_semantic
- #endif
- static int convert_to_lemon_token(Context *ctx, const char *token,
- unsigned int tokenlen, const Token tokenval)
- {
- switch (tokenval)
- {
- case ((Token) ','): return TOKEN_HLSL_COMMA;
- case ((Token) '='): return TOKEN_HLSL_ASSIGN;
- case ((Token) TOKEN_ADDASSIGN): return TOKEN_HLSL_ADDASSIGN;
- case ((Token) TOKEN_SUBASSIGN): return TOKEN_HLSL_SUBASSIGN;
- case ((Token) TOKEN_MULTASSIGN): return TOKEN_HLSL_MULASSIGN;
- case ((Token) TOKEN_DIVASSIGN): return TOKEN_HLSL_DIVASSIGN;
- case ((Token) TOKEN_MODASSIGN): return TOKEN_HLSL_MODASSIGN;
- case ((Token) TOKEN_LSHIFTASSIGN): return TOKEN_HLSL_LSHIFTASSIGN;
- case ((Token) TOKEN_RSHIFTASSIGN): return TOKEN_HLSL_RSHIFTASSIGN;
- case ((Token) TOKEN_ANDASSIGN): return TOKEN_HLSL_ANDASSIGN;
- case ((Token) TOKEN_ORASSIGN): return TOKEN_HLSL_ORASSIGN;
- case ((Token) TOKEN_XORASSIGN): return TOKEN_HLSL_XORASSIGN;
- case ((Token) '?'): return TOKEN_HLSL_QUESTION;
- case ((Token) TOKEN_OROR): return TOKEN_HLSL_OROR;
- case ((Token) TOKEN_ANDAND): return TOKEN_HLSL_ANDAND;
- case ((Token) '|'): return TOKEN_HLSL_OR;
- case ((Token) '^'): return TOKEN_HLSL_XOR;
- case ((Token) '&'): return TOKEN_HLSL_AND;
- case ((Token) TOKEN_EQL): return TOKEN_HLSL_EQL;
- case ((Token) TOKEN_NEQ): return TOKEN_HLSL_NEQ;
- case ((Token) '<'): return TOKEN_HLSL_LT;
- case ((Token) TOKEN_LEQ): return TOKEN_HLSL_LEQ;
- case ((Token) '>'): return TOKEN_HLSL_GT;
- case ((Token) TOKEN_GEQ): return TOKEN_HLSL_GEQ;
- case ((Token) TOKEN_LSHIFT): return TOKEN_HLSL_LSHIFT;
- case ((Token) TOKEN_RSHIFT): return TOKEN_HLSL_RSHIFT;
- case ((Token) '+'): return TOKEN_HLSL_PLUS;
- case ((Token) '-'): return TOKEN_HLSL_MINUS;
- case ((Token) '*'): return TOKEN_HLSL_STAR;
- case ((Token) '/'): return TOKEN_HLSL_SLASH;
- case ((Token) '%'): return TOKEN_HLSL_PERCENT;
- case ((Token) '!'): return TOKEN_HLSL_EXCLAMATION;
- case ((Token) '~'): return TOKEN_HLSL_COMPLEMENT;
- case ((Token) TOKEN_DECREMENT): return TOKEN_HLSL_MINUSMINUS;
- case ((Token) TOKEN_INCREMENT): return TOKEN_HLSL_PLUSPLUS;
- case ((Token) '.'): return TOKEN_HLSL_DOT;
- case ((Token) '['): return TOKEN_HLSL_LBRACKET;
- case ((Token) ']'): return TOKEN_HLSL_RBRACKET;
- case ((Token) '('): return TOKEN_HLSL_LPAREN;
- case ((Token) ')'): return TOKEN_HLSL_RPAREN;
- case ((Token) TOKEN_INT_LITERAL): return TOKEN_HLSL_INT_CONSTANT;
- case ((Token) TOKEN_FLOAT_LITERAL): return TOKEN_HLSL_FLOAT_CONSTANT;
- case ((Token) TOKEN_STRING_LITERAL): return TOKEN_HLSL_STRING_LITERAL;
- case ((Token) ':'): return TOKEN_HLSL_COLON;
- case ((Token) ';'): return TOKEN_HLSL_SEMICOLON;
- case ((Token) '{'): return TOKEN_HLSL_LBRACE;
- case ((Token) '}'): return TOKEN_HLSL_RBRACE;
- //case ((Token) TOKEN_PP_PRAGMA): return TOKEN_HLSL_PRAGMA;
- //case ((Token) '\n'): return TOKEN_HLSL_NEWLINE;
- case ((Token) TOKEN_IDENTIFIER):
- #define tokencmp(t) ((tokenlen == strlen(t)) && (memcmp(token, t, tokenlen) == 0))
- //case ((Token) ''): return TOKEN_HLSL_TYPECAST
- //if (tokencmp("")) return TOKEN_HLSL_TYPE_NAME
- //if (tokencmp("...")) return TOKEN_HLSL_ELIPSIS
- if (tokencmp("else")) return TOKEN_HLSL_ELSE;
- if (tokencmp("inline")) return TOKEN_HLSL_INLINE;
- if (tokencmp("void")) return TOKEN_HLSL_VOID;
- if (tokencmp("in")) return TOKEN_HLSL_IN;
- if (tokencmp("inout")) return TOKEN_HLSL_INOUT;
- if (tokencmp("out")) return TOKEN_HLSL_OUT;
- if (tokencmp("uniform")) return TOKEN_HLSL_UNIFORM;
- if (tokencmp("linear")) return TOKEN_HLSL_LINEAR;
- if (tokencmp("centroid")) return TOKEN_HLSL_CENTROID;
- if (tokencmp("nointerpolation")) return TOKEN_HLSL_NOINTERPOLATION;
- if (tokencmp("noperspective")) return TOKEN_HLSL_NOPERSPECTIVE;
- if (tokencmp("sample")) return TOKEN_HLSL_SAMPLE;
- if (tokencmp("struct")) return TOKEN_HLSL_STRUCT;
- if (tokencmp("typedef")) return TOKEN_HLSL_TYPEDEF;
- if (tokencmp("const")) return TOKEN_HLSL_CONST;
- if (tokencmp("packoffset")) return TOKEN_HLSL_PACKOFFSET;
- if (tokencmp("register")) return TOKEN_HLSL_REGISTER;
- if (tokencmp("extern")) return TOKEN_HLSL_EXTERN;
- if (tokencmp("shared")) return TOKEN_HLSL_SHARED;
- if (tokencmp("static")) return TOKEN_HLSL_STATIC;
- if (tokencmp("volatile")) return TOKEN_HLSL_VOLATILE;
- if (tokencmp("row_major")) return TOKEN_HLSL_ROWMAJOR;
- if (tokencmp("column_major")) return TOKEN_HLSL_COLUMNMAJOR;
- if (tokencmp("bool")) return TOKEN_HLSL_BOOL;
- if (tokencmp("int")) return TOKEN_HLSL_INT;
- if (tokencmp("uint")) return TOKEN_HLSL_UINT;
- if (tokencmp("half")) return TOKEN_HLSL_HALF;
- if (tokencmp("float")) return TOKEN_HLSL_FLOAT;
- if (tokencmp("double")) return TOKEN_HLSL_DOUBLE;
- if (tokencmp("string")) return TOKEN_HLSL_STRING;
- if (tokencmp("snorm")) return TOKEN_HLSL_SNORM;
- if (tokencmp("unorm")) return TOKEN_HLSL_UNORM;
- if (tokencmp("buffer")) return TOKEN_HLSL_BUFFER;
- if (tokencmp("vector")) return TOKEN_HLSL_VECTOR;
- if (tokencmp("matrix")) return TOKEN_HLSL_MATRIX;
- if (tokencmp("break")) return TOKEN_HLSL_BREAK;
- if (tokencmp("continue")) return TOKEN_HLSL_CONTINUE;
- if (tokencmp("discard")) return TOKEN_HLSL_DISCARD;
- if (tokencmp("return")) return TOKEN_HLSL_RETURN;
- if (tokencmp("while")) return TOKEN_HLSL_WHILE;
- if (tokencmp("for")) return TOKEN_HLSL_FOR;
- if (tokencmp("unroll")) return TOKEN_HLSL_UNROLL;
- if (tokencmp("loop")) return TOKEN_HLSL_LOOP;
- if (tokencmp("do")) return TOKEN_HLSL_DO;
- if (tokencmp("if")) return TOKEN_HLSL_IF;
- if (tokencmp("branch")) return TOKEN_HLSL_BRANCH;
- if (tokencmp("flatten")) return TOKEN_HLSL_FLATTEN;
- if (tokencmp("switch")) return TOKEN_HLSL_SWITCH;
- if (tokencmp("forcecase")) return TOKEN_HLSL_FORCECASE;
- if (tokencmp("call")) return TOKEN_HLSL_CALL;
- if (tokencmp("case")) return TOKEN_HLSL_CASE;
- if (tokencmp("default")) return TOKEN_HLSL_DEFAULT;
- if (tokencmp("sampler")) return TOKEN_HLSL_SAMPLER;
- if (tokencmp("sampler1D")) return TOKEN_HLSL_SAMPLER1D;
- if (tokencmp("sampler2D")) return TOKEN_HLSL_SAMPLER2D;
- if (tokencmp("sampler3D")) return TOKEN_HLSL_SAMPLER3D;
- if (tokencmp("samplerCUBE")) return TOKEN_HLSL_SAMPLERCUBE;
- if (tokencmp("sampler_state")) return TOKEN_HLSL_SAMPLER_STATE;
- if (tokencmp("SamplerState")) return TOKEN_HLSL_SAMPLERSTATE;
- if (tokencmp("true")) return TOKEN_HLSL_TRUE;
- if (tokencmp("false")) return TOKEN_HLSL_FALSE;
- if (tokencmp("SamplerComparisonState")) return TOKEN_HLSL_SAMPLERCOMPARISONSTATE;
- if (tokencmp("isolate")) return TOKEN_HLSL_ISOLATE;
- if (tokencmp("maxInstructionCount")) return TOKEN_HLSL_MAXINSTRUCTIONCOUNT;
- if (tokencmp("noExpressionOptimizations")) return TOKEN_HLSL_NOEXPRESSIONOPTIMIZATIONS;
- if (tokencmp("unused")) return TOKEN_HLSL_UNUSED;
- if (tokencmp("xps")) return TOKEN_HLSL_XPS;
- #undef tokencmp
- // get a canonical copy of the string now, as we'll need it.
- token = stringcache_len(ctx->strcache, token, tokenlen);
- if (get_usertype(ctx, token) != NULL)
- return TOKEN_HLSL_USERTYPE;
- return TOKEN_HLSL_IDENTIFIER;
- case TOKEN_EOI: return 0;
- default: assert(0 && "unexpected token from lexer\n"); return 0;
- } // switch
- return 0;
- } // convert_to_lemon_token
- static void delete_ir(Context *ctx, void *_ir); // !!! FIXME: move this code around.
- static void destroy_context(Context *ctx)
- {
- if (ctx != NULL)
- {
- MOJOSHADER_free f = ((ctx->free != NULL) ? ctx->free : MOJOSHADER_internal_free);
- void *d = ctx->malloc_data;
- size_t i = 0;
- // !!! FIXME: this is kinda hacky.
- const size_t count = buffer_size(ctx->garbage) / sizeof (void *);
- if (count > 0)
- {
- void **garbage = (void **) buffer_flatten(ctx->garbage);
- if (garbage != NULL)
- {
- for (i = 0; i < count; i++)
- f(garbage[i], d);
- f(garbage, d);
- } // if
- } // if
- buffer_destroy(ctx->garbage);
- delete_compilation_unit(ctx, (MOJOSHADER_astCompilationUnit*)ctx->ast);
- destroy_symbolmap(ctx, &ctx->usertypes);
- destroy_symbolmap(ctx, &ctx->variables);
- stringcache_destroy(ctx->strcache);
- errorlist_destroy(ctx->errors);
- errorlist_destroy(ctx->warnings);
- if (ctx->ir != NULL)
- {
- for (i = 0; i <= ctx->user_func_index; i++)
- delete_ir(ctx, ctx->ir[i]);
- f(ctx->ir, d);
- } // if
- // !!! FIXME: more to clean up here, now.
- f(ctx, d);
- } // if
- } // destroy_context
- static Context *build_context(MOJOSHADER_malloc m, MOJOSHADER_free f, void *d)
- {
- if (!m) m = MOJOSHADER_internal_malloc;
- if (!f) f = MOJOSHADER_internal_free;
- Context *ctx = (Context *) m(sizeof (Context), d);
- if (ctx == NULL)
- return NULL;
- memset(ctx, '\0', sizeof (Context));
- ctx->malloc = m;
- ctx->free = f;
- ctx->malloc_data = d;
- //ctx->parse_phase = MOJOSHADER_PARSEPHASE_NOTSTARTED;
- create_symbolmap(ctx, &ctx->usertypes); // !!! FIXME: check for failure.
- create_symbolmap(ctx, &ctx->variables); // !!! FIXME: check for failure.
- ctx->strcache = stringcache_create(MallocBridge, FreeBridge, ctx); // !!! FIXME: check for failure.
- ctx->errors = errorlist_create(MallocBridge, FreeBridge, ctx); // !!! FIXME: check for failure.
- ctx->warnings = errorlist_create(MallocBridge, FreeBridge, ctx); // !!! FIXME: check for failure.
- // !!! FIXME: this feels hacky.
- ctx->garbage = buffer_create(256*sizeof(void*),MallocBridge,FreeBridge,ctx); // !!! FIXME: check for failure.
- ctx->dt_none.type = MOJOSHADER_AST_DATATYPE_NONE;
- ctx->dt_bool.type = MOJOSHADER_AST_DATATYPE_BOOL;
- ctx->dt_int.type = MOJOSHADER_AST_DATATYPE_INT;
- ctx->dt_uint.type = MOJOSHADER_AST_DATATYPE_UINT;
- ctx->dt_float.type = MOJOSHADER_AST_DATATYPE_FLOAT;
- ctx->dt_float_snorm.type = MOJOSHADER_AST_DATATYPE_FLOAT_SNORM;
- ctx->dt_float_unorm.type = MOJOSHADER_AST_DATATYPE_FLOAT_UNORM;
- ctx->dt_half.type = MOJOSHADER_AST_DATATYPE_HALF;
- ctx->dt_double.type = MOJOSHADER_AST_DATATYPE_DOUBLE;
- ctx->dt_string.type = MOJOSHADER_AST_DATATYPE_STRING;
- ctx->dt_sampler1d.type = MOJOSHADER_AST_DATATYPE_SAMPLER_1D;
- ctx->dt_sampler2d.type = MOJOSHADER_AST_DATATYPE_SAMPLER_2D;
- ctx->dt_sampler3d.type = MOJOSHADER_AST_DATATYPE_SAMPLER_3D;
- ctx->dt_samplercube.type = MOJOSHADER_AST_DATATYPE_SAMPLER_CUBE;
- ctx->dt_samplerstate.type = MOJOSHADER_AST_DATATYPE_SAMPLER_STATE;
- ctx->dt_samplercompstate.type = MOJOSHADER_AST_DATATYPE_SAMPLER_COMPARISON_STATE;
- #define INIT_DT_BUFFER(t) \
- ctx->dt_buf_##t.type = MOJOSHADER_AST_DATATYPE_BUFFER; \
- ctx->dt_buf_##t.buffer.base = &ctx->dt_##t;
- INIT_DT_BUFFER(bool);
- INIT_DT_BUFFER(int);
- INIT_DT_BUFFER(uint);
- INIT_DT_BUFFER(half);
- INIT_DT_BUFFER(float);
- INIT_DT_BUFFER(double);
- INIT_DT_BUFFER(float_snorm);
- INIT_DT_BUFFER(float_unorm);
- #undef INIT_DT_BUFFER
- return ctx;
- } // build_context
- // This macro salsa is kinda nasty, but it's the smallest, least error-prone
- // way I can find to do this well in C. :/
- #define ADD_INTRINSIC(fn, ret, params) do { \
- push_function(ctx, fn, \
- build_function_datatype(ctx, ret, STATICARRAYLEN(params), params, 1), \
- 0); \
- } while (0)
- #define ADD_INTRINSIC_VECTOR(typestr, code) do { \
- const MOJOSHADER_astDataType *dt; \
- dt = get_usertype(ctx, typestr "1"); code; \
- dt = get_usertype(ctx, typestr "2"); code; \
- dt = get_usertype(ctx, typestr "3"); code; \
- dt = get_usertype(ctx, typestr "4"); code; \
- } while (0)
- #define ADD_INTRINSIC_VECTOR_FLOAT(code) { \
- ADD_INTRINSIC_VECTOR("float", code); \
- ADD_INTRINSIC_VECTOR("half", code); \
- ADD_INTRINSIC_VECTOR("double", code); \
- }
- #define ADD_INTRINSIC_VECTOR_INT(code) { \
- ADD_INTRINSIC_VECTOR("int", code); \
- ADD_INTRINSIC_VECTOR("uint", code); \
- }
- #define ADD_INTRINSIC_VECTOR_BOOL(code) { \
- ADD_INTRINSIC_VECTOR("bool", code); \
- }
- #define ADD_INTRINSIC_MATRIX(typestr, code) do { \
- const MOJOSHADER_astDataType *dt; \
- dt = get_usertype(ctx, typestr "1x1"); code; \
- dt = get_usertype(ctx, typestr "1x2"); code; \
- dt = get_usertype(ctx, typestr "1x3"); code; \
- dt = get_usertype(ctx, typestr "1x4"); code; \
- dt = get_usertype(ctx, typestr "2x1"); code; \
- dt = get_usertype(ctx, typestr "2x2"); code; \
- dt = get_usertype(ctx, typestr "2x3"); code; \
- dt = get_usertype(ctx, typestr "2x4"); code; \
- dt = get_usertype(ctx, typestr "3x1"); code; \
- dt = get_usertype(ctx, typestr "3x2"); code; \
- dt = get_usertype(ctx, typestr "3x3"); code; \
- dt = get_usertype(ctx, typestr "3x4"); code; \
- dt = get_usertype(ctx, typestr "4x1"); code; \
- dt = get_usertype(ctx, typestr "4x2"); code; \
- dt = get_usertype(ctx, typestr "4x3"); code; \
- dt = get_usertype(ctx, typestr "4x4"); code; \
- } while (0)
- #define ADD_INTRINSIC_MATRIX_FLOAT(code) { \
- ADD_INTRINSIC_MATRIX("float", code); \
- ADD_INTRINSIC_MATRIX("half", code); \
- ADD_INTRINSIC_MATRIX("double", code); \
- }
- #define ADD_INTRINSIC_MATRIX_INT(code) { \
- ADD_INTRINSIC_MATRIX("int", code); \
- ADD_INTRINSIC_MATRIX("uint", code); \
- }
- #define ADD_INTRINSIC_MATRIX_BOOL(code) { \
- ADD_INTRINSIC_MATRIX("bool", code); \
- }
- #define ADD_INTRINSIC_ANY(scalar, typestr, code) do { \
- { const MOJOSHADER_astDataType *dt = scalar; code; } \
- ADD_INTRINSIC_VECTOR(typestr, code); \
- ADD_INTRINSIC_MATRIX(typestr, code); \
- } while (0)
- #define ADD_INTRINSIC_ANY_FLOAT(code) do { \
- ADD_INTRINSIC_ANY(&ctx->dt_double, "double", code); \
- ADD_INTRINSIC_ANY(&ctx->dt_half, "half", code); \
- ADD_INTRINSIC_ANY(&ctx->dt_float, "float", code); \
- } while (0)
- #define ADD_INTRINSIC_ANY_INT(code) do { \
- ADD_INTRINSIC_ANY(&ctx->dt_uint, "uint", code); \
- ADD_INTRINSIC_ANY(&ctx->dt_int, "int", code); \
- } while (0)
- #define ADD_INTRINSIC_ANY_BOOL(code) ADD_INTRINSIC_ANY(&ctx->dt_bool, "bool", code)
- static void add_intrinsic1(Context *ctx, const char *fn,
- const MOJOSHADER_astDataType *ret,
- const MOJOSHADER_astDataType *dt1)
- {
- const MOJOSHADER_astDataType *params[] = { dt1 };
- ADD_INTRINSIC(fn, ret, params);
- } // add_intrinsic1
- static void add_intrinsic2(Context *ctx, const char *fn,
- const MOJOSHADER_astDataType *ret,
- const MOJOSHADER_astDataType *dt1,
- const MOJOSHADER_astDataType *dt2)
- {
- const MOJOSHADER_astDataType *params[] = { dt1, dt2 };
- ADD_INTRINSIC(fn, ret, params);
- } // add_intrinsic2
- static void add_intrinsic3(Context *ctx, const char *fn,
- const MOJOSHADER_astDataType *ret,
- const MOJOSHADER_astDataType *dt1,
- const MOJOSHADER_astDataType *dt2,
- const MOJOSHADER_astDataType *dt3)
- {
- const MOJOSHADER_astDataType *params[] = { dt1, dt2, dt3 };
- ADD_INTRINSIC(fn, ret, params);
- } // add_intrinsic3
- static void add_intrinsic4(Context *ctx, const char *fn,
- const MOJOSHADER_astDataType *ret,
- const MOJOSHADER_astDataType *dt1,
- const MOJOSHADER_astDataType *dt2,
- const MOJOSHADER_astDataType *dt3,
- const MOJOSHADER_astDataType *dt4)
- {
- const MOJOSHADER_astDataType *params[] = { dt1, dt2, dt3, dt4 };
- ADD_INTRINSIC(fn, ret, params);
- } // add_intrinsic4
- // PLEASE NOTE that add_intrinsic*() is called AFTER the various
- // ADD_INTRINSIC_* macros, even though these look like functions that
- // should be called first. They might be called multiple times by the macro.
- // The variable "dt" is defined by the macro for use by your code.
- static void add_intrinsic_SAME1_ANYf(Context *ctx, const char *fn)
- {
- ADD_INTRINSIC_ANY_FLOAT(add_intrinsic1(ctx, fn, dt, dt));
- } // add_intrinsic_SAME1_ANYf
- static void add_intrinsic_SAME1_ANYfi(Context *ctx, const char *fn)
- {
- ADD_INTRINSIC_ANY_INT(add_intrinsic1(ctx, fn, dt, dt));
- add_intrinsic_SAME1_ANYf(ctx, fn);
- } // add_intrinsic_SAME1_ANYfi
- static void add_intrinsic_BOOL_ANYf(Context *ctx, const char *fn)
- {
- ADD_INTRINSIC_ANY_FLOAT(add_intrinsic1(ctx, fn, &ctx->dt_bool, dt));
- } // add_intrinsic_BOOL_ANYf
- static void add_intrinsic_BOOL_ANYfib(Context *ctx, const char *fn)
- {
- ADD_INTRINSIC_ANY_BOOL(add_intrinsic1(ctx, fn, &ctx->dt_bool, dt));
- ADD_INTRINSIC_ANY_INT(add_intrinsic1(ctx, fn, &ctx->dt_bool, dt));
- add_intrinsic_BOOL_ANYf(ctx, fn);
- } // add_intrinsic_BOOL_ANYfib
- static void add_intrinsic_SAME1_ANYf_SAME1(Context *ctx, const char *fn)
- {
- ADD_INTRINSIC_ANY_FLOAT(add_intrinsic2(ctx, fn, dt, dt, dt));
- } // add_intrinsic_SAME1_ANYf_SAME1
- static void add_intrinsic_SAME1_ANYfi_SAME1(Context *ctx, const char *fn)
- {
- ADD_INTRINSIC_ANY_INT(add_intrinsic2(ctx, fn, dt, dt, dt));
- add_intrinsic_SAME1_ANYf_SAME1(ctx, fn);
- } // add_intrinsic_SAME1_ANYfi_SAME1
- static void add_intrinsic_SAME1_ANYf_SAME1_SAME1(Context *ctx, const char *fn)
- {
- ADD_INTRINSIC_ANY_FLOAT(add_intrinsic3(ctx, fn, dt, dt, dt, dt));
- } // add_intrinsic_SAME1_ANYf_SAME1_SAME1
- static void add_intrinsic_SAME1_ANYfi_SAME1_SAME1(Context *ctx, const char *fn)
- {
- ADD_INTRINSIC_ANY_INT(add_intrinsic3(ctx, fn, dt, dt, dt, dt));
- add_intrinsic_SAME1_ANYf_SAME1_SAME1(ctx, fn);
- } // add_intrinsic_SAME1_ANYfi_SAME1_SAME1
- static void add_intrinsic_SAME1_Mfib(Context *ctx, const char *fn)
- {
- ADD_INTRINSIC_MATRIX_BOOL(add_intrinsic1(ctx, fn, dt, dt));
- ADD_INTRINSIC_MATRIX_INT(add_intrinsic1(ctx, fn, dt, dt));
- ADD_INTRINSIC_MATRIX_FLOAT(add_intrinsic1(ctx, fn, dt, dt));
- } // add_intrinsic_SAME1_Mfib
- static void add_intrinsic_SAME1_Vf(Context *ctx, const char *fn)
- {
- ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic1(ctx, fn, dt, dt));
- } // add_intrinsic_SAME1_Vf
- static void add_intrinsic_SAME1_Vf_SAME1_SAME1(Context *ctx, const char *fn)
- {
- ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic3(ctx, fn, dt, dt, dt, dt));
- } // add_intrinsic_SAME1_Vf_SAME1_SAME1
- static void add_intrinsic_SAME1_Vf_SAME1_f(Context *ctx, const char *fn)
- {
- ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic3(ctx, fn, dt, dt, dt, dt->user.details->vector.base));
- } // add_intrinsic_SAME1_Vf_SAME1_f
- static void add_intrinsic_VOID_ANYf(Context *ctx, const char *fn)
- {
- ADD_INTRINSIC_ANY_FLOAT(add_intrinsic1(ctx, fn, NULL, dt));
- } // add_intrinsic_VOID_ANYf
- static void add_intrinsic_VOID_ANYf_SAME1_SAME1(Context *ctx, const char *fn)
- {
- ADD_INTRINSIC_ANY_FLOAT(add_intrinsic3(ctx, fn, NULL, dt, dt, dt));
- } // add_intrinsic_VOID_ANYf_SAME1_SAME1
- static void add_intrinsic_f_SQUAREMATRIXf(Context *ctx, const char *fn)
- {
- add_intrinsic1(ctx, fn, &ctx->dt_float, get_usertype(ctx, "float1x1"));
- add_intrinsic1(ctx, fn, &ctx->dt_float, get_usertype(ctx, "float2x2"));
- add_intrinsic1(ctx, fn, &ctx->dt_float, get_usertype(ctx, "float3x3"));
- add_intrinsic1(ctx, fn, &ctx->dt_float, get_usertype(ctx, "float4x4"));
- } // add_intrinsic_f_SQUAREMATRIXf
- static void add_intrinsic_f_Vf(Context *ctx, const char *fn)
- {
- ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic1(ctx, fn, dt->user.details->vector.base, dt));
- } // add_intrinsic_f_Vf
- static void add_intrinsic_fi_Vfi_SAME1(Context *ctx, const char *fn)
- {
- ADD_INTRINSIC_VECTOR_INT(add_intrinsic2(ctx, fn, dt->user.details->vector.base, dt, dt));
- ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic2(ctx, fn, dt->user.details->vector.base, dt, dt));
- } // add_intrinsic_fi_Vfi_SAME1
- static void add_intrinsic_f_Vf_SAME1(Context *ctx, const char *fn)
- {
- ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic2(ctx, fn, dt->user.details->vector.base, dt, dt));
- } // add_intrinsic_f_Vf_SAME1
- static void add_intrinsic_3f_3f_3f(Context *ctx, const char *fn)
- {
- const MOJOSHADER_astDataType *dt = get_usertype(ctx, "float3");
- add_intrinsic2(ctx, fn, dt, dt, dt);
- } // add_intrinsic_3f_3f_3f
- static void add_intrinsic_4f_f_f_f(Context *ctx, const char *fn)
- {
- const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
- const MOJOSHADER_astDataType *f = &ctx->dt_float;
- add_intrinsic3(ctx, fn, f4, f, f, f);
- } // add_intrinsic_4f_f_f_f
- static void add_intrinsic_4f_s1_4f(Context *ctx, const char *fn)
- {
- const MOJOSHADER_astDataType *dt = get_usertype(ctx, "float4");
- add_intrinsic2(ctx, fn, dt, &ctx->dt_sampler1d, dt);
- } // add_intrinsic_4f_s1_4f
- static void add_intrinsic_4f_s1_f(Context *ctx, const char *fn)
- {
- const MOJOSHADER_astDataType *dt = get_usertype(ctx, "float4");
- add_intrinsic2(ctx, fn, dt, &ctx->dt_sampler1d, &ctx->dt_float);
- } // add_intrinsic_4f_s1_f
- static void add_intrinsic_4f_s1_f_f_f(Context *ctx, const char *fn)
- {
- const MOJOSHADER_astDataType *dt = get_usertype(ctx, "float4");
- const MOJOSHADER_astDataType *f = &ctx->dt_float;
- add_intrinsic4(ctx, fn, dt, &ctx->dt_sampler1d, f, f, f);
- } // add_intrinsic_4f_s1_f_f_f
- static void add_intrinsic_4f_s2_2f(Context *ctx, const char *fn)
- {
- const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
- const MOJOSHADER_astDataType *f2 = get_usertype(ctx, "float2");
- add_intrinsic2(ctx, fn, f4, &ctx->dt_sampler2d, f2);
- } // add_intrinsic_4f_s2_2f
- static void add_intrinsic_4f_s2_2f_2f_2f(Context *ctx, const char *fn)
- {
- const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
- const MOJOSHADER_astDataType *f2 = get_usertype(ctx, "float2");
- add_intrinsic4(ctx, fn, f4, &ctx->dt_sampler2d, f2, f2, f2);
- } // add_intrinsic_4f_s2_2f_2f_2f
- static void add_intrinsic_4f_s2_4f(Context *ctx, const char *fn)
- {
- const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
- add_intrinsic2(ctx, fn, f4, &ctx->dt_sampler2d, f4);
- } // add_intrinsic_4f_s2_4f
- static void add_intrinsic_4f_s3_3f(Context *ctx, const char *fn)
- {
- const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
- const MOJOSHADER_astDataType *f3 = get_usertype(ctx, "float3");
- add_intrinsic2(ctx, fn, f4, &ctx->dt_sampler3d, f3);
- } // add_intrinsic_4f_s3_3f
- static void add_intrinsic_4f_s3_3f_3f_3f(Context *ctx, const char *fn)
- {
- const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
- const MOJOSHADER_astDataType *f3 = get_usertype(ctx, "float3");
- add_intrinsic4(ctx, fn, f4, &ctx->dt_sampler3d, f3, f3, f3);
- } // add_intrinsic_4f_s3_3f_3f_3f
- static void add_intrinsic_4f_s3_4f(Context *ctx, const char *fn)
- {
- const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
- add_intrinsic2(ctx, fn, f4, &ctx->dt_sampler3d, f4);
- } // add_intrinsic_4f_s3_4f
- static void add_intrinsic_4f_sc_3f(Context *ctx, const char *fn)
- {
- const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
- const MOJOSHADER_astDataType *f3 = get_usertype(ctx, "float3");
- add_intrinsic2(ctx, fn, f4, &ctx->dt_samplercube, f3);
- } // add_intrinsic_4f_sc_3f
- static void add_intrinsic_4f_sc_3f_3f_3f(Context *ctx, const char *fn)
- {
- const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
- const MOJOSHADER_astDataType *f3 = get_usertype(ctx, "float3");
- add_intrinsic4(ctx, fn, f4, &ctx->dt_samplercube, f3, f3, f3);
- } // add_intrinsic_4f_sc_3f_3f_3f
- static void add_intrinsic_4f_sc_4f(Context *ctx, const char *fn)
- {
- const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
- add_intrinsic2(ctx, fn, f4, &ctx->dt_samplercube, f4);
- } // add_intrinsic_4f_sc_4f
- static void add_intrinsic_4i_4f(Context *ctx, const char *fn)
- {
- const MOJOSHADER_astDataType *i4 = get_usertype(ctx, "int4");
- const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
- add_intrinsic1(ctx, fn, i4, f4);
- } // add_intrinsic_4i_4f
- static void add_intrinsic_mul(Context *ctx, const char *fn)
- {
- // mul() is nasty, since there's a bunch of overloads that aren't just
- // related to vector size.
- // !!! FIXME: needs half, double, uint...
- const MOJOSHADER_astDataType *dtf = &ctx->dt_float;
- const MOJOSHADER_astDataType *dti = &ctx->dt_int;
- const MOJOSHADER_astDataType *f1 = get_usertype(ctx, "float1");
- const MOJOSHADER_astDataType *f2 = get_usertype(ctx, "float2");
- const MOJOSHADER_astDataType *f3 = get_usertype(ctx, "float3");
- const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
- const MOJOSHADER_astDataType *i1 = get_usertype(ctx, "int1");
- const MOJOSHADER_astDataType *i2 = get_usertype(ctx, "int2");
- const MOJOSHADER_astDataType *i3 = get_usertype(ctx, "int3");
- const MOJOSHADER_astDataType *i4 = get_usertype(ctx, "int4");
- const MOJOSHADER_astDataType *f1x1 = get_usertype(ctx, "float1x1");
- const MOJOSHADER_astDataType *f1x2 = get_usertype(ctx, "float1x2");
- const MOJOSHADER_astDataType *f1x3 = get_usertype(ctx, "float1x3");
- const MOJOSHADER_astDataType *f1x4 = get_usertype(ctx, "float1x4");
- const MOJOSHADER_astDataType *f2x1 = get_usertype(ctx, "float2x1");
- const MOJOSHADER_astDataType *f2x2 = get_usertype(ctx, "float2x2");
- const MOJOSHADER_astDataType *f2x3 = get_usertype(ctx, "float2x3");
- const MOJOSHADER_astDataType *f2x4 = get_usertype(ctx, "float2x4");
- const MOJOSHADER_astDataType *f3x1 = get_usertype(ctx, "float3x1");
- const MOJOSHADER_astDataType *f3x2 = get_usertype(ctx, "float3x2");
- const MOJOSHADER_astDataType *f3x3 = get_usertype(ctx, "float3x3");
- const MOJOSHADER_astDataType *f3x4 = get_usertype(ctx, "float3x4");
- const MOJOSHADER_astDataType *f4x1 = get_usertype(ctx, "float4x1");
- const MOJOSHADER_astDataType *f4x2 = get_usertype(ctx, "float4x2");
- const MOJOSHADER_astDataType *f4x3 = get_usertype(ctx, "float4x3");
- const MOJOSHADER_astDataType *f4x4 = get_usertype(ctx, "float4x4");
- const MOJOSHADER_astDataType *i1x1 = get_usertype(ctx, "int1x1");
- const MOJOSHADER_astDataType *i1x2 = get_usertype(ctx, "int1x2");
- const MOJOSHADER_astDataType *i1x3 = get_usertype(ctx, "int1x3");
- const MOJOSHADER_astDataType *i1x4 = get_usertype(ctx, "int1x4");
- const MOJOSHADER_astDataType *i2x1 = get_usertype(ctx, "int2x1");
- const MOJOSHADER_astDataType *i2x2 = get_usertype(ctx, "int2x2");
- const MOJOSHADER_astDataType *i2x3 = get_usertype(ctx, "int2x3");
- const MOJOSHADER_astDataType *i2x4 = get_usertype(ctx, "int2x4");
- const MOJOSHADER_astDataType *i3x1 = get_usertype(ctx, "int3x1");
- const MOJOSHADER_astDataType *i3x2 = get_usertype(ctx, "int3x2");
- const MOJOSHADER_astDataType *i3x3 = get_usertype(ctx, "int3x3");
- const MOJOSHADER_astDataType *i3x4 = get_usertype(ctx, "int3x4");
- const MOJOSHADER_astDataType *i4x1 = get_usertype(ctx, "int4x1");
- const MOJOSHADER_astDataType *i4x2 = get_usertype(ctx, "int4x2");
- const MOJOSHADER_astDataType *i4x3 = get_usertype(ctx, "int4x3");
- const MOJOSHADER_astDataType *i4x4 = get_usertype(ctx, "int4x4");
- // scalar * scalar
- add_intrinsic2(ctx, fn, dti, dti, dti);
- add_intrinsic2(ctx, fn, dtf, dtf, dtf);
- // scalar * vector
- ADD_INTRINSIC_VECTOR_INT(add_intrinsic2(ctx, fn, dt, dti, dt));
- ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic2(ctx, fn, dt, dtf, dt));
- // scalar * matrix
- ADD_INTRINSIC_MATRIX_INT(add_intrinsic2(ctx, fn, dt, dti, dt));
- ADD_INTRINSIC_MATRIX_FLOAT(add_intrinsic2(ctx, fn, dt, dtf, dt));
- // vector * scalar
- ADD_INTRINSIC_VECTOR_INT(add_intrinsic2(ctx, fn, dt, dt, dti));
- ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic2(ctx, fn, dt, dt, dtf));
- // vector * vector
- ADD_INTRINSIC_VECTOR_INT(add_intrinsic2(ctx, fn, dti, dt, dt));
- ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic2(ctx, fn, dtf, dt, dt));
- // vector * matrix
- add_intrinsic2(ctx, fn, i1, i1, i1x1);
- add_intrinsic2(ctx, fn, i2, i1, i1x2);
- add_intrinsic2(ctx, fn, i3, i1, i1x3);
- add_intrinsic2(ctx, fn, i4, i1, i1x4);
- add_intrinsic2(ctx, fn, i1, i2, i2x1);
- add_intrinsic2(ctx, fn, i2, i2, i2x2);
- add_intrinsic2(ctx, fn, i3, i2, i2x3);
- add_intrinsic2(ctx, fn, i4, i2, i2x4);
- add_intrinsic2(ctx, fn, i1, i3, i3x1);
- add_intrinsic2(ctx, fn, i2, i3, i3x2);
- add_intrinsic2(ctx, fn, i3, i3, i3x3);
- add_intrinsic2(ctx, fn, i4, i3, i3x4);
- add_intrinsic2(ctx, fn, i1, i4, i4x1);
- add_intrinsic2(ctx, fn, i2, i4, i4x2);
- add_intrinsic2(ctx, fn, i3, i4, i4x3);
- add_intrinsic2(ctx, fn, i4, i4, i4x4);
- add_intrinsic2(ctx, fn, f1, f1, f1x1);
- add_intrinsic2(ctx, fn, f2, f1, f1x2);
- add_intrinsic2(ctx, fn, f3, f1, f1x3);
- add_intrinsic2(ctx, fn, f4, f1, f1x4);
- add_intrinsic2(ctx, fn, f1, f2, f2x1);
- add_intrinsic2(ctx, fn, f2, f2, f2x2);
- add_intrinsic2(ctx, fn, f3, f2, f2x3);
- add_intrinsic2(ctx, fn, f4, f2, f2x4);
- add_intrinsic2(ctx, fn, f1, f3, f3x1);
- add_intrinsic2(ctx, fn, f2, f3, f3x2);
- add_intrinsic2(ctx, fn, f3, f3, f3x3);
- add_intrinsic2(ctx, fn, f4, f3, f3x4);
- add_intrinsic2(ctx, fn, f1, f4, f4x1);
- add_intrinsic2(ctx, fn, f2, f4, f4x2);
- add_intrinsic2(ctx, fn, f3, f4, f4x3);
- add_intrinsic2(ctx, fn, f4, f4, f4x4);
- // matrix * scalar
- ADD_INTRINSIC_MATRIX_INT(add_intrinsic2(ctx, fn, dt, dt, dti));
- ADD_INTRINSIC_MATRIX_FLOAT(add_intrinsic2(ctx, fn, dt, dt, dtf));
- // matrix * vector
- add_intrinsic2(ctx, fn, i1, i1x1, i1);
- add_intrinsic2(ctx, fn, i1, i1x2, i2);
- add_intrinsic2(ctx, fn, i1, i1x3, i3);
- add_intrinsic2(ctx, fn, i1, i1x4, i4);
- add_intrinsic2(ctx, fn, i2, i2x1, i1);
- add_intrinsic2(ctx, fn, i2, i2x2, i2);
- add_intrinsic2(ctx, fn, i2, i2x3, i3);
- add_intrinsic2(ctx, fn, i2, i2x4, i4);
- add_intrinsic2(ctx, fn, i3, i3x1, i1);
- add_intrinsic2(ctx, fn, i3, i3x2, i2);
- add_intrinsic2(ctx, fn, i3, i3x3, i3);
- add_intrinsic2(ctx, fn, i3, i3x4, i4);
- add_intrinsic2(ctx, fn, i4, i4x1, i1);
- add_intrinsic2(ctx, fn, i4, i4x2, i2);
- add_intrinsic2(ctx, fn, i4, i4x3, i3);
- add_intrinsic2(ctx, fn, i4, i4x4, i4);
- add_intrinsic2(ctx, fn, f1, f1x1, f1);
- add_intrinsic2(ctx, fn, f1, f1x2, f2);
- add_intrinsic2(ctx, fn, f1, f1x3, f3);
- add_intrinsic2(ctx, fn, f1, f1x4, f4);
- add_intrinsic2(ctx, fn, f2, f2x1, f1);
- add_intrinsic2(ctx, fn, f2, f2x2, f2);
- add_intrinsic2(ctx, fn, f2, f2x3, f3);
- add_intrinsic2(ctx, fn, f2, f2x4, f4);
- add_intrinsic2(ctx, fn, f3, f3x1, f1);
- add_intrinsic2(ctx, fn, f3, f3x2, f2);
- add_intrinsic2(ctx, fn, f3, f3x3, f3);
- add_intrinsic2(ctx, fn, f3, f3x4, f4);
- add_intrinsic2(ctx, fn, f4, f4x1, f1);
- add_intrinsic2(ctx, fn, f4, f4x2, f2);
- add_intrinsic2(ctx, fn, f4, f4x3, f3);
- add_intrinsic2(ctx, fn, f4, f4x4, f4);
- // matrix * matrix
- add_intrinsic2(ctx, fn, i1x1, i1x1, i1x1);
- add_intrinsic2(ctx, fn, i1x2, i1x1, i1x2);
- add_intrinsic2(ctx, fn, i1x3, i1x1, i1x3);
- add_intrinsic2(ctx, fn, i1x4, i1x1, i1x4);
- add_intrinsic2(ctx, fn, i1x1, i1x2, i2x1);
- add_intrinsic2(ctx, fn, i1x2, i1x2, i2x2);
- add_intrinsic2(ctx, fn, i1x3, i1x2, i2x3);
- add_intrinsic2(ctx, fn, i1x4, i1x2, i2x4);
- add_intrinsic2(ctx, fn, i1x1, i1x3, i3x1);
- add_intrinsic2(ctx, fn, i1x2, i1x3, i3x2);
- add_intrinsic2(ctx, fn, i1x3, i1x3, i3x3);
- add_intrinsic2(ctx, fn, i1x4, i1x3, i3x4);
- add_intrinsic2(ctx, fn, i1x1, i1x4, i4x1);
- add_intrinsic2(ctx, fn, i1x2, i1x4, i4x2);
- add_intrinsic2(ctx, fn, i1x3, i1x4, i4x3);
- add_intrinsic2(ctx, fn, i1x4, i1x4, i4x4);
- add_intrinsic2(ctx, fn, i2x1, i2x1, i1x1);
- add_intrinsic2(ctx, fn, i2x2, i2x1, i1x2);
- add_intrinsic2(ctx, fn, i2x3, i2x1, i1x3);
- add_intrinsic2(ctx, fn, i2x4, i2x1, i1x4);
- add_intrinsic2(ctx, fn, i2x1, i2x2, i2x1);
- add_intrinsic2(ctx, fn, i2x2, i2x2, i2x2);
- add_intrinsic2(ctx, fn, i2x3, i2x2, i2x3);
- add_intrinsic2(ctx, fn, i2x4, i2x2, i2x4);
- add_intrinsic2(ctx, fn, i2x1, i2x3, i3x1);
- add_intrinsic2(ctx, fn, i2x2, i2x3, i3x2);
- add_intrinsic2(ctx, fn, i2x3, i2x3, i3x3);
- add_intrinsic2(ctx, fn, i2x4, i2x3, i3x4);
- add_intrinsic2(ctx, fn, i2x1, i2x4, i4x1);
- add_intrinsic2(ctx, fn, i2x2, i2x4, i4x2);
- add_intrinsic2(ctx, fn, i2x3, i2x4, i4x3);
- add_intrinsic2(ctx, fn, i2x4, i2x4, i4x4);
- add_intrinsic2(ctx, fn, i3x1, i3x1, i1x1);
- add_intrinsic2(ctx, fn, i3x2, i3x1, i1x2);
- add_intrinsic2(ctx, fn, i3x3, i3x1, i1x3);
- add_intrinsic2(ctx, fn, i3x4, i3x1, i1x4);
- add_intrinsic2(ctx, fn, i3x1, i3x2, i2x1);
- add_intrinsic2(ctx, fn, i3x2, i3x2, i2x2);
- add_intrinsic2(ctx, fn, i3x3, i3x2, i2x3);
- add_intrinsic2(ctx, fn, i3x4, i3x2, i2x4);
- add_intrinsic2(ctx, fn, i3x1, i3x3, i3x1);
- add_intrinsic2(ctx, fn, i3x2, i3x3, i3x2);
- add_intrinsic2(ctx, fn, i3x3, i3x3, i3x3);
- add_intrinsic2(ctx, fn, i3x4, i3x3, i3x4);
- add_intrinsic2(ctx, fn, i3x1, i3x4, i4x1);
- add_intrinsic2(ctx, fn, i3x2, i3x4, i4x2);
- add_intrinsic2(ctx, fn, i3x3, i3x4, i4x3);
- add_intrinsic2(ctx, fn, i3x4, i3x4, i4x4);
- add_intrinsic2(ctx, fn, i4x1, i4x1, i1x1);
- add_intrinsic2(ctx, fn, i4x2, i4x1, i1x2);
- add_intrinsic2(ctx, fn, i4x3, i4x1, i1x3);
- add_intrinsic2(ctx, fn, i4x4, i4x1, i1x4);
- add_intrinsic2(ctx, fn, i4x1, i4x2, i2x1);
- add_intrinsic2(ctx, fn, i4x2, i4x2, i2x2);
- add_intrinsic2(ctx, fn, i4x3, i4x2, i2x3);
- add_intrinsic2(ctx, fn, i4x4, i4x2, i2x4);
- add_intrinsic2(ctx, fn, i4x1, i4x3, i3x1);
- add_intrinsic2(ctx, fn, i4x2, i4x3, i3x2);
- add_intrinsic2(ctx, fn, i4x3, i4x3, i3x3);
- add_intrinsic2(ctx, fn, i4x4, i4x3, i3x4);
- add_intrinsic2(ctx, fn, i4x1, i4x4, i4x1);
- add_intrinsic2(ctx, fn, i4x2, i4x4, i4x2);
- add_intrinsic2(ctx, fn, i4x3, i4x4, i4x3);
- add_intrinsic2(ctx, fn, i4x4, i4x4, i4x4);
- add_intrinsic2(ctx, fn, f1x1, f1x1, f1x1);
- add_intrinsic2(ctx, fn, f1x2, f1x1, f1x2);
- add_intrinsic2(ctx, fn, f1x3, f1x1, f1x3);
- add_intrinsic2(ctx, fn, f1x4, f1x1, f1x4);
- add_intrinsic2(ctx, fn, f1x1, f1x2, f2x1);
- add_intrinsic2(ctx, fn, f1x2, f1x2, f2x2);
- add_intrinsic2(ctx, fn, f1x3, f1x2, f2x3);
- add_intrinsic2(ctx, fn, f1x4, f1x2, f2x4);
- add_intrinsic2(ctx, fn, f1x1, f1x3, f3x1);
- add_intrinsic2(ctx, fn, f1x2, f1x3, f3x2);
- add_intrinsic2(ctx, fn, f1x3, f1x3, f3x3);
- add_intrinsic2(ctx, fn, f1x4, f1x3, f3x4);
- add_intrinsic2(ctx, fn, f1x1, f1x4, f4x1);
- add_intrinsic2(ctx, fn, f1x2, f1x4, f4x2);
- add_intrinsic2(ctx, fn, f1x3, f1x4, f4x3);
- add_intrinsic2(ctx, fn, f1x4, f1x4, f4x4);
- add_intrinsic2(ctx, fn, f2x1, f2x1, f1x1);
- add_intrinsic2(ctx, fn, f2x2, f2x1, f1x2);
- add_intrinsic2(ctx, fn, f2x3, f2x1, f1x3);
- add_intrinsic2(ctx, fn, f2x4, f2x1, f1x4);
- add_intrinsic2(ctx, fn, f2x1, f2x2, f2x1);
- add_intrinsic2(ctx, fn, f2x2, f2x2, f2x2);
- add_intrinsic2(ctx, fn, f2x3, f2x2, f2x3);
- add_intrinsic2(ctx, fn, f2x4, f2x2, f2x4);
- add_intrinsic2(ctx, fn, f2x1, f2x3, f3x1);
- add_intrinsic2(ctx, fn, f2x2, f2x3, f3x2);
- add_intrinsic2(ctx, fn, f2x3, f2x3, f3x3);
- add_intrinsic2(ctx, fn, f2x4, f2x3, f3x4);
- add_intrinsic2(ctx, fn, f2x1, f2x4, f4x1);
- add_intrinsic2(ctx, fn, f2x2, f2x4, f4x2);
- add_intrinsic2(ctx, fn, f2x3, f2x4, f4x3);
- add_intrinsic2(ctx, fn, f2x4, f2x4, f4x4);
- add_intrinsic2(ctx, fn, f3x1, f3x1, f1x1);
- add_intrinsic2(ctx, fn, f3x2, f3x1, f1x2);
- add_intrinsic2(ctx, fn, f3x3, f3x1, f1x3);
- add_intrinsic2(ctx, fn, f3x4, f3x1, f1x4);
- add_intrinsic2(ctx, fn, f3x1, f3x2, f2x1);
- add_intrinsic2(ctx, fn, f3x2, f3x2, f2x2);
- add_intrinsic2(ctx, fn, f3x3, f3x2, f2x3);
- add_intrinsic2(ctx, fn, f3x4, f3x2, f2x4);
- add_intrinsic2(ctx, fn, f3x1, f3x3, f3x1);
- add_intrinsic2(ctx, fn, f3x2, f3x3, f3x2);
- add_intrinsic2(ctx, fn, f3x3, f3x3, f3x3);
- add_intrinsic2(ctx, fn, f3x4, f3x3, f3x4);
- add_intrinsic2(ctx, fn, f3x1, f3x4, f4x1);
- add_intrinsic2(ctx, fn, f3x2, f3x4, f4x2);
- add_intrinsic2(ctx, fn, f3x3, f3x4, f4x3);
- add_intrinsic2(ctx, fn, f3x4, f3x4, f4x4);
- add_intrinsic2(ctx, fn, f4x1, f4x1, f1x1);
- add_intrinsic2(ctx, fn, f4x2, f4x1, f1x2);
- add_intrinsic2(ctx, fn, f4x3, f4x1, f1x3);
- add_intrinsic2(ctx, fn, f4x4, f4x1, f1x4);
- add_intrinsic2(ctx, fn, f4x1, f4x2, f2x1);
- add_intrinsic2(ctx, fn, f4x2, f4x2, f2x2);
- add_intrinsic2(ctx, fn, f4x3, f4x2, f2x3);
- add_intrinsic2(ctx, fn, f4x4, f4x2, f2x4);
- add_intrinsic2(ctx, fn, f4x1, f4x3, f3x1);
- add_intrinsic2(ctx, fn, f4x2, f4x3, f3x2);
- add_intrinsic2(ctx, fn, f4x3, f4x3, f3x3);
- add_intrinsic2(ctx, fn, f4x4, f4x3, f3x4);
- add_intrinsic2(ctx, fn, f4x1, f4x4, f4x1);
- add_intrinsic2(ctx, fn, f4x2, f4x4, f4x2);
- add_intrinsic2(ctx, fn, f4x3, f4x4, f4x3);
- add_intrinsic2(ctx, fn, f4x4, f4x4, f4x4);
- } // add_intrinsic_mul
- static void init_builtins(Context *ctx)
- {
- // add in standard typedefs...
- const struct
- {
- const char *str;
- const MOJOSHADER_astDataType *datatype;
- } types[] = {
- { "bool", &ctx->dt_bool },
- { "int", &ctx->dt_int },
- { "uint", &ctx->dt_uint },
- { "half", &ctx->dt_half },
- { "float", &ctx->dt_float },
- { "double", &ctx->dt_double },
- };
- int i, j, k;
- for (i = 0; i < STATICARRAYLEN(types); i++)
- {
- char buf[32];
- int len;
- const MOJOSHADER_astDataType *dt;
- for (j = 1; j <= 4; j++)
- {
- // "float2"
- dt = new_datatype_vector(ctx, types[i].datatype, j);
- len = snprintf(buf, sizeof (buf), "%s%d", types[i].str, j);
- push_usertype(ctx, stringcache_len(ctx->strcache, buf, len), dt);
- for (k = 1; k <= 4; k++)
- {
- // "float2x2"
- dt = new_datatype_matrix(ctx, types[i].datatype, j, k);
- len = snprintf(buf, sizeof (buf), "%s%dx%d", types[i].str,j,k);
- push_usertype(ctx, stringcache_len(ctx->strcache,buf,len), dt);
- } // for
- } // for
- } // for
- // !!! FIXME: block these out by pixel/vertex/etc shader.
- // !!! FIXME: calculate actual shader model (or maybe just let bytecode verifier throw up?).
- const int shader_model = 3;
- if (shader_model >= 1)
- {
- add_intrinsic_SAME1_ANYfi(ctx, stringcache(ctx->strcache, "abs"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "acos"));
- add_intrinsic_BOOL_ANYfib(ctx, stringcache(ctx->strcache, "all"));
- add_intrinsic_BOOL_ANYfib(ctx, stringcache(ctx->strcache, "any"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "asin"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "atan"));
- add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "atan2"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "ceil"));
- add_intrinsic_SAME1_ANYfi_SAME1_SAME1(ctx, stringcache(ctx->strcache, "clamp"));
- add_intrinsic_VOID_ANYf(ctx, stringcache(ctx->strcache, "clip"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "cos"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "cosh"));
- add_intrinsic_3f_3f_3f(ctx, stringcache(ctx->strcache, "cross"));
- add_intrinsic_4i_4f(ctx, stringcache(ctx->strcache, "D3DCOLORtoUBYTE4"));
- add_intrinsic_f_Vf_SAME1(ctx, stringcache(ctx->strcache, "distance"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "degrees"));
- add_intrinsic_f_SQUAREMATRIXf(ctx, stringcache(ctx->strcache, "determinant"));
- add_intrinsic_fi_Vfi_SAME1(ctx, stringcache(ctx->strcache, "dot"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "exp"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "exp2"));
- add_intrinsic_SAME1_Vf_SAME1_SAME1(ctx, stringcache(ctx->strcache, "faceforward"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "floor"));
- add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "fmod"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "frac"));
- add_intrinsic_BOOL_ANYf(ctx, stringcache(ctx->strcache, "isfinite"));
- add_intrinsic_BOOL_ANYf(ctx, stringcache(ctx->strcache, "isinf"));
- add_intrinsic_BOOL_ANYf(ctx, stringcache(ctx->strcache, "isnan"));
- add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "ldexp"));
- add_intrinsic_f_Vf(ctx, stringcache(ctx->strcache, "length"));
- add_intrinsic_SAME1_ANYf_SAME1_SAME1(ctx, stringcache(ctx->strcache, "lerp"));
- add_intrinsic_4f_f_f_f(ctx, stringcache(ctx->strcache, "lit"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "log"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "log10"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "log2"));
- add_intrinsic_SAME1_ANYfi_SAME1(ctx, stringcache(ctx->strcache, "max"));
- add_intrinsic_SAME1_ANYfi_SAME1(ctx, stringcache(ctx->strcache, "min"));
- add_intrinsic_SAME1_ANYfi_SAME1(ctx, stringcache(ctx->strcache, "modf")); // !!! FIXME: out var?
- add_intrinsic_mul(ctx, stringcache(ctx->strcache, "mul"));
- add_intrinsic_f_Vf(ctx, stringcache(ctx->strcache, "noise"));
- add_intrinsic_SAME1_Vf(ctx, stringcache(ctx->strcache, "normalize"));
- add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "pow"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "radians"));
- add_intrinsic_SAME1_ANYfi_SAME1(ctx, stringcache(ctx->strcache, "reflect"));
- add_intrinsic_SAME1_Vf_SAME1_f(ctx, stringcache(ctx->strcache, "refract"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "round"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "rsqrt"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "saturate"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "sign"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "sin"));
- add_intrinsic_VOID_ANYf_SAME1_SAME1(ctx, stringcache(ctx->strcache, "sincos")); // !!! FIXME: out var?
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "sinh"));
- add_intrinsic_SAME1_ANYf_SAME1_SAME1(ctx, stringcache(ctx->strcache, "smoothstep"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "sqrt"));
- add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "step"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "tan"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "tanh"));
- add_intrinsic_4f_s1_f(ctx, stringcache(ctx->strcache, "tex1D"));
- add_intrinsic_4f_s2_2f(ctx, stringcache(ctx->strcache, "tex2D"));
- add_intrinsic_4f_s3_3f(ctx, stringcache(ctx->strcache, "tex3D"));
- add_intrinsic_4f_sc_3f(ctx, stringcache(ctx->strcache, "texCUBE"));
- add_intrinsic_SAME1_Mfib(ctx, stringcache(ctx->strcache, "transpose"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "trunc"));
- } // if
- if (shader_model >= 2)
- {
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "ddx"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "ddy"));
- add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "frexp"));
- add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "fwidth"));
- add_intrinsic_4f_s1_f_f_f(ctx, stringcache(ctx->strcache, "tex1D"));
- add_intrinsic_4f_s1_4f(ctx, stringcache(ctx->strcache, "tex1Dbias"));
- add_intrinsic_4f_s1_f_f_f(ctx, stringcache(ctx->strcache, "tex1Dgrad"));
- add_intrinsic_4f_s1_4f(ctx, stringcache(ctx->strcache, "tex1Dproj"));
- add_intrinsic_4f_s2_2f_2f_2f(ctx, stringcache(ctx->strcache, "tex2D"));
- add_intrinsic_4f_s2_4f(ctx, stringcache(ctx->strcache, "tex2Dbias"));
- add_intrinsic_4f_s2_2f_2f_2f(ctx, stringcache(ctx->strcache, "tex2Dgrad"));
- add_intrinsic_4f_s2_4f(ctx, stringcache(ctx->strcache, "tex2Dproj"));
- add_intrinsic_4f_s3_3f_3f_3f(ctx, stringcache(ctx->strcache, "tex3D"));
- add_intrinsic_4f_s3_4f(ctx, stringcache(ctx->strcache, "tex3Dbias"));
- add_intrinsic_4f_s3_3f_3f_3f(ctx, stringcache(ctx->strcache, "tex3Dgrad"));
- add_intrinsic_4f_s3_4f(ctx, stringcache(ctx->strcache, "tex3Dproj"));
- add_intrinsic_4f_sc_3f_3f_3f(ctx, stringcache(ctx->strcache, "texCUBE"));
- add_intrinsic_4f_sc_4f(ctx, stringcache(ctx->strcache, "texCUBEbias"));
- add_intrinsic_4f_sc_3f_3f_3f(ctx, stringcache(ctx->strcache, "texCUBEgrad"));
- add_intrinsic_4f_sc_4f(ctx, stringcache(ctx->strcache, "texCUBEproj"));
- } // if
- if (shader_model >= 3)
- {
- add_intrinsic_4f_s1_4f(ctx, stringcache(ctx->strcache, "tex1Dlod"));
- add_intrinsic_4f_s2_4f(ctx, stringcache(ctx->strcache, "tex2Dlod"));
- add_intrinsic_4f_s3_4f(ctx, stringcache(ctx->strcache, "tex3Dlod"));
- add_intrinsic_4f_sc_4f(ctx, stringcache(ctx->strcache, "texCUBElod"));
- } // if
- } // init_builtins
- // parse the source code into an AST.
- static void parse_source(Context *ctx, const char *filename,
- const char *source, unsigned int sourcelen,
- const MOJOSHADER_preprocessorDefine *defines,
- unsigned int define_count,
- MOJOSHADER_includeOpen include_open,
- MOJOSHADER_includeClose include_close)
- {
- TokenData data;
- unsigned int tokenlen;
- Token tokenval;
- const char *token;
- int lemon_token;
- const char *fname;
- Preprocessor *pp;
- void *parser;
- if (!include_open) include_open = MOJOSHADER_internal_include_open;
- if (!include_close) include_close = MOJOSHADER_internal_include_close;
- pp = preprocessor_start(filename, source, sourcelen, include_open,
- include_close, defines, define_count, 0,
- MallocBridge, FreeBridge, ctx);
- if (pp == NULL)
- {
- assert(ctx->out_of_memory); // shouldn't fail for any other reason.
- return;
- } // if
- parser = ParseHLSLAlloc(ctx->malloc, ctx->malloc_data);
- if (parser == NULL)
- {
- assert(ctx->out_of_memory); // shouldn't fail for any other reason.
- preprocessor_end(pp);
- return;
- } // if
- // !!! FIXME: check if (parser == NULL)...
- init_builtins(ctx);
- SymbolScope *start_scope = ctx->usertypes.scope;
- #if DEBUG_COMPILER_PARSER
- ParseHLSLTrace(stdout, "COMPILER: ");
- #endif
- // Run the preprocessor/lexer/parser...
- int is_pragma = 0; // !!! FIXME: remove this later when we can parse #pragma.
- int skipping = 0; // !!! FIXME: remove this later when we can parse #pragma.
- do {
- token = preprocessor_nexttoken(pp, &tokenlen, &tokenval);
- if (ctx->out_of_memory)
- break;
- fname = preprocessor_sourcepos(pp, &ctx->sourceline);
- ctx->sourcefile = fname ? stringcache(ctx->strcache, fname) : 0;
- if ((tokenval == TOKEN_HASH) || (tokenval == TOKEN_HASHHASH))
- tokenval = TOKEN_BAD_CHARS;
- if (tokenval == TOKEN_BAD_CHARS)
- {
- fail(ctx, "Bad characters in source file");
- continue;
- } // else if
- else if (tokenval == TOKEN_PREPROCESSING_ERROR)
- {
- fail(ctx, token); // this happens to be null-terminated.
- continue;
- } // else if
- else if (tokenval == TOKEN_PP_PRAGMA)
- {
- assert(!is_pragma);
- is_pragma = 1;
- skipping = 1;
- continue;
- }
- else if (tokenval == ((Token) '\n'))
- {
- assert(is_pragma);
- is_pragma = 0;
- skipping = 0;
- continue;
- }
- else if (skipping)
- {
- continue;
- }
- // !!! FIXME: this is a mess, decide who should be doing this stuff, and only do it once.
- lemon_token = convert_to_lemon_token(ctx, token, tokenlen, tokenval);
- switch (lemon_token)
- {
- case TOKEN_HLSL_INT_CONSTANT:
- data.i64 = strtoi64(token, tokenlen);
- break;
- case TOKEN_HLSL_FLOAT_CONSTANT:
- data.dbl = strtodouble(token, tokenlen);
- break;
- case TOKEN_HLSL_USERTYPE:
- data.string = stringcache_len(ctx->strcache, token, tokenlen);
- data.datatype = get_usertype(ctx, data.string); // !!! FIXME: do we need this? It's kind of useless during parsing.
- assert(data.datatype != NULL);
- break;
- case TOKEN_HLSL_STRING_LITERAL:
- case TOKEN_HLSL_IDENTIFIER:
- data.string = stringcache_len(ctx->strcache, token, tokenlen);
- break;
- default:
- data.i64 = 0;
- break;
- } // switch
- ParseHLSL(parser, lemon_token, data, ctx);
- // this probably isn't perfect, but it's good enough for surviving
- // the parse. We'll sort out correctness once we have a tree.
- if (lemon_token == TOKEN_HLSL_LBRACE)
- push_scope(ctx);
- else if (lemon_token == TOKEN_HLSL_RBRACE)
- pop_scope(ctx);
- } while (tokenval != TOKEN_EOI);
- // Clean out extra usertypes; they are dummies until semantic analysis.
- while (ctx->usertypes.scope != start_scope)
- pop_symbol(ctx, &ctx->usertypes);
- ParseHLSLFree(parser, ctx->free, ctx->malloc_data);
- preprocessor_end(pp);
- } // parse_source
- /* Intermediate representation... */
- static inline int generate_ir_label(Context *ctx)
- {
- return ctx->ir_label_count++;
- } // generate_ir_label
- static inline int generate_ir_temp(Context *ctx)
- {
- return ctx->ir_temp_count++;
- } // generate_ir_temp
- static const LoopLabels *push_ir_loop(Context *ctx, const int isswitch)
- {
- // !!! FIXME: cache these allocations?
- LoopLabels *retval = (LoopLabels *)Malloc(ctx, sizeof (LoopLabels));
- if (retval)
- {
- retval->start = (isswitch) ? -1 : generate_ir_label(ctx);
- retval->end = generate_ir_label(ctx);
- retval->prev = ctx->ir_loop;
- ctx->ir_loop = retval;
- } // if
- return retval;
- } // push_ir_loop
- static void pop_ir_loop(Context *ctx)
- {
- assert(ctx->ir_loop != NULL);
- LoopLabels *labels = ctx->ir_loop;
- ctx->ir_loop = ctx->ir_loop->prev;
- Free(ctx, labels);
- } // pop_ir_loop
- #define NEW_IR_NODE(retval, cls, typ) \
- cls *retval = (cls *) Malloc(ctx, sizeof (cls)); \
- do { \
- if (retval == NULL) { return NULL; } \
- retval->ir.type = typ; \
- retval->ir.filename = ctx->sourcefile; \
- retval->ir.line = ctx->sourceline; \
- } while (0)
- #define NEW_IR_EXPR(retval, cls, typ, dt, numelems) \
- cls *retval = (cls *) Malloc(ctx, sizeof (cls)); \
- do { \
- if (retval == NULL) { return NULL; } \
- retval->info.ir.type = typ; \
- retval->info.ir.filename = ctx->sourcefile; \
- retval->info.ir.line = ctx->sourceline; \
- retval->info.type = dt; \
- retval->info.elements = numelems; \
- } while (0)
- // syntactic sugar.
- static inline MOJOSHADER_irNode *build_ir(Context *ctx, void *_ast);
- static inline MOJOSHADER_irExpression *build_ir_expr(Context *ctx, void *_ast)
- {
- MOJOSHADER_irNode *retval = build_ir(ctx, _ast);
- assert(!retval || (retval->ir.type > MOJOSHADER_IR_START_RANGE_EXPR));
- assert(!retval || (retval->ir.type < MOJOSHADER_IR_END_RANGE_EXPR));
- return (MOJOSHADER_irExpression *) retval;
- } // build_ir_expr
- static inline MOJOSHADER_irStatement *build_ir_stmt(Context *ctx, void *_ast)
- {
- MOJOSHADER_irNode *retval = build_ir(ctx, _ast);
- assert(!retval || (retval->ir.type > MOJOSHADER_IR_START_RANGE_STMT));
- assert(!retval || (retval->ir.type < MOJOSHADER_IR_END_RANGE_STMT));
- return (MOJOSHADER_irStatement *) retval;
- } // build_ir_stmt
- static MOJOSHADER_irExpression *new_ir_binop(Context *ctx,
- const MOJOSHADER_irBinOpType op,
- MOJOSHADER_irExpression *left,
- MOJOSHADER_irExpression *right)
- {
- if ((!left) || (!right)) return NULL;
- NEW_IR_EXPR(retval, MOJOSHADER_irBinOp, MOJOSHADER_IR_BINOP, left->info.type, left->info.elements);
- assert(left->info.type == right->info.type);
- assert(left->info.elements == right->info.elements);
- retval->op = op;
- retval->left = left;
- retval->right = right;
- return (MOJOSHADER_irExpression *) retval;
- } // new_ir_binop
- static MOJOSHADER_irExpression *new_ir_eseq(Context *ctx,
- MOJOSHADER_irStatement *stmt,
- MOJOSHADER_irExpression *expr)
- {
- if (!expr) return NULL;
- NEW_IR_EXPR(retval, MOJOSHADER_irESeq, MOJOSHADER_IR_ESEQ, expr->info.type, expr->info.elements);
- retval->stmt = stmt;
- retval->expr = expr;
- return (MOJOSHADER_irExpression *) retval;
- } // new_ir_eseq
- static MOJOSHADER_irExpression *new_ir_temp(Context *ctx, const int index,
- const MOJOSHADER_astDataTypeType type,
- const int elements)
- {
- NEW_IR_EXPR(retval, MOJOSHADER_irTemp, MOJOSHADER_IR_TEMP, type, elements);
- retval->index = index;
- return (MOJOSHADER_irExpression *) retval;
- } // new_ir_temp
- #define NEW_IR_BINOP(op,l,r) new_ir_binop(ctx, MOJOSHADER_IR_BINOP_##op, l, r)
- #define EASY_IR_BINOP(op) \
- NEW_IR_BINOP(op, build_ir_expr(ctx, ast->binary.left), \
- build_ir_expr(ctx, ast->binary.right))
- // You have to fill in ->value yourself!
- static MOJOSHADER_irExpression *new_ir_constant(Context *ctx,
- const MOJOSHADER_astDataTypeType type,
- const int elements)
- {
- NEW_IR_EXPR(retval, MOJOSHADER_irConstant, MOJOSHADER_IR_CONSTANT, type, elements);
- return (MOJOSHADER_irExpression *) retval;
- } // new_ir_constant
- static MOJOSHADER_irExpression *new_ir_constint(Context *ctx, const int val)
- {
- NEW_IR_EXPR(retval, MOJOSHADER_irConstant, MOJOSHADER_IR_CONSTANT, MOJOSHADER_AST_DATATYPE_INT, 1);
- retval->value.ival[0] = val;
- return (MOJOSHADER_irExpression *) retval;
- } // new_ir_constint
- static MOJOSHADER_irExpression *new_ir_constfloat(Context *ctx, const float val)
- {
- NEW_IR_EXPR(retval, MOJOSHADER_irConstant, MOJOSHADER_IR_CONSTANT, MOJOSHADER_AST_DATATYPE_FLOAT, 1);
- retval->value.fval[0] = val;
- return (MOJOSHADER_irExpression *) retval;
- } // new_ir_constfloat
- static MOJOSHADER_irExpression *new_ir_constbool(Context *ctx, const int val)
- {
- // !!! FIXME: cache true and false in (ctx), ignore in delete_ir().
- NEW_IR_EXPR(retval, MOJOSHADER_irConstant, MOJOSHADER_IR_CONSTANT, MOJOSHADER_AST_DATATYPE_BOOL, 1);
- retval->value.ival[0] = val;
- return (MOJOSHADER_irExpression *) retval;
- } // new_ir_constbool
- static MOJOSHADER_irExpression *new_ir_convert(Context *ctx, MOJOSHADER_irExpression *expr,
- const MOJOSHADER_astDataTypeType type,
- const int elements)
- {
- NEW_IR_EXPR(retval, MOJOSHADER_irConvert, MOJOSHADER_IR_CONVERT, type, elements);
- retval->expr = expr;
- return (MOJOSHADER_irExpression *) retval;
- } // new_ir_convert
- static MOJOSHADER_irExpression *new_ir_construct(Context *ctx, MOJOSHADER_irExprList *args,
- const MOJOSHADER_astDataTypeType type,
- const int elements)
- {
- NEW_IR_EXPR(retval, MOJOSHADER_irConstruct, MOJOSHADER_IR_CONSTRUCT, type, elements);
- retval->args = args;
- return (MOJOSHADER_irExpression *) retval;
- } // new_ir_construct
- static MOJOSHADER_irExpression *new_ir_call(Context *ctx, const int index,
- MOJOSHADER_irExprList *args,
- const MOJOSHADER_astDataTypeType type,
- const int elements)
- {
- NEW_IR_EXPR(retval, MOJOSHADER_irCall, MOJOSHADER_IR_CALL, type, elements);
- retval->args = args;
- retval->index = index;
- return (MOJOSHADER_irExpression *) retval;
- } // new_ir_call
- static MOJOSHADER_irExpression *new_ir_swizzle(Context *ctx,
- MOJOSHADER_irExpression *expr,
- const char *channels,
- const MOJOSHADER_astDataTypeType type,
- const int elements)
- {
- NEW_IR_EXPR(retval, MOJOSHADER_irSwizzle, MOJOSHADER_IR_SWIZZLE, type, elements);
- retval->expr = expr;
- memcpy(retval->channels, channels, sizeof (retval->channels));
- return (MOJOSHADER_irExpression *) retval;
- } // new_ir_swizzle
- static MOJOSHADER_irExpression *new_ir_memory(Context *ctx, const int index,
- const MOJOSHADER_astDataTypeType type,
- const int elements)
- {
- NEW_IR_EXPR(retval, MOJOSHADER_irMemory, MOJOSHADER_IR_MEMORY, type, elements);
- retval->index = index;
- return (MOJOSHADER_irExpression *) retval;
- } // new_ir_memory
- static MOJOSHADER_irExpression *new_ir_array(Context *ctx,
- MOJOSHADER_irExpression *array,
- MOJOSHADER_irExpression *element,
- const MOJOSHADER_astDataTypeType type,
- const int elements)
- {
- NEW_IR_EXPR(retval, MOJOSHADER_irArray, MOJOSHADER_IR_ARRAY, type, elements);
- retval->array = array;
- retval->element = element;
- return (MOJOSHADER_irExpression *) retval;
- } // new_ir_array
- static MOJOSHADER_irStatement *new_ir_seq(Context *ctx,
- MOJOSHADER_irStatement *first,
- MOJOSHADER_irStatement *next)
- {
- assert((first != NULL) || (next != NULL));
- if (first == NULL) // don't generate a SEQ if unnecessary.
- return next;
- else if (next == NULL)
- return first;
- NEW_IR_NODE(retval, MOJOSHADER_irSeq, MOJOSHADER_IR_SEQ);
- retval->first = first;
- retval->next = next;
- return (MOJOSHADER_irStatement *) retval;
- } // new_ir_seq
- static MOJOSHADER_irStatement *new_ir_jump(Context *ctx, const int label)
- {
- NEW_IR_NODE(retval, MOJOSHADER_irJump, MOJOSHADER_IR_JUMP);
- retval->label = label;
- return (MOJOSHADER_irStatement *) retval;
- } // new_ir_jump
- static MOJOSHADER_irStatement *new_ir_cjump(Context *ctx,
- const MOJOSHADER_irConditionType cond,
- MOJOSHADER_irExpression *left,
- MOJOSHADER_irExpression *right,
- const int iftrue, const int iffalse)
- {
- NEW_IR_NODE(retval, MOJOSHADER_irCJump, MOJOSHADER_IR_CJUMP);
- retval->cond = cond;
- retval->left = left;
- retval->right = right;
- retval->iftrue = iftrue;
- retval->iffalse = iffalse;
- return (MOJOSHADER_irStatement *) retval;
- } // new_ir_cjump
- static MOJOSHADER_irStatement *new_ir_label(Context *ctx, const int index)
- {
- NEW_IR_NODE(retval, MOJOSHADER_irLabel, MOJOSHADER_IR_LABEL);
- retval->index = index;
- return (MOJOSHADER_irStatement *) retval;
- } // new_ir_label
- static MOJOSHADER_irStatement *new_ir_move(Context *ctx,
- MOJOSHADER_irExpression *dst,
- MOJOSHADER_irExpression *src,
- const int writemask)
- {
- NEW_IR_NODE(retval, MOJOSHADER_irMove, MOJOSHADER_IR_MOVE);
- assert(dst && src && (dst->info.type == src->info.type));
- assert(dst && src && (dst->info.elements == src->info.elements));
- retval->dst = dst;
- retval->src = src;
- retval->writemask = writemask;
- return (MOJOSHADER_irStatement *) retval;
- } // new_ir_move
- static MOJOSHADER_irStatement *new_ir_expr_stmt(Context *ctx, MOJOSHADER_irExpression *expr)
- {
- NEW_IR_NODE(retval, MOJOSHADER_irExprStmt, MOJOSHADER_IR_EXPR_STMT);
- retval->expr = expr;
- return (MOJOSHADER_irStatement *) retval;
- } // new_ir_expr_stmt
- static MOJOSHADER_irStatement *new_ir_discard(Context *ctx)
- {
- NEW_IR_NODE(retval, MOJOSHADER_irDiscard, MOJOSHADER_IR_DISCARD);
- return (MOJOSHADER_irStatement *) retval;
- } // new_ir_discard
- static MOJOSHADER_irExprList *new_ir_exprlist(Context *ctx, MOJOSHADER_irExpression *expr)
- {
- NEW_IR_NODE(retval, MOJOSHADER_irExprList, MOJOSHADER_IR_EXPRLIST);
- retval->expr = expr;
- retval->next = NULL;
- return (MOJOSHADER_irExprList *) retval;
- } // new_ir_exprlist
- // This handles most comparison operators (less-than, equals, etc...)
- static MOJOSHADER_irExpression *build_ir_compare(Context *ctx,
- const MOJOSHADER_irConditionType operation,
- MOJOSHADER_irExpression *left,
- MOJOSHADER_irExpression *right,
- MOJOSHADER_irExpression *tval,
- MOJOSHADER_irExpression *fval)
- {
- /* The gist...
- cjump x < y, t, f // '<' is whatever operation
- t:
- move tmp, tval
- jump join
- f:
- move tmp, fval
- join:
- */
- const int t = generate_ir_label(ctx);
- const int f = generate_ir_label(ctx);
- const int join = generate_ir_label(ctx);
- const int tmp = generate_ir_temp(ctx);
- assert(tval && fval && (tval->info.type == fval->info.type));
- assert(tval && fval && (tval->info.elements == fval->info.elements));
- const MOJOSHADER_astDataTypeType dt = tval->info.type;
- const int elements = tval->info.elements;
- return new_ir_eseq(ctx,
- new_ir_seq(ctx, new_ir_cjump(ctx, operation, left, right, t, f),
- new_ir_seq(ctx, new_ir_label(ctx, t),
- new_ir_seq(ctx, new_ir_move(ctx, new_ir_temp(ctx, tmp, dt, elements), tval, -1),
- new_ir_seq(ctx, new_ir_jump(ctx, join),
- new_ir_seq(ctx, new_ir_label(ctx, f),
- new_ir_seq(ctx, new_ir_move(ctx, new_ir_temp(ctx, tmp, dt, elements), fval, -1),
- new_ir_label(ctx, join))))))),
- new_ir_temp(ctx, tmp, dt, elements));
- } // build_ir_compare
- #define EASY_IR_COMPARE(op) \
- build_ir_compare(ctx, MOJOSHADER_IR_COND_##op, \
- build_ir_expr(ctx, ast->binary.left), \
- build_ir_expr(ctx, ast->binary.right), \
- new_ir_constbool(ctx, 1), \
- new_ir_constbool(ctx, 0))
- // This handles && and || operators.
- static MOJOSHADER_irExpression *build_ir_logical_and_or(Context *ctx,
- const MOJOSHADER_astExpressionBinary *ast,
- const int left_testval)
- {
- /* The gist...
- cjump left == left_testval, maybe, f
- maybe:
- cjump right == true, t, f
- t:
- move tmp, 1
- jump join
- f:
- move tmp, 0
- join:
- */
- assert(ast->left->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
- assert(ast->right->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
- const int t = generate_ir_label(ctx);
- const int f = generate_ir_label(ctx);
- const int maybe = generate_ir_label(ctx);
- const int join = generate_ir_label(ctx);
- const int tmp = generate_ir_temp(ctx);
- return new_ir_eseq(ctx,
- new_ir_seq(ctx, new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, ast->left), new_ir_constbool(ctx, left_testval), maybe, f),
- new_ir_seq(ctx, new_ir_label(ctx, maybe),
- new_ir_seq(ctx, new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, ast->right), new_ir_constbool(ctx, 1), t, f),
- new_ir_seq(ctx, new_ir_label(ctx, t),
- new_ir_seq(ctx, new_ir_move(ctx, new_ir_temp(ctx, tmp, MOJOSHADER_AST_DATATYPE_BOOL, 1), new_ir_constbool(ctx, 1), -1),
- new_ir_seq(ctx, new_ir_jump(ctx, join),
- new_ir_seq(ctx, new_ir_label(ctx, f),
- new_ir_seq(ctx, new_ir_move(ctx, new_ir_temp(ctx, tmp, MOJOSHADER_AST_DATATYPE_BOOL, 1), new_ir_constbool(ctx, 0), -1),
- new_ir_label(ctx, join))))))))),
- new_ir_temp(ctx, tmp, MOJOSHADER_AST_DATATYPE_BOOL, 1));
- } // build_ir_logical_and_or
- static inline MOJOSHADER_irExpression *build_ir_logical_and(Context *ctx,
- const MOJOSHADER_astExpressionBinary *ast)
- {
- // this needs to not evaluate (right) if (left) is false!
- return build_ir_logical_and_or(ctx, ast, 1);
- } // build_ir_logical_and
- static inline MOJOSHADER_irExpression *build_ir_logical_or(Context *ctx,
- const MOJOSHADER_astExpressionBinary *ast)
- {
- // this needs to not evaluate (right) if (left) is true!
- return build_ir_logical_and_or(ctx, ast, 0);
- } // build_ir_logical_or
- static inline MOJOSHADER_irStatement *build_ir_no_op(Context *ctx)
- {
- return new_ir_label(ctx, generate_ir_label(ctx));
- } // build_ir_no_op
- static MOJOSHADER_irStatement *build_ir_ifstmt(Context *ctx,
- const MOJOSHADER_astIfStatement *ast)
- {
- assert(ast->expr->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
- // !!! FIXME: ast->attributes?
- // IF statement without an ELSE.
- if (ast->else_statement == NULL)
- {
- /* The gist...
- cjump expr, t, join
- t:
- statement
- join:
- */
- const int t = generate_ir_label(ctx);
- const int join = generate_ir_label(ctx);
- return new_ir_seq(ctx, new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, ast->expr), new_ir_constbool(ctx, 1), t, join),
- new_ir_seq(ctx, new_ir_label(ctx, t),
- new_ir_seq(ctx, build_ir_stmt(ctx, ast->statement),
- new_ir_seq(ctx, new_ir_label(ctx, join),
- build_ir_stmt(ctx, ast->next)))));
- } // if
- // IF statement _with_ an ELSE.
- /* The gist...
- cjump expr, t, f
- t:
- statement
- jump join
- f:
- elsestatement
- join:
- */
- const int t = generate_ir_label(ctx);
- const int f = generate_ir_label(ctx);
- const int join = generate_ir_label(ctx);
- return new_ir_seq(ctx, new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, ast->expr), new_ir_constbool(ctx, 1), t, f),
- new_ir_seq(ctx, new_ir_label(ctx, t),
- new_ir_seq(ctx, build_ir_stmt(ctx, ast->statement),
- new_ir_seq(ctx, new_ir_jump(ctx, join),
- new_ir_seq(ctx, new_ir_label(ctx, f),
- new_ir_seq(ctx, build_ir_stmt(ctx, ast->else_statement),
- new_ir_seq(ctx, new_ir_label(ctx, join),
- build_ir_stmt(ctx, ast->next))))))));
- } // build_ir_ifstmt
- static MOJOSHADER_irStatement *build_ir_forstmt(Context *ctx,
- const MOJOSHADER_astForStatement *ast)
- {
- // !!! FIXME: ast->unroll
- assert(ast->looptest->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
- /* The gist...
- initializer // (or var_decl->initializer!)
- test:
- cjump looptest == true, loop, join
- loop:
- statement
- increment: // needs to be here; this is where "continue" jumps!
- counter
- jump test
- join:
- */
- const int test = generate_ir_label(ctx);
- const int loop = generate_ir_label(ctx);
- const LoopLabels *labels = push_ir_loop(ctx, 0);
- if (labels == NULL)
- return NULL; // out of memory...
- const int increment = labels->start;
- const int join = labels->end;
- assert( (ast->var_decl && !ast->initializer) ||
- (!ast->var_decl && ast->initializer) );
- MOJOSHADER_irStatement *init = NULL;
- if (ast->var_decl != NULL)
- {
- //sdfsdf
- // !!! FIXME: map the initializer to the variable? Need fix to var_decl parsing.
- // new_ir_move(ctx, FIXME MAP TO REGISTER ast->var_decl->index, build_ir_expr(ctx, ast->fsdf));
- // FIXME
- // init = build_ir_vardecl(ctx, ast->var_decl);
- } // if
- else
- {
- // init = build_ir_expr(ctx, ast->initializer);
- } // else
- MOJOSHADER_irStatement *retval =
- new_ir_seq(ctx, init,
- new_ir_seq(ctx, new_ir_label(ctx, test),
- new_ir_seq(ctx, new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, ast->looptest), new_ir_constbool(ctx, 1), loop, join),
- new_ir_seq(ctx, new_ir_label(ctx, loop),
- new_ir_seq(ctx, build_ir_stmt(ctx, ast->statement),
- new_ir_seq(ctx, new_ir_label(ctx, increment),
- new_ir_seq(ctx, new_ir_expr_stmt(ctx, build_ir_expr(ctx, ast->counter)),
- new_ir_seq(ctx, new_ir_jump(ctx, test),
- new_ir_label(ctx, join)))))))));
- pop_ir_loop(ctx);
- return new_ir_seq(ctx, retval, build_ir_stmt(ctx, ast->next));
- } // build_ir_forstmt
- static MOJOSHADER_irStatement *build_ir_whilestmt(Context *ctx,
- const MOJOSHADER_astWhileStatement *ast)
- {
- // !!! FIXME: ast->unroll
- assert(ast->expr->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
- /* The gist...
- loop:
- cjump expr == true, t, join
- t:
- statement
- jump loop
- join:
- */
- const LoopLabels *labels = push_ir_loop(ctx, 0);
- if (labels == NULL)
- return NULL; // out of memory...
- const int loop = labels->start;
- const int t = generate_ir_label(ctx);
- const int join = labels->end;
- MOJOSHADER_irStatement *retval =
- new_ir_seq(ctx, new_ir_label(ctx, loop),
- new_ir_seq(ctx, new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, ast->expr), new_ir_constbool(ctx, 1), t, join),
- new_ir_seq(ctx, new_ir_label(ctx, t),
- new_ir_seq(ctx, build_ir_stmt(ctx, ast->statement),
- new_ir_seq(ctx, new_ir_jump(ctx, loop),
- new_ir_label(ctx, join))))));
- pop_ir_loop(ctx);
- return new_ir_seq(ctx, retval, build_ir_stmt(ctx, ast->next));
- } // build_ir_whilestmt
- static MOJOSHADER_irStatement *build_ir_dostmt(Context *ctx,
- const MOJOSHADER_astDoStatement *ast)
- {
- // !!! FIXME: ast->unroll
- assert(ast->expr->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
- /* The gist...
- loop:
- statement
- cjump expr == true, loop, join
- join:
- */
- const LoopLabels *labels = push_ir_loop(ctx, 0);
- if (labels == NULL)
- return NULL; // out of memory...
- const int loop = labels->start;
- const int join = labels->end;
- MOJOSHADER_irStatement *retval =
- new_ir_seq(ctx, new_ir_label(ctx, loop),
- new_ir_seq(ctx, build_ir_stmt(ctx, ast->statement),
- new_ir_seq(ctx, new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, ast->expr), new_ir_constbool(ctx, 1), loop, join),
- new_ir_label(ctx, join))));
- pop_ir_loop(ctx);
- return new_ir_seq(ctx, retval, build_ir_stmt(ctx, ast->next));
- } // build_ir_dostmt
- static MOJOSHADER_irStatement *build_ir_switch(Context *ctx, const MOJOSHADER_astSwitchStatement *ast)
- {
- // Dithering down to a list of if-statements in all cases
- // isn't ideal, but we can't do jumptables in D3D bytecode.
- // !!! FIXME: attributes?
- /* The gist...
- move tmp, expr
- cjump tmp == case1expr, case1, testcase2
- testcase2: // etc
- cjump tmp == case2expr, case2, join
- case1:
- case1stmt // might have a break in it somewhere.
- case2:
- case2stmt
- join:
- */
- const LoopLabels *labels = push_ir_loop(ctx, 1);
- if (labels == NULL)
- return NULL; // out of memory...
- const int join = labels->end;
- const int elems = datatype_elems(ctx, ast->expr->datatype);
- const MOJOSHADER_astDataTypeType dt = datatype_base(ctx, ast->expr->datatype)->type;
- const MOJOSHADER_astSwitchCases *cases = ast->cases;
- const int tmp = generate_ir_temp(ctx);
- MOJOSHADER_irStatement *startseqs = new_ir_move(ctx, new_ir_temp(ctx, tmp, dt, elems), build_ir_expr(ctx, ast->expr), -1);
- MOJOSHADER_irStatement *testseqs = startseqs;
- MOJOSHADER_irStatement *startcaseseqs = NULL;
- MOJOSHADER_irStatement *caseseqs = NULL;
- while (cases)
- {
- const int t = generate_ir_label(ctx);
- const int f = (cases->next == NULL) ? join : generate_ir_label(ctx);
- MOJOSHADER_irStatement *cjump = new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, cases->expr), new_ir_temp(ctx, tmp, dt, elems), t, f);
- if (cases->next == NULL) // last one, do the join label.
- {
- testseqs = new_ir_seq(ctx, testseqs, cjump);
- caseseqs = new_ir_seq(ctx, caseseqs, new_ir_seq(ctx, new_ir_label(ctx, t), build_ir_stmt(ctx, cases->statement)));
- caseseqs = new_ir_seq(ctx, caseseqs, new_ir_label(ctx, f));
- } // if
- else
- {
- testseqs = new_ir_seq(ctx, testseqs, new_ir_seq(ctx, cjump, new_ir_label(ctx, f)));
- caseseqs = new_ir_seq(ctx, caseseqs, new_ir_seq(ctx, new_ir_label(ctx, t), build_ir_stmt(ctx, cases->statement)));
- } // else
- if (startcaseseqs == NULL)
- startcaseseqs = caseseqs;
- cases = cases->next;
- } // while
- pop_ir_loop(ctx);
- return new_ir_seq(ctx, startseqs, new_ir_seq(ctx, startcaseseqs, build_ir_stmt(ctx, ast->next)));
- } // build_ir_switch
- static MOJOSHADER_irExpression *build_ir_increxpr(Context *ctx, const MOJOSHADER_astDataType *_dt,
- const int val)
- {
- const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, _dt);
- const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
- const int elems = datatype_elems(ctx, dt);
- MOJOSHADER_irConstant *retval = (MOJOSHADER_irConstant *) new_ir_constant(ctx, type, elems);
- int i;
- switch (type)
- {
- case MOJOSHADER_AST_DATATYPE_BOOL:
- case MOJOSHADER_AST_DATATYPE_INT:
- case MOJOSHADER_AST_DATATYPE_UINT:
- for (i = 0; i < elems; i++)
- retval->value.ival[i] = (int) val;
- break;
- case MOJOSHADER_AST_DATATYPE_FLOAT:
- case MOJOSHADER_AST_DATATYPE_FLOAT_SNORM:
- case MOJOSHADER_AST_DATATYPE_FLOAT_UNORM:
- case MOJOSHADER_AST_DATATYPE_HALF:
- case MOJOSHADER_AST_DATATYPE_DOUBLE:
- for (i = 0; i < elems; i++)
- retval->value.fval[i] = (float) val;
- break;
- default:
- assert(0 && "Semantic analysis should have caught this!");
- } // switch
- return (MOJOSHADER_irExpression *) retval;
- } // build_ir_increxpr
- static MOJOSHADER_irExpression *build_ir_preincdec(Context *ctx, MOJOSHADER_astExpressionUnary *ast, const MOJOSHADER_irBinOpType binop)
- {
- /* The gist...
- move expr, expr + 1
- return expr
- */
- // !!! FIXME: can you writemask an increment operator?
- MOJOSHADER_irExpression *constant = build_ir_increxpr(ctx, ast->datatype, 1);
- return new_ir_eseq(ctx,
- new_ir_move(ctx,
- build_ir_expr(ctx, ast->operand),
- new_ir_binop(ctx, binop, build_ir_expr(ctx, ast->operand), constant), -1),
- build_ir_expr(ctx, ast->operand));
- } // build_ir_preincdec
- static MOJOSHADER_irExpression *build_ir_postincdec(Context *ctx, MOJOSHADER_astExpressionUnary *ast, const MOJOSHADER_irBinOpType binop)
- {
- /* The gist...
- move tmp, expr
- move expr, expr + 1
- return tmp
- */
- // !!! FIXME: can you writemask an increment operator?
- MOJOSHADER_irExpression *constant = build_ir_increxpr(ctx, ast->datatype, 1);
- const int tmp = generate_ir_temp(ctx);
- return new_ir_eseq(ctx,
- new_ir_seq(ctx,
- new_ir_move(ctx, new_ir_temp(ctx, tmp, constant->info.type, constant->info.elements), build_ir_expr(ctx, ast->operand), -1),
- new_ir_move(ctx, build_ir_expr(ctx, ast->operand),
- new_ir_binop(ctx, binop, build_ir_expr(ctx, ast->operand), constant), -1)),
- new_ir_temp(ctx, tmp, constant->info.type, constant->info.elements));
- } // build_ir_postincdec
- static MOJOSHADER_irExpression *build_ir_convert(Context *ctx, const MOJOSHADER_astExpressionCast *ast)
- {
- const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->datatype);
- const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
- const int elems = datatype_elems(ctx, dt);
- return new_ir_convert(ctx, build_ir_expr(ctx, ast->operand), type, elems);
- } // build_ir_convert
- static MOJOSHADER_irExprList *build_ir_exprlist(Context *ctx, MOJOSHADER_astArguments *args)
- {
- MOJOSHADER_irExprList *retval = NULL;
- MOJOSHADER_irExprList *prev = NULL;
- while (args != NULL)
- {
- assert((retval && prev) || ((!retval) && (!prev)));
- MOJOSHADER_irExprList *item = new_ir_exprlist(ctx, build_ir_expr(ctx, args->argument));
- if (prev == NULL)
- prev = retval = item;
- else
- prev->next = item;
- args = args->next;
- } // while
- return retval;
- } // build_ir_exprlist
- static MOJOSHADER_irExpression *build_ir_constructor(Context *ctx, const MOJOSHADER_astExpressionConstructor *ast)
- {
- const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->datatype);
- const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
- const int elems = datatype_elems(ctx, dt);
- assert(elems <= 16); // just in case (matrix4x4 constructor is largest).
- return new_ir_construct(ctx, build_ir_exprlist(ctx, ast->args), type, elems);
- } // build_ir_constructor
- static MOJOSHADER_irExpression *build_ir_call(Context *ctx, const MOJOSHADER_astExpressionCallFunction *ast)
- {
- const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->datatype);
- const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
- const int elems = datatype_elems(ctx, dt);
- return new_ir_call(ctx, ast->identifier->index, build_ir_exprlist(ctx, ast->args), type, elems);
- } // build_ir_call
- static char swiz_to_channel(const char swiz)
- {
- if ((swiz == 'r') || (swiz == 'x')) return 0;
- if ((swiz == 'g') || (swiz == 'y')) return 1;
- if ((swiz == 'b') || (swiz == 'z')) return 2;
- if ((swiz == 'a') || (swiz == 'w')) return 3;
- assert(0 && "Should have been caught by semantic analysis.");
- return 0;
- } // swiz_to_channel
- static MOJOSHADER_irExpression *build_ir_swizzle(Context *ctx, const MOJOSHADER_astExpressionDerefStruct *ast)
- {
- const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->datatype);
- const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
- const int elems = datatype_elems(ctx, dt);
- char chans[4] = { 0, 0, 0, 0 };
- const char *swizstr = ast->member;
- int i;
- for (i = 0; swizstr[i]; i++)
- chans[i] = swiz_to_channel(swizstr[i]);
- return new_ir_swizzle(ctx, build_ir_expr(ctx, ast->identifier), chans, type, elems);
- } // build_ir_swizzle
- static MOJOSHADER_irExpression *build_ir_identifier(Context *ctx, const MOJOSHADER_astExpressionIdentifier *ast)
- {
- const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->datatype);
- const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
- const int elems = datatype_elems(ctx, dt);
- return new_ir_memory(ctx, ast->index, type, elems);
- } // build_ir_identifier
- static MOJOSHADER_irExpression *build_ir_derefstruct(Context *ctx, const MOJOSHADER_astExpressionDerefStruct *ast)
- {
- // There are only three possible IR nodes that contain a struct:
- // an irTemp, an irMemory, or an irESeq that results in a temp or memory.
- // As such, we figure out which it is, and offset appropriately for the
- // member.
- const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->datatype);
- const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
- const int elems = datatype_elems(ctx, dt);
- MOJOSHADER_irExpression *expr = build_ir_expr(ctx, ast->identifier);
- MOJOSHADER_irExpression *finalexpr = expr;
- if (expr == NULL)
- return NULL;
- assert(!ast->isswizzle);
- while (finalexpr->ir.type == MOJOSHADER_IR_ESEQ)
- finalexpr = finalexpr->eseq.expr;
- if (finalexpr->ir.type == MOJOSHADER_IR_TEMP)
- finalexpr->temp.index += ast->member_index;
- else if (finalexpr->ir.type == MOJOSHADER_IR_MEMORY)
- finalexpr->memory.index += ast->member_index;
- else
- assert(0 && "Unexpected condition");
- // Replace the struct type with the type of the member.
- expr->info.type = type;
- expr->info.elements = elems;
- return expr;
- } // build_ir_derefstruct
- static MOJOSHADER_irExpression *build_ir_derefarray(Context *ctx, const MOJOSHADER_astExpressionBinary *ast)
- {
- // In most compilers, arrays dither down to offsets into memory, but
- // they're somewhat special in D3D, since they might have to deal with
- // vectors, etc...so we keep them as first-class citizens of the IR,
- // and let the optimizer/codegen sort it out.
- // !!! FIXME: this might be the wrong move. Maybe remove this IR node type?
- const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->datatype);
- const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
- const int elems = datatype_elems(ctx, dt);
- // !!! FIXME: Array dereference of a vector can become a simple swizzle operation, if we have a constant index.
- // !!! FIXME: Matrix dereference of a vector can become a simple reference to a temp/memory, if we have a constant index.
- return new_ir_array(ctx, build_ir_expr(ctx, ast->left), build_ir_expr(ctx, ast->right), type, elems);
- } // build_ir_derefarray
- static MOJOSHADER_irExpression *build_ir_assign_binop(Context *ctx,
- const MOJOSHADER_irBinOpType op,
- const MOJOSHADER_astExpressionBinary *ast)
- {
- MOJOSHADER_irExpression *lvalue = build_ir_expr(ctx, ast->left);
- MOJOSHADER_irExpression *rvalue = build_ir_expr(ctx, ast->right);
- const MOJOSHADER_astDataTypeType type = lvalue->info.type;
- const int elems = lvalue->info.elements;
- const int tmp = generate_ir_temp(ctx);
- // Semantic analysis should have inserted casts if necessary.
- assert(type == rvalue->info.type);
- assert(elems == rvalue->info.elements);
- // The destination must eventually be lvalue, which means memory or temp.
- MOJOSHADER_irExpression *dst = lvalue;
- while (dst->ir.type == MOJOSHADER_IR_ESEQ)
- dst = dst->eseq.expr;
- if (dst->ir.type == MOJOSHADER_IR_TEMP)
- dst = new_ir_temp(ctx, dst->temp.index, dst->info.type, dst->info.elements);
- else if (dst->ir.type == MOJOSHADER_IR_MEMORY)
- dst = new_ir_memory(ctx, dst->memory.index, dst->info.type, dst->info.elements);
- else
- assert(0 && "Unexpected condition");
- // !!! FIXME: write masking!
- return new_ir_eseq(ctx,
- new_ir_seq(ctx,
- new_ir_move(ctx, new_ir_temp(ctx, tmp, type, elems), new_ir_binop(ctx, op, lvalue, rvalue), -1),
- new_ir_move(ctx, dst, new_ir_temp(ctx, tmp, type, elems), -1)),
- new_ir_temp(ctx, tmp, type, elems));
- } // build_ir_assign_binop
- static MOJOSHADER_irExpression *build_ir_assign(Context *ctx,
- const MOJOSHADER_astExpressionBinary *ast)
- {
- MOJOSHADER_irExpression *lvalue = build_ir_expr(ctx, ast->left);
- MOJOSHADER_irExpression *rvalue = build_ir_expr(ctx, ast->right);
- const MOJOSHADER_astDataTypeType type = lvalue->info.type;
- const int elems = lvalue->info.elements;
- const int tmp = generate_ir_temp(ctx);
- // Semantic analysis should have inserted casts if necessary.
- assert(type == rvalue->info.type);
- assert(elems == rvalue->info.elements);
- // !!! FIXME: write masking!
- // !!! FIXME: whole array/struct assignments need to become a sequence of moves.
- return new_ir_eseq(ctx,
- new_ir_seq(ctx,
- new_ir_move(ctx, new_ir_temp(ctx, tmp, type, elems), rvalue, -1),
- new_ir_move(ctx, lvalue, new_ir_temp(ctx, tmp, type, elems), -1)),
- new_ir_temp(ctx, tmp, type, elems));
- } // build_ir_assign
- // The AST must be perfect and normalized and sane here. If there are any
- // strange corner cases, you should strive to handle them in semantic
- // analysis, so conversion to IR can proceed with a minimum of drama.
- static void *build_ir_internal(Context *ctx, void *_ast);
- static inline MOJOSHADER_irNode *build_ir(Context *ctx, void *_ast)
- {
- return (MOJOSHADER_irNode *) build_ir_internal(ctx, _ast);
- } // build_ir
- static void *build_ir_internal(Context *ctx, void *_ast)
- {
- if ((_ast == NULL) || (ctx->out_of_memory))
- return NULL;
- MOJOSHADER_astNode *ast = (MOJOSHADER_astNode *) _ast;
- // upkeep so we report correct error locations...
- ctx->sourcefile = ast->ast.filename;
- ctx->sourceline = ast->ast.line;
- switch (ast->ast.type)
- {
- case MOJOSHADER_AST_OP_PREINCREMENT: // !!! FIXME: sequence points?
- return build_ir_preincdec(ctx, &ast->unary, MOJOSHADER_IR_BINOP_ADD);
- case MOJOSHADER_AST_OP_POSTINCREMENT: // !!! FIXME: sequence points?
- return build_ir_postincdec(ctx, &ast->unary, MOJOSHADER_IR_BINOP_ADD);
- case MOJOSHADER_AST_OP_PREDECREMENT: // !!! FIXME: sequence points?
- return build_ir_preincdec(ctx, &ast->unary, MOJOSHADER_IR_BINOP_SUBTRACT);
- case MOJOSHADER_AST_OP_POSTDECREMENT: // !!! FIXME: sequence points?
- return build_ir_postincdec(ctx, &ast->unary, MOJOSHADER_IR_BINOP_SUBTRACT);
- case MOJOSHADER_AST_OP_COMPLEMENT:
- return NEW_IR_BINOP(XOR, build_ir_expr(ctx, ast->unary.operand),
- new_ir_constint(ctx, 0xFFFFFFFF));
- case MOJOSHADER_AST_OP_NEGATE: // !!! FIXME: -0.0f != +0.0f
- return NEW_IR_BINOP(SUBTRACT, build_ir_increxpr(ctx, ast->unary.datatype, -1),
- build_ir_expr(ctx, ast->unary.operand));
- case MOJOSHADER_AST_OP_NOT: // operand must be bool here!
- assert(ast->unary.operand->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
- return NEW_IR_BINOP(XOR, build_ir_expr(ctx, ast->unary.operand),
- new_ir_constint(ctx, 1));
- case MOJOSHADER_AST_OP_DEREF_ARRAY:
- return build_ir_derefarray(ctx, &ast->binary);
- case MOJOSHADER_AST_OP_DEREF_STRUCT:
- if (ast->derefstruct.isswizzle)
- return build_ir_swizzle(ctx, &ast->derefstruct);
- return build_ir_derefstruct(ctx, &ast->derefstruct);
- case MOJOSHADER_AST_OP_COMMA:
- // evaluate and throw away left, return right.
- return new_ir_eseq(ctx, new_ir_expr_stmt(ctx, build_ir_expr(ctx, ast->binary.left)),
- build_ir_expr(ctx, ast->binary.right));
- case MOJOSHADER_AST_OP_LESSTHAN: return EASY_IR_COMPARE(LT);
- case MOJOSHADER_AST_OP_GREATERTHAN: return EASY_IR_COMPARE(GT);
- case MOJOSHADER_AST_OP_LESSTHANOREQUAL: return EASY_IR_COMPARE(LEQ);
- case MOJOSHADER_AST_OP_GREATERTHANOREQUAL: return EASY_IR_COMPARE(GEQ);
- case MOJOSHADER_AST_OP_NOTEQUAL: return EASY_IR_COMPARE(NEQ);
- case MOJOSHADER_AST_OP_EQUAL: return EASY_IR_COMPARE(EQL);
- case MOJOSHADER_AST_OP_MULTIPLY: return EASY_IR_BINOP(MULTIPLY);
- case MOJOSHADER_AST_OP_DIVIDE: return EASY_IR_BINOP(DIVIDE);
- case MOJOSHADER_AST_OP_MODULO: return EASY_IR_BINOP(MODULO);
- case MOJOSHADER_AST_OP_ADD: return EASY_IR_BINOP(ADD);
- case MOJOSHADER_AST_OP_SUBTRACT: return EASY_IR_BINOP(SUBTRACT);
- case MOJOSHADER_AST_OP_LSHIFT: return EASY_IR_BINOP(LSHIFT);
- case MOJOSHADER_AST_OP_RSHIFT: return EASY_IR_BINOP(RSHIFT);
- case MOJOSHADER_AST_OP_BINARYAND: return EASY_IR_BINOP(AND);
- case MOJOSHADER_AST_OP_BINARYXOR: return EASY_IR_BINOP(XOR);
- case MOJOSHADER_AST_OP_BINARYOR: return EASY_IR_BINOP(OR);
- case MOJOSHADER_AST_OP_LOGICALAND:
- return build_ir_logical_and(ctx, &ast->binary);
- case MOJOSHADER_AST_OP_LOGICALOR:
- return build_ir_logical_or(ctx, &ast->binary);
- case MOJOSHADER_AST_OP_ASSIGN:
- return build_ir_assign(ctx, &ast->binary);
- case MOJOSHADER_AST_OP_MULASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_MULTIPLY, &ast->binary);
- case MOJOSHADER_AST_OP_DIVASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_DIVIDE, &ast->binary);
- case MOJOSHADER_AST_OP_MODASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_MODULO, &ast->binary);
- case MOJOSHADER_AST_OP_ADDASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_ADD, &ast->binary);
- case MOJOSHADER_AST_OP_SUBASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_SUBTRACT, &ast->binary);
- case MOJOSHADER_AST_OP_LSHIFTASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_LSHIFT, &ast->binary);
- case MOJOSHADER_AST_OP_RSHIFTASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_RSHIFT, &ast->binary);
- case MOJOSHADER_AST_OP_ANDASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_AND, &ast->binary);
- case MOJOSHADER_AST_OP_XORASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_XOR, &ast->binary);
- case MOJOSHADER_AST_OP_ORASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_OR, &ast->binary);
- case MOJOSHADER_AST_OP_CONDITIONAL:
- assert(ast->binary.left->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
- return build_ir_compare(ctx, MOJOSHADER_IR_COND_EQL,
- build_ir_expr(ctx, ast->ternary.left),
- new_ir_constbool(ctx, 1),
- build_ir_expr(ctx, ast->ternary.center),
- build_ir_expr(ctx, ast->ternary.right));
- case MOJOSHADER_AST_OP_IDENTIFIER:
- return build_ir_identifier(ctx, &ast->identifier);
- case MOJOSHADER_AST_OP_INT_LITERAL:
- return new_ir_constint(ctx, ast->intliteral.value);
- case MOJOSHADER_AST_OP_FLOAT_LITERAL:
- return new_ir_constfloat(ctx, ast->floatliteral.value);
- case MOJOSHADER_AST_OP_BOOLEAN_LITERAL:
- return new_ir_constbool(ctx, ast->boolliteral.value);
- case MOJOSHADER_AST_OP_CALLFUNC:
- return build_ir_call(ctx, &ast->callfunc);
- case MOJOSHADER_AST_OP_CONSTRUCTOR:
- return build_ir_constructor(ctx, &ast->constructor);
- case MOJOSHADER_AST_OP_CAST:
- return build_ir_convert(ctx, &ast->cast);
- case MOJOSHADER_AST_STATEMENT_BREAK:
- {
- const LoopLabels *labels = ctx->ir_loop;
- assert(labels != NULL); // semantic analysis should catch this.
- return new_ir_jump(ctx, labels->end);
- } // case
- case MOJOSHADER_AST_STATEMENT_CONTINUE:
- {
- const LoopLabels *labels = ctx->ir_loop;
- assert(labels != NULL); // semantic analysis should catch this.
- return new_ir_jump(ctx, labels->start);
- } // case
- case MOJOSHADER_AST_STATEMENT_DISCARD:
- return new_ir_seq(ctx, new_ir_discard(ctx), build_ir_stmt(ctx, ast->discardstmt.next));
- case MOJOSHADER_AST_STATEMENT_EMPTY:
- return build_ir(ctx, ast->stmt.next); // skip it, do next thing.
- case MOJOSHADER_AST_STATEMENT_EXPRESSION:
- return new_ir_seq(ctx, new_ir_expr_stmt(ctx, build_ir_expr(ctx, ast->exprstmt.expr)), build_ir_stmt(ctx, ast->exprstmt.next));
- case MOJOSHADER_AST_STATEMENT_IF:
- return build_ir_ifstmt(ctx, &ast->ifstmt);
- case MOJOSHADER_AST_STATEMENT_TYPEDEF: // ignore this, move on.
- return build_ir(ctx, ast->typedefstmt.next);
- case MOJOSHADER_AST_STATEMENT_SWITCH:
- return build_ir_switch(ctx, &ast->switchstmt);
- case MOJOSHADER_AST_STATEMENT_STRUCT: // ignore this, move on.
- return build_ir(ctx, ast->structstmt.next);
- case MOJOSHADER_AST_STATEMENT_VARDECL: // ignore this, move on.
- return build_ir(ctx, ast->vardeclstmt.next);
- case MOJOSHADER_AST_STATEMENT_BLOCK:
- return new_ir_seq(ctx, build_ir_stmt(ctx, ast->blockstmt.statements), build_ir_stmt(ctx, ast->blockstmt.next));
- case MOJOSHADER_AST_STATEMENT_FOR:
- return build_ir_forstmt(ctx, &ast->forstmt);
- case MOJOSHADER_AST_STATEMENT_DO:
- return build_ir_dostmt(ctx, &ast->dostmt);
- case MOJOSHADER_AST_STATEMENT_WHILE:
- return build_ir_whilestmt(ctx, &ast->whilestmt);
- case MOJOSHADER_AST_STATEMENT_RETURN:
- {
- const int label = ctx->ir_end;
- assert(label >= 0); // parser should have caught this!
- MOJOSHADER_irStatement *retval = NULL;
- if (ast->returnstmt.expr != NULL)
- {
- // !!! FIXME: whole array/struct returns need to move more into the temp.
- const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->returnstmt.expr->datatype);
- const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
- const int elems = datatype_elems(ctx, dt);
- assert(ctx->ir_ret >= 0);
- retval = new_ir_move(ctx, new_ir_temp(ctx, ctx->ir_ret, type, elems), build_ir_expr(ctx, ast->returnstmt.expr), -1);
- } // if
- return new_ir_seq(ctx, retval, new_ir_jump(ctx, label));
- } // case
- case MOJOSHADER_AST_COMPUNIT_TYPEDEF:
- case MOJOSHADER_AST_COMPUNIT_STRUCT:
- case MOJOSHADER_AST_COMPUNIT_VARIABLE:
- case MOJOSHADER_AST_COMPUNIT_FUNCTION:
- case MOJOSHADER_AST_ARGUMENTS:
- case MOJOSHADER_AST_OP_STRING_LITERAL:
- case MOJOSHADER_AST_SWITCH_CASE:
- case MOJOSHADER_AST_SCALAR_OR_ARRAY:
- case MOJOSHADER_AST_TYPEDEF:
- case MOJOSHADER_AST_FUNCTION_PARAMS:
- case MOJOSHADER_AST_FUNCTION_SIGNATURE:
- case MOJOSHADER_AST_STRUCT_DECLARATION:
- case MOJOSHADER_AST_STRUCT_MEMBER:
- case MOJOSHADER_AST_VARIABLE_DECLARATION:
- case MOJOSHADER_AST_ANNOTATION:
- case MOJOSHADER_AST_PACK_OFFSET:
- case MOJOSHADER_AST_VARIABLE_LOWLEVEL:
- assert(0 && "Shouldn't hit this in build_ir.");
- return NULL;
- default:
- assert(0 && "unexpected type");
- return NULL;
- } // switch
- } // build_ir
- static void print_ir(FILE *io, unsigned int depth, void *_ir)
- {
- MOJOSHADER_irNode *ir = (MOJOSHADER_irNode *) _ir;
- if (ir == NULL)
- return;
- const char *fname = strrchr(ir->ir.filename, '/');
- if (fname != NULL)
- fname++;
- else
- {
- fname = strrchr(ir->ir.filename, '\\');
- if (fname != NULL)
- fname++;
- else
- fname = ir->ir.filename;
- } // else
- int i;
- for (i = 0; i < depth; i++)
- fprintf(io, " ");
- depth++;
- fprintf(io, "[ %s:%d ", fname, ir->ir.line);
- switch (ir->ir.type)
- {
- case MOJOSHADER_IR_LABEL:
- fprintf(io, "LABEL %d ]\n", ir->stmt.label.index);
- break;
- case MOJOSHADER_IR_CONSTANT:
- fprintf(io, "CONSTANT ");
- switch (ir->expr.constant.info.type)
- {
- case MOJOSHADER_AST_DATATYPE_BOOL:
- case MOJOSHADER_AST_DATATYPE_INT:
- case MOJOSHADER_AST_DATATYPE_UINT:
- for (i = 0; i < ir->expr.constant.info.elements-1; i++)
- fprintf(io, "%d, ", ir->expr.constant.value.ival[i]);
- if (ir->expr.constant.info.elements > 0)
- fprintf(io, "%d", ir->expr.constant.value.ival[i]);
- break;
- case MOJOSHADER_AST_DATATYPE_FLOAT:
- case MOJOSHADER_AST_DATATYPE_FLOAT_SNORM:
- case MOJOSHADER_AST_DATATYPE_FLOAT_UNORM:
- case MOJOSHADER_AST_DATATYPE_HALF:
- case MOJOSHADER_AST_DATATYPE_DOUBLE:
- for (i = 0; i < ir->expr.constant.info.elements-1; i++)
- fprintf(io, "%ff, ", ir->expr.constant.value.fval[i]);
- if (ir->expr.constant.info.elements > 0)
- fprintf(io, "%ff", ir->expr.constant.value.fval[i]);
- break;
- default: assert(0 && "shouldn't happen");
- } // switch
- fprintf(io, " ]\n");
- break;
- case MOJOSHADER_IR_TEMP:
- fprintf(io, "TEMP %d ]\n", ir->expr.temp.index);
- break;
- case MOJOSHADER_IR_DISCARD:
- fprintf(io, "DISCARD ]\n");
- break;
- case MOJOSHADER_IR_SWIZZLE:
- fprintf(io, "SWIZZLE");
- for (i = 0; i < ir->expr.swizzle.info.elements-1; i++)
- fprintf(io, " %d", (int) ir->expr.swizzle.channels[i]);
- fprintf(io, " ]\n");
- print_ir(io, depth, ir->expr.swizzle.expr);
- break;
- case MOJOSHADER_IR_CONSTRUCT:
- fprintf(io, "CONSTRUCT ]\n");
- print_ir(io, depth, ir->expr.construct.args);
- break;
- case MOJOSHADER_IR_CONVERT:
- fprintf(io, "CONVERT ]\n");
- print_ir(io, depth, ir->expr.convert.expr);
- break;
- case MOJOSHADER_IR_BINOP:
- fprintf(io, "BINOP ");
- switch (ir->expr.binop.op)
- {
- #define PRINT_IR_BINOP(x) \
- case MOJOSHADER_IR_BINOP_##x: fprintf(io, #x); break;
- PRINT_IR_BINOP(ADD)
- PRINT_IR_BINOP(SUBTRACT)
- PRINT_IR_BINOP(MULTIPLY)
- PRINT_IR_BINOP(DIVIDE)
- PRINT_IR_BINOP(MODULO)
- PRINT_IR_BINOP(AND)
- PRINT_IR_BINOP(OR)
- PRINT_IR_BINOP(XOR)
- PRINT_IR_BINOP(LSHIFT)
- PRINT_IR_BINOP(RSHIFT)
- PRINT_IR_BINOP(UNKNOWN)
- #undef PRINT_IR_BINOP
- default: assert(0 && "unexpected case"); break;
- } // switch
- fprintf(io, " ]\n");
- print_ir(io, depth, ir->expr.binop.left);
- print_ir(io, depth, ir->expr.binop.right);
- break;
- case MOJOSHADER_IR_MEMORY:
- fprintf(io, "MEMORY %d ]\n", ir->expr.memory.index);
- break;
- case MOJOSHADER_IR_CALL:
- fprintf(io, "CALL %d ]\n", ir->expr.call.index);
- print_ir(io, depth, ir->expr.call.args);
- break;
- case MOJOSHADER_IR_ESEQ:
- fprintf(io, "ESEQ ]\n");
- print_ir(io, depth, ir->expr.eseq.stmt);
- break;
- case MOJOSHADER_IR_ARRAY:
- fprintf(io, "ARRAY ]\n");
- print_ir(io, depth, ir->expr.array.array);
- print_ir(io, depth, ir->expr.array.element);
- break;
- case MOJOSHADER_IR_MOVE:
- fprintf(io, "MOVE ]\n");
- print_ir(io, depth, ir->stmt.move.dst);
- print_ir(io, depth, ir->stmt.move.src);
- break;
- case MOJOSHADER_IR_EXPR_STMT:
- fprintf(io, "EXPRSTMT ]\n");
- print_ir(io, depth, ir->stmt.expr.expr);
- break;
- case MOJOSHADER_IR_JUMP:
- fprintf(io, "JUMP %d ]\n", ir->stmt.jump.label);
- break;
- case MOJOSHADER_IR_CJUMP:
- fprintf(io, "CJUMP ");
- switch (ir->stmt.cjump.cond)
- {
- #define PRINT_IR_COND(x) \
- case MOJOSHADER_IR_COND_##x: fprintf(io, #x); break;
- PRINT_IR_COND(EQL)
- PRINT_IR_COND(NEQ)
- PRINT_IR_COND(LT)
- PRINT_IR_COND(GT)
- PRINT_IR_COND(LEQ)
- PRINT_IR_COND(GEQ)
- PRINT_IR_COND(UNKNOWN)
- #undef PRINT_IR_COND
- default: assert(0 && "unexpected case"); break;
- } // switch
- fprintf(io, " %d %d ]\n", ir->stmt.cjump.iftrue, ir->stmt.cjump.iffalse);
- print_ir(io, depth, ir->stmt.cjump.left);
- print_ir(io, depth, ir->stmt.cjump.right);
- break;
- case MOJOSHADER_IR_SEQ:
- fprintf(io, "SEQ ]\n");
- print_ir(io, depth, ir->stmt.seq.first);
- print_ir(io, depth, ir->stmt.seq.next); // !!! FIXME: don't recurse?
- break;
- case MOJOSHADER_IR_EXPRLIST:
- fprintf(io, "EXPRLIST ]\n");
- print_ir(io, depth, ir->misc.exprlist.expr);
- print_ir(io, depth, ir->misc.exprlist.next); // !!! FIXME: don't recurse?
- break;
- default: assert(0 && "unexpected IR node"); break;
- } // switch
- } // print_ir
- static void print_whole_ir(Context *ctx, FILE *io)
- {
- if (ctx->ir != NULL)
- {
- int i;
- for (i = 0; i <= ctx->user_func_index; i++)
- {
- printf("[FUNCTION %d ]\n", i);
- print_ir(io, 1, ctx->ir[i]);
- } // for
- } // if
- } // print_whole_ir
- static void delete_ir(Context *ctx, void *_ir)
- {
- MOJOSHADER_irNode *ir = (MOJOSHADER_irNode *) _ir;
- if (ir == NULL)
- return;
- switch (ir->ir.type)
- {
- case MOJOSHADER_IR_JUMP:
- case MOJOSHADER_IR_LABEL:
- case MOJOSHADER_IR_CONSTANT:
- case MOJOSHADER_IR_TEMP:
- case MOJOSHADER_IR_DISCARD:
- case MOJOSHADER_IR_MEMORY:
- break; // nothing extra to free here.
- case MOJOSHADER_IR_BINOP:
- delete_ir(ctx, ir->expr.binop.left);
- delete_ir(ctx, ir->expr.binop.right);
- break;
- case MOJOSHADER_IR_CALL:
- delete_ir(ctx, ir->expr.call.args);
- break;
- case MOJOSHADER_IR_ESEQ:
- delete_ir(ctx, ir->expr.eseq.stmt);
- delete_ir(ctx, ir->expr.eseq.expr);
- break;
- case MOJOSHADER_IR_ARRAY:
- delete_ir(ctx, ir->expr.array.array);
- delete_ir(ctx, ir->expr.array.element);
- break;
- case MOJOSHADER_IR_MOVE:
- delete_ir(ctx, ir->stmt.move.dst);
- delete_ir(ctx, ir->stmt.move.src);
- break;
- case MOJOSHADER_IR_EXPR_STMT:
- delete_ir(ctx, ir->stmt.expr.expr);
- break;
- case MOJOSHADER_IR_CJUMP:
- delete_ir(ctx, ir->stmt.cjump.left);
- delete_ir(ctx, ir->stmt.cjump.right);
- break;
- case MOJOSHADER_IR_SEQ:
- delete_ir(ctx, ir->stmt.seq.first);
- delete_ir(ctx, ir->stmt.seq.next); // !!! FIXME: don't recurse?
- break;
- case MOJOSHADER_IR_EXPRLIST:
- delete_ir(ctx, ir->misc.exprlist.expr);
- delete_ir(ctx, ir->misc.exprlist.next); // !!! FIXME: don't recurse?
- break;
- case MOJOSHADER_IR_SWIZZLE:
- delete_ir(ctx, ir->expr.swizzle.expr);
- break;
- case MOJOSHADER_IR_CONSTRUCT:
- delete_ir(ctx, ir->expr.construct.args);
- break;
- case MOJOSHADER_IR_CONVERT:
- delete_ir(ctx, ir->expr.convert.expr);
- break;
- default: assert(0 && "unexpected IR node"); break;
- } // switch
- Free(ctx, ir);
- } // delete_ir
- static void intermediate_representation(Context *ctx)
- {
- const MOJOSHADER_astCompilationUnit *ast = NULL;
- const MOJOSHADER_astCompilationUnitFunction *astfn = NULL;
- const size_t arraylen = (ctx->user_func_index+1) * sizeof (MOJOSHADER_irStatement *);
- ctx->ir = (MOJOSHADER_irStatement **)Malloc(ctx, arraylen);
- if (ctx->ir == NULL)
- return;
- memset(ctx->ir, '\0', arraylen);
- ctx->ir_end = -1;
- ctx->ir_ret = -1;
- for (ast = &ctx->ast->compunit; ast != NULL; ast = ast->next)
- {
- assert(ast->ast.type > MOJOSHADER_AST_COMPUNIT_START_RANGE);
- assert(ast->ast.type < MOJOSHADER_AST_COMPUNIT_END_RANGE);
- if (ast->ast.type != MOJOSHADER_AST_COMPUNIT_FUNCTION)
- continue; // only care about functions right now.
- astfn = (MOJOSHADER_astCompilationUnitFunction *) ast;
- if (astfn->definition == NULL) // just a predeclare; skip.
- continue;
- assert(ctx->ir_loop == NULL); // parser should have caught this!
- assert(ctx->ir_end < 0); // parser should have caught this!
- assert(ctx->ir_ret < 0); // parser should have caught this!
- const int start = generate_ir_label(ctx); // !!! FIXME: store somewhere.
- const int end = generate_ir_label(ctx);
- ctx->ir_end = end;
- if (astfn->declaration->datatype != NULL)
- ctx->ir_ret = generate_ir_temp(ctx);
- MOJOSHADER_irStatement *funcseq = new_ir_seq(ctx, new_ir_label(ctx, start), build_ir_stmt(ctx, astfn->definition));
- funcseq = new_ir_seq(ctx, funcseq, new_ir_label(ctx, end));
- assert(ctx->ir_loop == NULL); // parser should have caught this!
- ctx->ir_end = -1;
- ctx->ir_ret = -1;
- assert(astfn->index <= ctx->user_func_index);
- assert(ctx->ir[astfn->index] == NULL);
- ctx->ir[astfn->index] = funcseq;
- } // for
- print_whole_ir(ctx, stdout);
- // done with the AST, nuke it.
- // !!! FIXME: we're going to need CTAB data from this at some point.
- delete_compilation_unit(ctx, (MOJOSHADER_astCompilationUnit *) ctx->ast);
- ctx->ast = NULL;
- } // intermediate_representation
- static MOJOSHADER_astData MOJOSHADER_out_of_mem_ast_data = {
- 1, &MOJOSHADER_out_of_mem_error, 0, 0, 0, 0, 0, 0
- };
- // !!! FIXME: cut and paste from assembler.
- static const MOJOSHADER_astData *build_failed_ast(Context *ctx)
- {
- assert(isfail(ctx));
- if (ctx->out_of_memory)
- return &MOJOSHADER_out_of_mem_ast_data;
-
- MOJOSHADER_astData *retval = NULL;
- retval = (MOJOSHADER_astData *) Malloc(ctx, sizeof (MOJOSHADER_astData));
- if (retval == NULL)
- return &MOJOSHADER_out_of_mem_ast_data;
- memset(retval, '\0', sizeof (MOJOSHADER_astData));
- retval->source_profile = ctx->source_profile;
- retval->malloc = (ctx->malloc == MOJOSHADER_internal_malloc) ? NULL : ctx->malloc;
- retval->free = (ctx->free == MOJOSHADER_internal_free) ? NULL : ctx->free;
- retval->malloc_data = ctx->malloc_data;
- retval->error_count = errorlist_count(ctx->errors);
- retval->errors = errorlist_flatten(ctx->errors);
- if (ctx->out_of_memory)
- {
- Free(ctx, retval);
- return &MOJOSHADER_out_of_mem_ast_data;
- } // if
- return retval;
- } // build_failed_ast
- static const MOJOSHADER_astData *build_astdata(Context *ctx)
- {
- MOJOSHADER_astData *retval = NULL;
- if (ctx->out_of_memory)
- return &MOJOSHADER_out_of_mem_ast_data;
- retval = (MOJOSHADER_astData *) Malloc(ctx, sizeof (MOJOSHADER_astData));
- if (retval == NULL)
- return &MOJOSHADER_out_of_mem_ast_data;
- memset(retval, '\0', sizeof (MOJOSHADER_astData));
- retval->malloc = (ctx->malloc == MOJOSHADER_internal_malloc) ? NULL : ctx->malloc;
- retval->free = (ctx->free == MOJOSHADER_internal_free) ? NULL : ctx->free;
- retval->malloc_data = ctx->malloc_data;
- if (!isfail(ctx))
- {
- retval->source_profile = ctx->source_profile;
- retval->ast = ctx->ast;
- } // if
- retval->error_count = errorlist_count(ctx->errors);
- retval->errors = errorlist_flatten(ctx->errors);
- if (ctx->out_of_memory)
- {
- Free(ctx, retval);
- return &MOJOSHADER_out_of_mem_ast_data;
- } // if
- retval->opaque = ctx;
- return retval;
- } // build_astdata
- static void choose_src_profile(Context *ctx, const char *srcprofile)
- {
- ctx->source_profile = srcprofile;
- #define TEST_PROFILE(x) if (strcmp(srcprofile, x) == 0) { return; }
- TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_VS_1_1);
- TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_VS_2_0);
- TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_VS_3_0);
- TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_PS_1_1);
- TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_PS_1_2);
- TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_PS_1_3);
- TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_PS_1_4);
- TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_PS_2_0);
- TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_PS_3_0);
- #undef TEST_PROFILE
- fail(ctx, "Unknown profile");
- } // choose_src_profile
- static MOJOSHADER_compileData MOJOSHADER_out_of_mem_compile_data = {
- 1, &MOJOSHADER_out_of_mem_error, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
- // !!! FIXME: cut and paste from assembler.
- static const MOJOSHADER_compileData *build_failed_compile(Context *ctx)
- {
- assert(isfail(ctx));
- MOJOSHADER_compileData *retval = NULL;
- retval = (MOJOSHADER_compileData *) Malloc(ctx, sizeof (MOJOSHADER_compileData));
- if (retval == NULL)
- return &MOJOSHADER_out_of_mem_compile_data;
- memset(retval, '\0', sizeof (MOJOSHADER_compileData));
- retval->malloc = (ctx->malloc == MOJOSHADER_internal_malloc) ? NULL : ctx->malloc;
- retval->free = (ctx->free == MOJOSHADER_internal_free) ? NULL : ctx->free;
- retval->malloc_data = ctx->malloc_data;
- retval->source_profile = ctx->source_profile;
- retval->error_count = errorlist_count(ctx->errors);
- retval->errors = errorlist_flatten(ctx->errors);
- retval->warning_count = errorlist_count(ctx->warnings);
- retval->warnings = errorlist_flatten(ctx->warnings);
- if (ctx->out_of_memory) // in case something failed up there.
- {
- MOJOSHADER_freeCompileData(retval);
- return &MOJOSHADER_out_of_mem_compile_data;
- } // if
- return retval;
- } // build_failed_compile
- static const MOJOSHADER_compileData *build_compiledata(Context *ctx)
- {
- assert(!isfail(ctx));
- MOJOSHADER_compileData *retval = NULL;
- retval = (MOJOSHADER_compileData *) Malloc(ctx, sizeof (MOJOSHADER_compileData));
- if (retval == NULL)
- return &MOJOSHADER_out_of_mem_compile_data;
- memset(retval, '\0', sizeof (MOJOSHADER_compileData));
- retval->malloc = (ctx->malloc == MOJOSHADER_internal_malloc) ? NULL : ctx->malloc;
- retval->free = (ctx->free == MOJOSHADER_internal_free) ? NULL : ctx->free;
- retval->malloc_data = ctx->malloc_data;
- retval->source_profile = ctx->source_profile;
- if (!isfail(ctx))
- {
- // !!! FIXME: build output and output_len here.
- } // if
- if (!isfail(ctx))
- {
- // !!! FIXME: build symbols and symbol_count here.
- } // if
- retval->error_count = errorlist_count(ctx->errors);
- retval->errors = errorlist_flatten(ctx->errors);
- retval->warning_count = errorlist_count(ctx->warnings);
- retval->warnings = errorlist_flatten(ctx->warnings);
- if (ctx->out_of_memory) // in case something failed up there.
- {
- MOJOSHADER_freeCompileData(retval);
- return &MOJOSHADER_out_of_mem_compile_data;
- } // if
- return retval;
- } // build_compiledata
- // API entry point...
- // !!! FIXME: move this (and a lot of other things) to mojoshader_ast.c.
- const MOJOSHADER_astData *MOJOSHADER_parseAst(const char *srcprofile,
- const char *filename, const char *source,
- unsigned int sourcelen,
- const MOJOSHADER_preprocessorDefine *defs,
- unsigned int define_count,
- MOJOSHADER_includeOpen include_open,
- MOJOSHADER_includeClose include_close,
- MOJOSHADER_malloc m, MOJOSHADER_free f,
- void *d)
- {
- const MOJOSHADER_astData *retval = NULL;
- Context *ctx = NULL;
- if ( ((m == NULL) && (f != NULL)) || ((m != NULL) && (f == NULL)) )
- return &MOJOSHADER_out_of_mem_ast_data; // supply both or neither.
- ctx = build_context(m, f, d);
- if (ctx == NULL)
- return &MOJOSHADER_out_of_mem_ast_data;
- choose_src_profile(ctx, srcprofile);
- if (!isfail(ctx))
- {
- parse_source(ctx, filename, source, sourcelen, defs, define_count,
- include_open, include_close);
- } // if
- if (!isfail(ctx))
- retval = build_astdata(ctx); // ctx isn't destroyed yet!
- else
- {
- retval = (MOJOSHADER_astData *) build_failed_ast(ctx);
- destroy_context(ctx);
- } // else
- return retval;
- } // MOJOSHADER_parseAst
- void MOJOSHADER_freeAstData(const MOJOSHADER_astData *_data)
- {
- MOJOSHADER_astData *data = (MOJOSHADER_astData *) _data;
- if ((data == NULL) || (data == &MOJOSHADER_out_of_mem_ast_data))
- return; // no-op.
- // !!! FIXME: this needs to live for deleting the stringcache and the ast.
- Context *ctx = (Context *) data->opaque;
- MOJOSHADER_free f = (data->free == NULL) ? MOJOSHADER_internal_free : data->free;
- void *d = data->malloc_data;
- int i;
- // we don't f(data->source_profile), because that's internal static data.
- for (i = 0; i < data->error_count; i++)
- {
- f((void *) data->errors[i].error, d);
- f((void *) data->errors[i].filename, d);
- } // for
- f((void *) data->errors, d);
- // don't delete data->ast (it'll delete with the context).
- f(data, d);
- destroy_context(ctx); // finally safe to destroy this.
- } // MOJOSHADER_freeAstData
- const MOJOSHADER_compileData *MOJOSHADER_compile(const char *srcprofile,
- const char *filename, const char *source,
- unsigned int sourcelen,
- const MOJOSHADER_preprocessorDefine *defs,
- unsigned int define_count,
- MOJOSHADER_includeOpen include_open,
- MOJOSHADER_includeClose include_close,
- MOJOSHADER_malloc m, MOJOSHADER_free f,
- void *d)
- {
- // !!! FIXME: cut and paste from MOJOSHADER_parseAst().
- MOJOSHADER_compileData *retval = NULL;
- Context *ctx = NULL;
- if ( ((m == NULL) && (f != NULL)) || ((m != NULL) && (f == NULL)) )
- return &MOJOSHADER_out_of_mem_compile_data; // supply both or neither.
- ctx = build_context(m, f, d);
- if (ctx == NULL)
- return &MOJOSHADER_out_of_mem_compile_data;
- choose_src_profile(ctx, srcprofile);
- if (!isfail(ctx))
- {
- parse_source(ctx, filename, source, sourcelen, defs, define_count,
- include_open, include_close);
- } // if
- if (!isfail(ctx))
- semantic_analysis(ctx);
- if (!isfail(ctx))
- intermediate_representation(ctx);
- if (isfail(ctx))
- retval = (MOJOSHADER_compileData *) build_failed_compile(ctx);
- else
- retval = (MOJOSHADER_compileData *) build_compiledata(ctx);
- destroy_context(ctx);
- return retval;
- } // MOJOSHADER_compile
- void MOJOSHADER_freeCompileData(const MOJOSHADER_compileData *_data)
- {
- MOJOSHADER_compileData *data = (MOJOSHADER_compileData *) _data;
- if ((data == NULL) || (data == &MOJOSHADER_out_of_mem_compile_data))
- return; // no-op.
- MOJOSHADER_free f = (data->free == NULL) ? MOJOSHADER_internal_free : data->free;
- void *d = data->malloc_data;
- int i;
- // we don't f(data->source_profile), because that's internal static data.
- for (i = 0; i < data->error_count; i++)
- {
- f((void *) data->errors[i].error, d);
- f((void *) data->errors[i].filename, d);
- } // for
- f((void *) data->errors, d);
- for (i = 0; i < data->warning_count; i++)
- {
- f((void *) data->warnings[i].error, d);
- f((void *) data->warnings[i].filename, d);
- } // for
- f((void *) data->warnings, d);
- for (i = 0; i < data->symbol_count; i++)
- {
- f((void *) data->symbols[i].name, d);
- // !!! FIXME: this is missing stuff (including freeing substructs).
- } // for
- f((void *) data->symbols, d);
- f((void *) data->output, d);
- f(data, d);
- } // MOJOSHADER_freeCompileData
- // end of mojoshader_compiler.c ...
|