12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047 |
- \documentclass[7x10]{TimesAPriori_MIT}%%7x10
- \usepackage[utf8]{inputenc}
- %% \usepackage{setspace}
- %% \doublespacing
- \usepackage{listings}
- \usepackage{verbatim}
- \usepackage{amssymb}
- \usepackage{lmodern} % better typewriter font for code
- %\usepackage{wrapfig}
- \usepackage{multirow}
- \usepackage{tcolorbox}
- \usepackage{color}
- %\usepackage{ifthen}
- \usepackage{upquote}
- \definecolor{lightgray}{gray}{1}
- \newcommand{\black}[1]{{\color{black} #1}}
- %\newcommand{\gray}[1]{{\color{lightgray} #1}}
- \newcommand{\gray}[1]{{\color{gray} #1}}
- \def\racketEd{0}
- \def\pythonEd{1}
- \def\edition{0}
- % material that is specific to the Racket edition of the book
- \newcommand{\racket}[1]{{\if\edition\racketEd{#1}\fi}}
- % would like a command for: \if\edition\racketEd\color{olive}
- % and : \fi\color{black}
- % material that is specific to the Python edition of the book
- \newcommand{\python}[1]{{\if\edition\pythonEd #1\fi}}
- %% For multiple indices:
- \usepackage{multind}
- \makeindex{subject}
- \makeindex{authors}
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- \if\edition\racketEd
- \lstset{%
- language=Lisp,
- basicstyle=\ttfamily\small,
- morekeywords={seq,assign,program,block,define,lambda,match,goto,if,else,then,struct,Integer,Boolean,Vector,Void,Any,while,begin,define,public,override,class},
- deletekeywords={read,mapping,vector},
- escapechar=|,
- columns=flexible,
- moredelim=[is][\color{red}]{~}{~},
- showstringspaces=false
- }
- \fi
- \if\edition\pythonEd
- \lstset{%
- language=Python,
- basicstyle=\ttfamily\small,
- morekeywords={match,case,bool,int},
- deletekeywords={},
- escapechar=|,
- columns=flexible,
- moredelim=[is][\color{red}]{~}{~},
- showstringspaces=false
- }
- \fi
- %%% Any shortcut own defined macros place here
- %% sample of author macro:
- \input{defs}
- \newtheorem{exercise}[theorem]{Exercise}
- % Adjusted settings
- \setlength{\columnsep}{4pt}
- %% \begingroup
- %% \setlength{\intextsep}{0pt}%
- %% \setlength{\columnsep}{0pt}%
- %% \begin{wrapfigure}{r}{0.5\textwidth}
- %% \centering\includegraphics[width=\linewidth]{example-image-a}
- %% \caption{Basic layout}
- %% \end{wrapfigure}
- %% \lipsum[1]
- %% \endgroup
- \newbox\oiintbox
- \setbox\oiintbox=\hbox{$\lower2pt\hbox{\huge$\displaystyle\circ$}
- \hskip-13pt\displaystyle\int\hskip-7pt\int_{S}\ $}
- \def\oiint{\copy\oiintbox}
- \def\boldnabla{\hbox{\boldmath$\displaystyle\nabla$}}
- %\usepackage{showframe}
- \def\ShowFrameLinethickness{0.125pt}
- \addbibresource{book.bib}
- \begin{document}
- \frontmatter
- \HalfTitle{Essentials of Compilation, \python{Python}\racket{Racket} Edition}
- \halftitlepage
- \Title{Essentials of Compilation, \python{Python}\racket{Racket} Edition}
- \Booksubtitle{The Incremental, Nano-Pass Approach}
- %\edition{First Edition}
- \BookAuthor{Jeremy G. Siek}
- \imprint{The MIT Press\\
- Cambridge, Massachusetts\\
- London, England}
- \begin{copyrightpage}
- \textcopyright\ 2021 Jeremy G. Siek. Available for free viewing
- or personal downloading under the
- \href{https://creativecommons.org/licenses/by-nc-nd/2.0/uk/}{CC-BY-NC-ND}
- license.
-
- Copyright in this monograph has been licensed exclusively to The MIT
- Press, \url{http://mitpress.mit.edu}, which will be releasing the final
- version to the public in 2022. All inquiries regarding rights should
- be addressed to The MIT Press, Rights and Permissions Department.
- %% \textcopyright\ [YEAR] Massachusetts Institute of Technology
- %% All rights reserved. No part of this book may be reproduced in any
- %% form by any electronic or mechanical means (including photocopying,
- %% recording, or information storage and retrieval) without permission in
- %% writing from the publisher.
- %% This book was set in LaTeX by Jeremy G. Siek. Printed and bound in the
- %% United States of America.
- %% Library of Congress Cataloging-in-Publication Data is available.
- %% ISBN:
- %% 10\quad9\quad8\quad7\quad6\quad5\quad4\quad3\quad2\quad1
- \end{copyrightpage}
- \dedication{This book is dedicated to the programming language wonks
- at Indiana University.}
- %% \begin{epigraphpage}
- %% \epigraph{First Epigraph line goes here}{Mention author name if any,
- %% \textit{Book Name if any}}
- %% \epigraph{Second Epigraph line goes here}{Mention author name if any}
- %% \end{epigraphpage}
- \tableofcontents
- %\listoffigures
- %\listoftables
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- \chapter*{Preface}
- \addcontentsline{toc}{fmbm}{Preface}
- There is a magical moment when a programmer presses the ``run'' button
- and the software begins to execute. Somehow a program written in a
- high-level language is running on a computer that is only capable of
- shuffling bits. Here we reveal the wizardry that makes that moment
- possible. Beginning with the ground breaking work of Backus and
- colleagues in the 1950s, computer scientists discovered techniques for
- constructing programs, called \emph{compilers}, that automatically
- translate high-level programs into machine code.
- We take you on a journey by constructing your own compiler for a small
- but powerful language. Along the way we explain the essential
- concepts, algorithms, and data structures that underlie compilers. We
- develop your understanding of how programs are mapped onto computer
- hardware, which is helpful when reasoning about properties at the
- junction between hardware and software such as execution time,
- software errors, and security vulnerabilities. For those interested
- in pursuing compiler construction, our goal is to provide a
- stepping-stone to advanced topics such as just-in-time compilation,
- program analysis, and program optimization. For those interested in
- designing and implementing programming languages, we connect
- language design choices to their impact on the compiler and the generated
- code.
- A compiler is typically organized as a sequence of stages that
- progressively translate a program to code that runs on hardware. We
- take this approach to the extreme by partitioning our compiler into a
- large number of \emph{nanopasses}, each of which performs a single
- task. This allows us to test the output of each pass in isolation, and
- furthermore, allows us to focus our attention which makes the compiler
- far easier to understand.
- The most familiar approach to describing compilers is with one pass
- per chapter. The problem with that approach is it obfuscates how
- language features motivate design choices in a compiler. We take an
- \emph{incremental} approach in which we build a complete compiler in
- each chapter, starting with a small input language that includes only
- arithmetic and variables and we add new language features in
- subsequent chapters.
- Our choice of language features is designed to elicit the fundamental
- concepts and algorithms used in compilers.
- \begin{itemize}
- \item We begin with integer arithmetic and local variables in
- Chapters~\ref{ch:trees-recur} and \ref{ch:Lvar}, where we introduce
- the fundamental tools of compiler construction: \emph{abstract
- syntax trees} and \emph{recursive functions}.
- \item In Chapter~\ref{ch:register-allocation-Lvar} we apply
- \emph{graph coloring} to assign variables to machine registers.
- \item Chapter~\ref{ch:Lif} adds \code{if} expressions, which motivates
- an elegant recursive algorithm for translating them into conditional
- \code{goto}'s.
- \item Chapter~\ref{ch:Rwhile} fleshes out support for imperative
- programming languages with the addition of loops\racket{ and mutable
- variables}. This elicits the need for \emph{dataflow
- analysis} in the register allocator.
- \item Chapter~\ref{ch:Rvec} adds heap-allocated tuples, motivating
- \emph{garbage collection}.
- \item Chapter~\ref{ch:Rfun} adds functions that are first-class values
- but lack lexical scoping, similar to the C programming
- language~\citep{Kernighan:1988nx} except that we generate efficient
- tail calls. The reader learns about the procedure call stack,
- \emph{calling conventions}, and their interaction with register
- allocation and garbage collection.
- \item Chapter~\ref{ch:Rlam} adds anonymous functions with lexical
- scoping, i.e., \emph{lambda abstraction}. The reader learns about
- \emph{closure conversion}, in which lambdas are translated into a
- combination of functions and tuples.
- % Chapter about classes and objects?
- \item Chapter~\ref{ch:Rdyn} adds \emph{dynamic typing}. Prior to this
- point the input languages are statically typed. The reader extends
- the statically typed language with an \code{Any} type which serves
- as a target for compiling the dynamically typed language.
- {\if\edition\pythonEd
- \item Chapter~\ref{ch:Robject} adds support for \emph{objects} and
- \emph{classes}.
- \fi}
- \item Chapter~\ref{ch:Rgrad} uses the \code{Any} type of
- Chapter~\ref{ch:Rdyn} to implement a \emph{gradually typed language}
- in which different regions of a program may be static or dynamically
- typed. The reader implements runtime support for \emph{proxies} that
- allow values to safely move between regions.
- \item Chapter~\ref{ch:Rpoly} adds \emph{generics} with autoboxing,
- leveraging the \code{Any} type and type casts developed in Chapters
- \ref{ch:Rdyn} and \ref{ch:Rgrad}.
- \end{itemize}
- There are many language features that we do not include. Our choices
- balance the incidental complexity of a feature versus the fundamental
- concepts that it exposes. For example, we include tuples and not
- records because they both elicit the study of heap allocation and
- garbage collection but records come with more incidental complexity.
- Since 2009 drafts of this book have served as the textbook for 16-week
- compiler courses for upper-level undergraduates and first-year
- graduate students at the University of Colorado and Indiana
- University.
- %
- Students come into the course having learned the basics of
- programming, data structures and algorithms, and discrete
- mathematics.
- %
- At the beginning of the course, students form groups of 2-4 people.
- The groups complete one chapter every two weeks, starting with
- Chapter~\ref{ch:Lvar}. Many chapters include a challenge problem that
- we assign to the graduate students. The last two weeks of the course
- involve a final project in which students design and implement a
- compiler extension of their choosing. Chapters~\ref{ch:Rgrad} and
- \ref{ch:Rpoly} can be used in support of these projects or they can
- replace some of the other chapters. For example, a course with an
- emphasis on statically-typed imperative languages could include
- Chapter~\ref{ch:Rpoly} but skip Chapter~\ref{ch:Rdyn}. For compiler
- courses at universities on the quarter system, with 10 weeks, we
- recommend completing up through Chapter~\ref{ch:Rfun}. (If pressed
- for time, one can skip Chapter~\ref{ch:Rvec} but still include
- Chapter~\ref{ch:Rfun} by limiting the number of parameters allowed in
- functions.) Figure~\ref{fig:chapter-dependences} depicts the
- dependencies between chapters.
- This book has also been used in compiler courses at California
- Polytechnic State University, Portland State University, Rose–Hulman
- Institute of Technology, University of Massachusetts Lowell, and the
- University of Vermont.
- \begin{figure}[tp]
- {\if\edition\racketEd
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (C1) at (0,1.5) {\small Ch.~\ref{ch:trees-recur} Preliminaries};
- \node (C2) at (4,1.5) {\small Ch.~\ref{ch:Lvar} Variables};
- \node (C3) at (8,1.5) {\small Ch.~\ref{ch:register-allocation-Lvar} Registers};
- \node (C4) at (0,0) {\small Ch.~\ref{ch:Lif} Conditionals};
- \node (C5) at (4,0) {\small Ch.~\ref{ch:Rvec} Tuples};
- \node (C6) at (8,0) {\small Ch.~\ref{ch:Rfun} Functions};
- \node (C9) at (0,-1.5) {\small Ch.~\ref{ch:Rwhile} Loops};
- \node (C8) at (4,-1.5) {\small Ch.~\ref{ch:Rdyn} Dynamic};
- \node (C7) at (8,-1.5) {\small Ch.~\ref{ch:Rlam} Lambda};
- \node (C10) at (4,-3) {\small Ch.~\ref{ch:Rgrad} Gradual Typing};
- \node (C11) at (8,-3) {\small Ch.~\ref{ch:Rpoly} Generics};
- \path[->] (C1) edge [above] node {} (C2);
- \path[->] (C2) edge [above] node {} (C3);
- \path[->] (C3) edge [above] node {} (C4);
- \path[->] (C4) edge [above] node {} (C5);
- \path[->] (C5) edge [above] node {} (C6);
- \path[->] (C6) edge [above] node {} (C7);
- \path[->] (C4) edge [above] node {} (C8);
- \path[->] (C4) edge [above] node {} (C9);
- \path[->] (C8) edge [above] node {} (C10);
- \path[->] (C10) edge [above] node {} (C11);
- \end{tikzpicture}
- \fi}
- {\if\edition\pythonEd
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (C1) at (0,1.5) {\small Ch.~\ref{ch:trees-recur} Preliminaries};
- \node (C2) at (4,1.5) {\small Ch.~\ref{ch:Lvar} Variables};
- \node (C3) at (8,1.5) {\small Ch.~\ref{ch:register-allocation-Lvar} Registers};
- \node (C4) at (0,0) {\small Ch.~\ref{ch:Lif} Conditionals};
- \node (C5) at (4,0) {\small Ch.~\ref{ch:Rvec} Tuples};
- \node (C6) at (8,0) {\small Ch.~\ref{ch:Rfun} Functions};
- \node (C9) at (0,-1.5) {\small Ch.~\ref{ch:Rwhile} Loops};
- \node (C8) at (4,-1.5) {\small Ch.~\ref{ch:Rdyn} Dynamic};
- \node (CO) at (0,-3) {\small Ch.~\ref{ch:Robject} Objects};
- \node (C7) at (8,-1.5) {\small Ch.~\ref{ch:Rlam} Lambda};
- \node (C10) at (4,-3) {\small Ch.~\ref{ch:Rgrad} Gradual Typing};
- \node (C11) at (8,-3) {\small Ch.~\ref{ch:Rpoly} Generics};
- \path[->] (C1) edge [above] node {} (C2);
- \path[->] (C2) edge [above] node {} (C3);
- \path[->] (C3) edge [above] node {} (C4);
- \path[->] (C4) edge [above] node {} (C5);
- \path[->] (C5) edge [above] node {} (C6);
- \path[->] (C6) edge [above] node {} (C7);
- \path[->] (C4) edge [above] node {} (C8);
- \path[->] (C4) edge [above] node {} (C9);
- \path[->] (C8) edge [above] node {} (C10);
- \path[->] (C8) edge [above] node {} (CO);
- \path[->] (C10) edge [above] node {} (C11);
- \end{tikzpicture}
- \fi}
- \caption{Diagram of chapter dependencies.}
- \label{fig:chapter-dependences}
- \end{figure}
- \racket{
- We use the \href{https://racket-lang.org/}{Racket} language both for
- the implementation of the compiler and for the input language, so the
- reader should be proficient with Racket or Scheme. There are many
- excellent resources for learning Scheme and
- Racket~\citep{Dybvig:1987aa,Abelson:1996uq,Friedman:1996aa,Felleisen:2001aa,Felleisen:2013aa,Flatt:2014aa}.
- }
- \python{
- This edition of the book uses \href{https://www.python.org/}{Python}
- both for the implementation of the compiler and for the input language, so the
- reader should be proficient with Python. There are many
- excellent resources for learning Python~\citep{Lutz:2013vp,Barry:2016vj,Sweigart:2019vn,Matthes:2019vs}.
- }
- The support code for this book is in the github repository at
- the following URL:
- \if\edition\racketEd
- \begin{center}\small
- \url{https://github.com/IUCompilerCourse/public-student-support-code}
- \end{center}
- \fi
- \if\edition\pythonEd
- \begin{center}\small
- \url{https://github.com/IUCompilerCourse/}
- \end{center}
- \fi
- The compiler targets x86 assembly language~\citep{Intel:2015aa}, so it
- is helpful but not necessary for the reader to have taken a computer
- systems course~\citep{Bryant:2010aa}. This book introduces the parts
- of x86-64 assembly language that are needed.
- %
- We follow the System V calling
- conventions~\citep{Bryant:2005aa,Matz:2013aa}, so the assembly code
- that we generate works with the runtime system (written in C) when it
- is compiled using the GNU C compiler (\code{gcc}) on Linux and MacOS
- operating systems on Intel hardware.
- %
- On the Windows operating system, \code{gcc} uses the Microsoft x64
- calling convention~\citep{Microsoft:2018aa,Microsoft:2020aa}. So the
- assembly code that we generate does \emph{not} work with the runtime
- system on Windows. One workaround is to use a virtual machine with
- Linux as the guest operating system.
- \section*{Acknowledgments}
- The tradition of compiler construction at Indiana University goes back
- to research and courses on programming languages by Daniel Friedman in
- the 1970's and 1980's. One of his students, Kent Dybvig, implemented
- Chez Scheme~\citep{Dybvig:2006aa}, an efficient, production-quality
- compiler for Scheme. Throughout the 1990's and 2000's, Dybvig taught
- the compiler course and continued the development of Chez Scheme.
- %
- The compiler course evolved to incorporate novel pedagogical ideas
- while also including elements of real-world compilers. One of
- Friedman's ideas was to split the compiler into many small
- passes. Another idea, called ``the game'', was to test the code
- generated by each pass using interpreters.
- Dybvig, with help from his students Dipanwita Sarkar and Andrew Keep,
- developed infrastructure to support this approach and evolved the
- course to use even smaller
- nanopasses~\citep{Sarkar:2004fk,Keep:2012aa}. Many of the compiler
- design decisions in this book are inspired by the assignment
- descriptions of \citet{Dybvig:2010aa}. In the mid 2000's a student of
- Dybvig's named Abdulaziz Ghuloum observed that the front-to-back
- organization of the course made it difficult for students to
- understand the rationale for the compiler design. Ghuloum proposed the
- incremental approach~\citep{Ghuloum:2006bh} that this book is based
- on.
- We thank the many students who served as teaching assistants for the
- compiler course at IU and made suggestions for improving the book
- including Carl Factora, Ryan Scott, and Cameron Swords. We especially
- thank Andre Kuhlenschmidt for his work on the garbage collector,
- Michael Vollmer for his work on efficient tail calls, and Michael
- Vitousek for his help running the first offering of the incremental
- compiler course at IU.
- We thank professors Bor-Yuh Chang, John Clements, Jay McCarthy, Joseph
- Near, Ryan Newton, Nate Nystrom, Andrew Tolmach, and Michael Wollowski
- for teaching courses based on drafts of this book and for their
- invaluable feedback.
- We thank Ronald Garcia for helping Jeremy survive Dybvig's compiler
- course in the early 2000's and especially for finding the bug that
- sent our garbage collector on a wild goose chase!
- \mbox{}\\
- \noindent Jeremy G. Siek \\
- Bloomington, Indiana
- \mainmatter
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- \chapter{Preliminaries}
- \label{ch:trees-recur}
- In this chapter we review the basic tools that are needed to implement
- a compiler. Programs are typically input by a programmer as text,
- i.e., a sequence of characters. The program-as-text representation is
- called \emph{concrete syntax}. We use concrete syntax to concisely
- write down and talk about programs. Inside the compiler, we use
- \emph{abstract syntax trees} (ASTs) to represent programs in a way
- that efficiently supports the operations that the compiler needs to
- perform.\index{subject}{concrete syntax}\index{subject}{abstract syntax}\index{subject}{abstract
- syntax tree}\index{subject}{AST}\index{subject}{program}\index{subject}{parse} The translation
- from concrete syntax to abstract syntax is a process called
- \emph{parsing}~\citep{Aho:1986qf}. We do not cover the theory and
- implementation of parsing in this book.
- %
- \racket{A parser is provided in the support code for translating from
- concrete to abstract syntax.}
- %
- \python{We use Python's \code{ast} module to translate from concrete
- to abstract syntax.}
- ASTs can be represented in many different ways inside the compiler,
- depending on the programming language used to write the compiler.
- %
- \racket{We use Racket's
- \href{https://docs.racket-lang.org/guide/define-struct.html}{\code{struct}}
- feature to represent ASTs (Section~\ref{sec:ast}).}
- %
- \python{We use Python classes and objects to represent ASTs, especially the
- classes defined in the standard \code{ast} module for the Python
- source language.}
- %
- We use grammars to define the abstract syntax of programming languages
- (Section~\ref{sec:grammar}) and pattern matching to inspect individual
- nodes in an AST (Section~\ref{sec:pattern-matching}). We use
- recursive functions to construct and deconstruct ASTs
- (Section~\ref{sec:recursion}). This chapter provides an brief
- introduction to these ideas.
- \racket{\index{subject}{struct}}
- \python{\index{subject}{class}\index{subject}{object}}
- \section{Abstract Syntax Trees}
- \label{sec:ast}
- Compilers use abstract syntax trees to represent programs because they
- often need to ask questions like: for a given part of a program, what
- kind of language feature is it? What are its sub-parts? Consider the
- program on the left and its AST on the right. This program is an
- addition operation and it has two sub-parts, a
- \racket{read}\python{input} operation and a negation. The negation has
- another sub-part, the integer constant \code{8}. By using a tree to
- represent the program, we can easily follow the links to go from one
- part of a program to its sub-parts.
- \begin{center}
- \begin{minipage}{0.4\textwidth}
- \if\edition\racketEd
- \begin{lstlisting}
- (+ (read) (- 8))
- \end{lstlisting}
- \fi
- \if\edition\pythonEd
- \begin{lstlisting}
- input_int() + -8
- \end{lstlisting}
- \fi
- \end{minipage}
- \begin{minipage}{0.4\textwidth}
- \begin{equation}
- \begin{tikzpicture}
- \node[draw] (plus) at (0 , 0) {\key{+}};
- \node[draw] (read) at (-1, -1.5) {{\if\edition\racketEd\footnotesize\key{read}\fi\if\edition\pythonEd\key{input\_int()}\fi}};
- \node[draw] (minus) at (1 , -1.5) {$\key{-}$};
- \node[draw] (8) at (1 , -3) {\key{8}};
- \draw[->] (plus) to (read);
- \draw[->] (plus) to (minus);
- \draw[->] (minus) to (8);
- \end{tikzpicture}
- \label{eq:arith-prog}
- \end{equation}
- \end{minipage}
- \end{center}
- We use the standard terminology for trees to describe ASTs: each
- rectangle above is called a \emph{node}. The arrows connect a node to its
- \emph{children} (which are also nodes). The top-most node is the
- \emph{root}. Every node except for the root has a \emph{parent} (the
- node it is the child of). If a node has no children, it is a
- \emph{leaf} node. Otherwise it is an \emph{internal} node.
- \index{subject}{node}
- \index{subject}{children}
- \index{subject}{root}
- \index{subject}{parent}
- \index{subject}{leaf}
- \index{subject}{internal node}
- %% Recall that an \emph{symbolic expression} (S-expression) is either
- %% \begin{enumerate}
- %% \item an atom, or
- %% \item a pair of two S-expressions, written $(e_1 \key{.} e_2)$,
- %% where $e_1$ and $e_2$ are each an S-expression.
- %% \end{enumerate}
- %% An \emph{atom} can be a symbol, such as \code{`hello}, a number, the
- %% null value \code{'()}, etc. We can create an S-expression in Racket
- %% simply by writing a backquote (called a quasi-quote in Racket)
- %% followed by the textual representation of the S-expression. It is
- %% quite common to use S-expressions to represent a list, such as $a, b
- %% ,c$ in the following way:
- %% \begin{lstlisting}
- %% `(a . (b . (c . ())))
- %% \end{lstlisting}
- %% Each element of the list is in the first slot of a pair, and the
- %% second slot is either the rest of the list or the null value, to mark
- %% the end of the list. Such lists are so common that Racket provides
- %% special notation for them that removes the need for the periods
- %% and so many parenthesis:
- %% \begin{lstlisting}
- %% `(a b c)
- %% \end{lstlisting}
- %% The following expression creates an S-expression that represents AST
- %% \eqref{eq:arith-prog}.
- %% \begin{lstlisting}
- %% `(+ (read) (- 8))
- %% \end{lstlisting}
- %% When using S-expressions to represent ASTs, the convention is to
- %% represent each AST node as a list and to put the operation symbol at
- %% the front of the list. The rest of the list contains the children. So
- %% in the above case, the root AST node has operation \code{`+} and its
- %% two children are \code{`(read)} and \code{`(- 8)}, just as in the
- %% diagram \eqref{eq:arith-prog}.
- %% To build larger S-expressions one often needs to splice together
- %% several smaller S-expressions. Racket provides the comma operator to
- %% splice an S-expression into a larger one. For example, instead of
- %% creating the S-expression for AST \eqref{eq:arith-prog} all at once,
- %% we could have first created an S-expression for AST
- %% \eqref{eq:arith-neg8} and then spliced that into the addition
- %% S-expression.
- %% \begin{lstlisting}
- %% (define ast1.4 `(- 8))
- %% (define ast1_1 `(+ (read) ,ast1.4))
- %% \end{lstlisting}
- %% In general, the Racket expression that follows the comma (splice)
- %% can be any expression that produces an S-expression.
- {\if\edition\racketEd
- We define a Racket \code{struct} for each kind of node. For this
- chapter we require just two kinds of nodes: one for integer constants
- and one for primitive operations. The following is the \code{struct}
- definition for integer constants.
- \begin{lstlisting}
- (struct Int (value))
- \end{lstlisting}
- An integer node includes just one thing: the integer value.
- To create an AST node for the integer $8$, we write \INT{8}.
- \begin{lstlisting}
- (define eight (Int 8))
- \end{lstlisting}
- We say that the value created by \INT{8} is an
- \emph{instance} of the
- \code{Int} structure.
- The following is the \code{struct} definition for primitive operations.
- \begin{lstlisting}
- (struct Prim (op args))
- \end{lstlisting}
- A primitive operation node includes an operator symbol \code{op} and a
- list of child \code{args}. For example, to create an AST that negates
- the number $8$, we write \code{(Prim '- (list eight))}.
- \begin{lstlisting}
- (define neg-eight (Prim '- (list eight)))
- \end{lstlisting}
- Primitive operations may have zero or more children. The \code{read}
- operator has zero children:
- \begin{lstlisting}
- (define rd (Prim 'read '()))
- \end{lstlisting}
- whereas the addition operator has two children:
- \begin{lstlisting}
- (define ast1_1 (Prim '+ (list rd neg-eight)))
- \end{lstlisting}
- We have made a design choice regarding the \code{Prim} structure.
- Instead of using one structure for many different operations
- (\code{read}, \code{+}, and \code{-}), we could have instead defined a
- structure for each operation, as follows.
- \begin{lstlisting}
- (struct Read ())
- (struct Add (left right))
- (struct Neg (value))
- \end{lstlisting}
- The reason we choose to use just one structure is that in many parts
- of the compiler the code for the different primitive operators is the
- same, so we might as well just write that code once, which is enabled
- by using a single structure.
- \fi}
- {\if\edition\pythonEd
- We use a Python \code{class} for each kind of node.
- The following is the class definition for constants.
- \begin{lstlisting}
- class Constant:
- def __init__(self, value):
- self.value = value
- \end{lstlisting}
- An integer constant node includes just one thing: the integer value.
- To create an AST node for the integer $8$, we write \INT{8}.
- \begin{lstlisting}
- eight = Constant(8)
- \end{lstlisting}
- We say that the value created by \INT{8} is an
- \emph{instance} of the \code{Constant} class.
- The following is the class definition for unary operators.
- \begin{lstlisting}
- class UnaryOp:
- def __init__(self, op, operand):
- self.op = op
- self.operand = operand
- \end{lstlisting}
- The specific operation is specified by the \code{op} parameter. For
- example, the class \code{USub} is for unary subtraction. (More unary
- operators are introduced in later chapters.) To create an AST that
- negates the number $8$, we write the following.
- \begin{lstlisting}
- neg_eight = UnaryOp(USub(), eight)
- \end{lstlisting}
- The call to the \code{input\_int} function is represented by the
- \code{Call} and \code{Name} classes.
- \begin{lstlisting}
- class Call:
- def __init__(self, func, args):
- self.func = func
- self.args = args
- class Name:
- def __init__(self, id):
- self.id = id
- \end{lstlisting}
- To create an AST node that calls \code{input\_int}, we write
- \begin{lstlisting}
- read = Call(Name('input_int'), [])
- \end{lstlisting}
- Finally, to represent the addition in \eqref{eq:arith-prog}, we use
- the \code{BinOp} class for binary operators.
- \begin{lstlisting}
- class BinOp:
- def __init__(self, left, op, right):
- self.op = op
- self.left = left
- self.right = right
- \end{lstlisting}
- Similar to \code{UnaryOp}, the specific operation is specified by the
- \code{op} parameter, which for now is just an instance of the
- \code{Add} class. So to create the AST node that adds negative eight
- to some user input, we write the following.
- \begin{lstlisting}
- ast1_1 = BinOp(read, Add(), neg_eight)
- \end{lstlisting}
- \fi}
- When compiling a program such as \eqref{eq:arith-prog}, we need to
- know that the operation associated with the root node is addition and
- we need to be able to access its two children. \racket{Racket}\python{Python}
- provides pattern matching to support these kinds of queries, as we see in
- Section~\ref{sec:pattern-matching}.
- In this book, we often write down the concrete syntax of a program
- even when we really have in mind the AST because the concrete syntax
- is more concise. We recommend that, in your mind, you always think of
- programs as abstract syntax trees.
- \section{Grammars}
- \label{sec:grammar}
- \index{subject}{integer}
- \index{subject}{literal}
- \index{subject}{constant}
- A programming language can be thought of as a \emph{set} of programs.
- The set is typically infinite (one can always create larger and larger
- programs), so one cannot simply describe a language by listing all of
- the programs in the language. Instead we write down a set of rules, a
- \emph{grammar}, for building programs. Grammars are often used to
- define the concrete syntax of a language, but they can also be used to
- describe the abstract syntax. We write our rules in a variant of
- Backus-Naur Form (BNF)~\citep{Backus:1960aa,Knuth:1964aa}.
- \index{subject}{Backus-Naur Form}\index{subject}{BNF}
- As an example, we describe a small language, named \LangInt{}, that consists of
- integers and arithmetic operations.
- \index{subject}{grammar}
- The first grammar rule for the abstract syntax of \LangInt{} says that an
- instance of the \racket{\code{Int} structure}\python{\code{Constant} class} is an expression:
- \begin{equation}
- \Exp ::= \INT{\Int} \label{eq:arith-int}
- \end{equation}
- %
- Each rule has a left-hand-side and a right-hand-side.
- If you have an AST node that matches the
- right-hand-side, then you can categorize it according to the
- left-hand-side.
- %
- A name such as $\Exp$ that is defined by the grammar rules is a
- \emph{non-terminal}. \index{subject}{non-terminal}
- %
- The name $\Int$ is also a non-terminal, but instead of defining it
- with a grammar rule, we define it with the following explanation. An
- $\Int$ is a sequence of decimals ($0$ to $9$), possibly starting with
- $-$ (for negative integers), such that the sequence of decimals
- represent an integer in range $-2^{62}$ to $2^{62}-1$. This enables
- the representation of integers using 63 bits, which simplifies several
- aspects of compilation. \racket{Thus, these integers corresponds to
- the Racket \texttt{fixnum} datatype on a 64-bit machine.}
- \python{In contrast, integers in Python have unlimited precision, but
- the techniques need to handle unlimited precision fall outside the
- scope of this book.}
- The second grammar rule is the \READOP{} operation that receives an
- input integer from the user of the program.
- \begin{equation}
- \Exp ::= \READ{} \label{eq:arith-read}
- \end{equation}
- The third rule says that, given an $\Exp$ node, the negation of that
- node is also an $\Exp$.
- \begin{equation}
- \Exp ::= \NEG{\Exp} \label{eq:arith-neg}
- \end{equation}
- Symbols in typewriter font are \emph{terminal} symbols and must
- literally appear in the program for the rule to be applicable.
- \index{subject}{terminal}
- We can apply these rules to categorize the ASTs that are in the
- \LangInt{} language. For example, by rule \eqref{eq:arith-int}
- \INT{8} is an $\Exp$, then by rule \eqref{eq:arith-neg} the
- following AST is an $\Exp$.
- \begin{center}
- \begin{minipage}{0.5\textwidth}
- \NEG{\INT{\code{8}}}
- \end{minipage}
- \begin{minipage}{0.25\textwidth}
- \begin{equation}
- \begin{tikzpicture}
- \node[draw, circle] (minus) at (0, 0) {$\text{--}$};
- \node[draw, circle] (8) at (0, -1.2) {$8$};
- \draw[->] (minus) to (8);
- \end{tikzpicture}
- \label{eq:arith-neg8}
- \end{equation}
- \end{minipage}
- \end{center}
- The next grammar rule is for addition expressions:
- \begin{equation}
- \Exp ::= \ADD{\Exp}{\Exp} \label{eq:arith-add}
- \end{equation}
- We can now justify that the AST \eqref{eq:arith-prog} is an $\Exp$ in
- \LangInt{}. We know that \READ{} is an $\Exp$ by rule
- \eqref{eq:arith-read} and we have already categorized
- \NEG{\INT{\code{8}}} as an $\Exp$, so we apply rule \eqref{eq:arith-add}
- to show that
- \[
- \ADD{\READ{}}{\NEG{\INT{\code{8}}}}
- \]
- is an $\Exp$ in the \LangInt{} language.
- If you have an AST for which the above rules do not apply, then the
- AST is not in \LangInt{}. For example, the program \racket{\code{(-
- (read) 8)}} \python{\code{input\_int() - 8}} is not in \LangInt{}
- because there are no rules for the \key{-} operator with two
- arguments. Whenever we define a language with a grammar, the language
- only includes those programs that are justified by the grammar rules.
- {\if\edition\pythonEd
- The language \LangInt{} includes a second non-terminal $\Stmt$ for statements.
- There is a statement for printing the value of an expression
- \[
- \Stmt{} ::= \PRINT{\Exp}
- \]
- and a statement that evaluates an expression but ignores the result.
- \[
- \Stmt{} ::= \EXPR{\Exp}
- \]
- \fi}
- {\if\edition\racketEd
- The last grammar rule for \LangInt{} states that there is a
- \code{Program} node to mark the top of the whole program:
- \[
- \LangInt{} ::= \PROGRAM{\code{'()}}{\Exp}
- \]
- The \code{Program} structure is defined as follows
- \begin{lstlisting}
- (struct Program (info body))
- \end{lstlisting}
- where \code{body} is an expression. In later chapters, the \code{info}
- part will be used to store auxiliary information but for now it is
- just the empty list.
- \fi}
- {\if\edition\pythonEd
- The last grammar rule for \LangInt{} states that there is a
- \code{Module} node to mark the top of the whole program:
- \[
- \LangInt{} ::= \PROGRAM{}{\Stmt^{*}}
- \]
- The asterisk symbol $*$ indicates a list of the preceding grammar item, in
- this case, a list of statements.
- %
- The \code{Module} class is defined as follows
- \begin{lstlisting}
- class Module:
- def __init__(self, body):
- self.body = body
- \end{lstlisting}
- where \code{body} is a list of statements.
- \fi}
- It is common to have many grammar rules with the same left-hand side
- but different right-hand sides, such as the rules for $\Exp$ in the
- grammar of \LangInt{}. As a short-hand, a vertical bar can be used to
- combine several right-hand-sides into a single rule.
- We collect all of the grammar rules for the abstract syntax of \LangInt{}
- in Figure~\ref{fig:r0-syntax}. The concrete syntax for \LangInt{} is
- defined in Figure~\ref{fig:r0-concrete-syntax}.
- \racket{The \code{read-program} function provided in
- \code{utilities.rkt} of the support code reads a program in from a
- file (the sequence of characters in the concrete syntax of Racket)
- and parses it into an abstract syntax tree. See the description of
- \code{read-program} in Appendix~\ref{appendix:utilities} for more
- details.}
- \python{The \code{parse} function in Python's \code{ast} module
- converts the concrete syntax (represented as a string) into an
- abstract syntax tree.}
- \begin{figure}[tp]
- \fbox{
- \begin{minipage}{0.96\textwidth}
- {\if\edition\racketEd
- \[
- \begin{array}{rcl}
- \Exp &::=& \Int \MID \LP\key{read}\RP \MID \LP\key{-}\;\Exp\RP \MID \LP\key{+} \; \Exp\;\Exp\RP\\
- \LangInt{} &::=& \Exp
- \end{array}
- \]
- \fi}
- {\if\edition\pythonEd
- \[
- \begin{array}{rcl}
- \Exp &::=& \Int \MID \key{input\_int}\LP\RP \MID \key{-}\;\Exp \MID \Exp \; \key{+} \; \Exp\\
- \Stmt &::=& \key{print}\LP \Exp \RP \MID \Exp\\
- \LangInt{} &::=& \Stmt^{*}
- \end{array}
- \]
- \fi}
- \end{minipage}
- }
- \caption{The concrete syntax of \LangInt{}.}
- \label{fig:r0-concrete-syntax}
- \end{figure}
- \begin{figure}[tp]
- \fbox{
- \begin{minipage}{0.96\textwidth}
- {\if\edition\racketEd
- \[
- \begin{array}{rcl}
- \Exp &::=& \INT{\Int} \MID \READ{} \MID \NEG{\Exp} \\
- &\MID& \ADD{\Exp}{\Exp} \\
- \LangInt{} &::=& \PROGRAM{\code{'()}}{\Exp}
- \end{array}
- \]
- \fi}
- {\if\edition\pythonEd
- \[
- \begin{array}{rcl}
- \Exp{} &::=& \INT{\Int} \MID \READ{} \\
- &\MID& \NEG{\Exp} \MID \ADD{\Exp}{\Exp} \\
- \Stmt{} &::=& \PRINT{\Exp} \MID \EXPR{\Exp} \\
- \LangInt{} &::=& \PROGRAM{}{\Stmt^{*}}
- \end{array}
- \]
- \fi}
- \end{minipage}
- }
- \caption{The abstract syntax of \LangInt{}.}
- \label{fig:r0-syntax}
- \end{figure}
- \section{Pattern Matching}
- \label{sec:pattern-matching}
- As mentioned in Section~\ref{sec:ast}, compilers often need to access
- the parts of an AST node. \racket{Racket}\python{As of version 3.10, Python} provides the
- \texttt{match} feature to access the parts of a value.
- Consider the following example. \index{subject}{match} \index{subject}{pattern matching}
- \begin{center}
- \begin{minipage}{0.5\textwidth}
- {\if\edition\racketEd
- \begin{lstlisting}
- (match ast1_1
- [(Prim op (list child1 child2))
- (print op)])
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- match ast1_1:
- case BinOp(child1, op, child2):
- print(op)
- \end{lstlisting}
- \fi}
- \end{minipage}
- \end{center}
- {\if\edition\racketEd
- %
- In the above example, the \texttt{match} form checks whether the AST
- \eqref{eq:arith-prog} is a binary operator and binds its parts to the
- three pattern variables \texttt{op}, \texttt{child1}, and
- \texttt{child2}, and then prints out the operator. In general, a match
- clause consists of a \emph{pattern} and a
- \emph{body}.\index{subject}{pattern} Patterns are recursively defined
- to be either a pattern variable, a structure name followed by a
- pattern for each of the structure's arguments, or an S-expression
- (symbols, lists, etc.). (See Chapter 12 of The Racket
- Guide\footnote{\url{https://docs.racket-lang.org/guide/match.html}}
- and Chapter 9 of The Racket
- Reference\footnote{\url{https://docs.racket-lang.org/reference/match.html}}
- for a complete description of \code{match}.)
- %
- The body of a match clause may contain arbitrary Racket code. The
- pattern variables can be used in the scope of the body, such as
- \code{op} in \code{(print op)}.
- %
- \fi}
- %
- %
- {\if\edition\pythonEd
- %
- In the above example, the \texttt{match} form checks whether the AST
- \eqref{eq:arith-prog} is a binary operator and binds its parts to the
- three pattern variables \texttt{child1}, \texttt{op}, and
- \texttt{child2}, and then prints out the operator. In general, each
- \code{case} consists of a \emph{pattern} and a
- \emph{body}.\index{subject}{pattern} Patterns are recursively defined
- to be either a pattern variable, a class name followed by a pattern
- for each of its constructor's arguments, or other literals such as
- strings, lists, etc.
- %
- The body of each \code{case} may contain arbitrary Python code. The
- pattern variables can be used in the body, such as \code{op} in
- \code{print(op)}.
- %
- \fi}
- A \code{match} form may contain several clauses, as in the following
- function \code{leaf} that recognizes when an \LangInt{} node is a leaf in
- the AST. The \code{match} proceeds through the clauses in order,
- checking whether the pattern can match the input AST. The body of the
- first clause that matches is executed. The output of \code{leaf} for
- several ASTs is shown on the right.
- \begin{center}
- \begin{minipage}{0.6\textwidth}
- {\if\edition\racketEd
- \begin{lstlisting}
- (define (leaf arith)
- (match arith
- [(Int n) #t]
- [(Prim 'read '()) #t]
- [(Prim '- (list e1)) #f]
- [(Prim '+ (list e1 e2)) #f]))
- (leaf (Prim 'read '()))
- (leaf (Prim '- (list (Int 8))))
- (leaf (Int 8))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- def leaf(arith):
- match arith:
- case Constant(n):
- return True
- case Call(Name('input_int'), []):
- return True
- case UnaryOp(USub(), e1):
- return False
- case BinOp(e1, Add(), e2):
- return False
- print(leaf(Call(Name('input_int'), [])))
- print(leaf(UnaryOp(USub(), eight)))
- print(leaf(Constant(8)))
- \end{lstlisting}
- \fi}
- \end{minipage}
- \vrule
- \begin{minipage}{0.25\textwidth}
- {\if\edition\racketEd
- \begin{lstlisting}
-
- #t
- #f
- #t
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
-
-
- True
- False
- True
- \end{lstlisting}
- \fi}
- \end{minipage}
- \end{center}
- When writing a \code{match}, we refer to the grammar definition to
- identify which non-terminal we are expecting to match against, then we
- make sure that 1) we have one \racket{clause}\python{case} for each alternative of that
- non-terminal and 2) that the pattern in each \racket{clause}\python{case} corresponds to the
- corresponding right-hand side of a grammar rule. For the \code{match}
- in the \code{leaf} function, we refer to the grammar for \LangInt{} in
- Figure~\ref{fig:r0-syntax}. The $\Exp$ non-terminal has 4
- alternatives, so the \code{match} has 4 \racket{clauses}\python{cases}.
- The pattern in each \racket{clause}\python{case} corresponds to the right-hand side
- of a grammar rule. For example, the pattern \ADD{\code{e1}}{\code{e2}} corresponds to the
- right-hand side $\ADD{\Exp}{\Exp}$. When translating from grammars to
- patterns, replace non-terminals such as $\Exp$ with pattern variables
- of your choice (e.g. \code{e1} and \code{e2}).
- \section{Recursive Functions}
- \label{sec:recursion}
- \index{subject}{recursive function}
- Programs are inherently recursive. For example, an expression is often
- made of smaller expressions. Thus, the natural way to process an
- entire program is with a recursive function. As a first example of
- such a recursive function, we define the function \code{exp} in
- Figure~\ref{fig:exp-predicate}, which takes an arbitrary value and
- determines whether or not it is an expression in \LangInt{}.
- %
- We say that a function is defined by \emph{structural recursion} when
- it is defined using a sequence of match \racket{clauses}\python{cases}
- that correspond to a grammar, and the body of each \racket{clause}\python{case}
- makes a recursive call on each
- child node.\footnote{This principle of structuring code according to
- the data definition is advocated in the book \emph{How to Design
- Programs} \url{https://htdp.org/2020-8-1/Book/index.html}.}.
- \python{We define a second function, named \code{stmt}, that recognizes
- whether a value is a \LangInt{} statement.}
- \python{Finally, }
- Figure~\ref{fig:exp-predicate} \racket{also} defines \code{Lint}, which
- determines whether an AST is a program in \LangInt{}. In general we can
- expect to write one recursive function to handle each non-terminal in
- a grammar.\index{subject}{structural recursion}
- \begin{figure}[tp]
- {\if\edition\racketEd
- \begin{minipage}{0.7\textwidth}
- \begin{lstlisting}
- (define (exp ast)
- (match ast
- [(Int n) #t]
- [(Prim 'read '()) #t]
- [(Prim '- (list e)) (exp e)]
- [(Prim '+ (list e1 e2))
- (and (exp e1) (exp e2))]
- [else #f]))
- (define (Lint ast)
- (match ast
- [(Program '() e) (exp e)]
- [else #f]))
- (Lint (Program '() ast1_1)
- (Lint (Program '()
- (Prim '- (list (Prim 'read '())
- (Prim '+ (list (Num 8)))))))
- \end{lstlisting}
- \end{minipage}
- \vrule
- \begin{minipage}{0.25\textwidth}
- \begin{lstlisting}
- #t
- #f
- \end{lstlisting}
- \end{minipage}
- \fi}
- {\if\edition\pythonEd
- \begin{minipage}{0.7\textwidth}
- \begin{lstlisting}
- def exp(e):
- match e:
- case Constant(n):
- return True
- case Call(Name('input_int'), []):
- return True
- case UnaryOp(USub(), e1):
- return exp(e1)
- case BinOp(e1, Add(), e2):
- return exp(e1) and exp(e2)
- case _:
- return False
- def stmt(s):
- match s:
- case Call(Name('print'), [e]):
- return exp(e)
- case Expr(e):
- return exp(e)
- case _:
- return False
-
- def Lint(p):
- match p:
- case Module(body):
- return all([stmt(s) for s in body])
- case _:
- return False
- print(Lint(Module([Expr(ast1_1)])))
- print(Lint(Module([Expr(BinOp(read, Sub(),
- UnaryOp(Add(), Constant(8))))])))
- \end{lstlisting}
- \end{minipage}
- \vrule
- \begin{minipage}{0.25\textwidth}
- \begin{lstlisting}
-
-
- True
- False
- \end{lstlisting}
- \end{minipage}
- \fi}
- \caption{Example of recursive functions for \LangInt{}. These functions
- recognize whether an AST is in \LangInt{}.}
- \label{fig:exp-predicate}
- \end{figure}
- %% You may be tempted to merge the two functions into one, like this:
- %% \begin{center}
- %% \begin{minipage}{0.5\textwidth}
- %% \begin{lstlisting}
- %% (define (Lint ast)
- %% (match ast
- %% [(Int n) #t]
- %% [(Prim 'read '()) #t]
- %% [(Prim '- (list e)) (Lint e)]
- %% [(Prim '+ (list e1 e2)) (and (Lint e1) (Lint e2))]
- %% [(Program '() e) (Lint e)]
- %% [else #f]))
- %% \end{lstlisting}
- %% \end{minipage}
- %% \end{center}
- %% %
- %% Sometimes such a trick will save a few lines of code, especially when
- %% it comes to the \code{Program} wrapper. Yet this style is generally
- %% \emph{not} recommended because it can get you into trouble.
- %% %
- %% For example, the above function is subtly wrong:
- %% \lstinline{(Lint (Program '() (Program '() (Int 3))))}
- %% returns true when it should return false.
- \section{Interpreters}
- \label{sec:interp_Lint}
- \index{subject}{interpreter}
- The behavior of a program is defined by the specification of the
- programming language.
- %
- \racket{For example, the Scheme language is defined in the report by
- \cite{SPERBER:2009aa}. The Racket language is defined in its
- reference manual~\citep{plt-tr}.}
- %
- \python{For example, the Python language is defined in the Python
- Language Reference~\citep{PSF21:python_ref} and the CPython interpreter~\citep{PSF21:cpython}.}
- %
- In this book we use interpreters
- to specify each language that we consider. An interpreter that is
- designated as the definition of a language is called a
- \emph{definitional interpreter}~\citep{reynolds72:_def_interp}.
- \index{subject}{definitional interpreter} We warm up by creating a
- definitional interpreter for the \LangInt{} language, which serves as
- a second example of structural recursion. The \code{interp\_Lint}
- function is defined in Figure~\ref{fig:interp_Lint}.
- %
- \racket{The body of the function is a match on the input program
- followed by a call to the \lstinline{interp_exp} helper function,
- which in turn has one match clause per grammar rule for \LangInt{}
- expressions.}
- %
- \python{The body of the function matches on the \code{Module} AST node
- and then invokes \code{interp\_stmt} on each statement in the
- module. The \code{interp\_stmt} function includes a case for each
- grammar rule of the \Stmt{} non-terminal and it calls
- \code{interp\_exp} on each subexpression. The \code{interp\_exp}
- function includes a case for each grammar rule of the \Exp{}
- non-terminal.}
- \begin{figure}[tp]
- {\if\edition\racketEd
- \begin{lstlisting}
- (define (interp_exp e)
- (match e
- [(Int n) n]
- [(Prim 'read '())
- (define r (read))
- (cond [(fixnum? r) r]
- [else (error 'interp_exp "read expected an integer" r)])]
- [(Prim '- (list e))
- (define v (interp_exp e))
- (fx- 0 v)]
- [(Prim '+ (list e1 e2))
- (define v1 (interp_exp e1))
- (define v2 (interp_exp e2))
- (fx+ v1 v2)]))
- (define (interp_Lint p)
- (match p
- [(Program '() e) (interp_exp e)]))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- def interp_exp(e):
- match e:
- case BinOp(left, Add(), right):
- l = interp_exp(left)
- r = interp_exp(right)
- return l + r
- case UnaryOp(USub(), v):
- return - interp_exp(v)
- case Constant(value):
- return value
- case Call(Name('input_int'), []):
- return int(input())
- def interp_stmt(s):
- match s:
- case Expr(Call(Name('print'), [arg])):
- print(interp_exp(arg))
- case Expr(value):
- interp_exp(value)
- def interp_Lint(p):
- match p:
- case Module(body):
- for s in body:
- interp_stmt(s)
- \end{lstlisting}
- \fi}
- \caption{Interpreter for the \LangInt{} language.}
- \label{fig:interp_Lint}
- \end{figure}
- Let us consider the result of interpreting a few \LangInt{} programs. The
- following program adds two integers.
- {\if\edition\racketEd
- \begin{lstlisting}
- (+ 10 32)
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- print(10 + 32)
- \end{lstlisting}
- \fi}
- The result is \key{42}, the answer to life, the universe, and
- everything: \code{42}!\footnote{\emph{The Hitchhiker's Guide to the
- Galaxy} by Douglas Adams.}.
- %
- We wrote the above program in concrete syntax whereas the parsed
- abstract syntax is:
- {\if\edition\racketEd
- \begin{lstlisting}
- (Program '() (Prim '+ (list (Int 10) (Int 32))))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- Module([Expr(Call(Name('print'), [BinOp(Constant(10), Add(), Constant(32))]))])
- \end{lstlisting}
- \fi}
- The next example demonstrates that expressions may be nested within
- each other, in this case nesting several additions and negations.
- {\if\edition\racketEd
- \begin{lstlisting}
- (+ 10 (- (+ 12 20)))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- print(10 + -(12 + 20))
- \end{lstlisting}
- \fi}
- %
- \noindent What is the result of the above program?
- {\if\edition\racketEd
- As mentioned previously, the \LangInt{} language does not support
- arbitrarily-large integers, but only $63$-bit integers, so we
- interpret the arithmetic operations of \LangInt{} using fixnum arithmetic
- in Racket.
- Suppose
- \[
- n = 999999999999999999
- \]
- which indeed fits in $63$-bits. What happens when we run the
- following program in our interpreter?
- \begin{lstlisting}
- (+ (+ (+ |$n$| |$n$|) (+ |$n$| |$n$|)) (+ (+ |$n$| |$n$|) (+ |$n$| |$n$|)))))
- \end{lstlisting}
- It produces an error:
- \begin{lstlisting}
- fx+: result is not a fixnum
- \end{lstlisting}
- We establish the convention that if running the definitional
- interpreter on a program produces an error then the meaning of that
- program is \emph{unspecified}\index{subject}{unspecified behavior}, unless the
- error is a \code{trapped-error}. A compiler for the language is under
- no obligations regarding programs with unspecified behavior; it does
- not have to produce an executable, and if it does, that executable can
- do anything. On the other hand, if the error is a
- \code{trapped-error}, then the compiler must produce an executable and
- it is required to report that an error occurred. To signal an error,
- exit with a return code of \code{255}. The interpreters in chapters
- \ref{ch:Rdyn} and \ref{ch:Rgrad} use
- \code{trapped-error}.
- \fi}
- % TODO: how to deal with too-large integers in the Python interpreter?
- %% This convention applies to the languages defined in this
- %% book, as a way to simplify the student's task of implementing them,
- %% but this convention is not applicable to all programming languages.
- %%
- Moving on to the last feature of the \LangInt{} language, the
- \READOP{} operation prompts the user of the program for an integer.
- Recall that program \eqref{eq:arith-prog} requests an integer input
- and then subtracts \code{8}. So if we run
- {\if\edition\racketEd
- \begin{lstlisting}
- (interp_Lint (Program '() ast1_1))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- interp_Lint(Module([Expr(Call(Name('print'), [ast1_1]))]))
- \end{lstlisting}
- \fi}
- \noindent and if the input is \code{50}, the result is \code{42}.
- We include the \READOP{} operation in \LangInt{} so a clever student
- cannot implement a compiler for \LangInt{} that simply runs the interpreter
- during compilation to obtain the output and then generates the trivial
- code to produce the output.\footnote{Yes, a clever student did this in the
- first instance of this course!}
- The job of a compiler is to translate a program in one language into a
- program in another language so that the output program behaves the
- same way as the input program. This idea is depicted in the
- following diagram. Suppose we have two languages, $\mathcal{L}_1$ and
- $\mathcal{L}_2$, and a definitional interpreter for each language.
- Given a compiler that translates from language $\mathcal{L}_1$ to
- $\mathcal{L}_2$ and given any program $P_1$ in $\mathcal{L}_1$, the
- compiler must translate it into some program $P_2$ such that
- interpreting $P_1$ and $P_2$ on their respective interpreters with
- same input $i$ yields the same output $o$.
- \begin{equation} \label{eq:compile-correct}
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (p1) at (0, 0) {$P_1$};
- \node (p2) at (3, 0) {$P_2$};
- \node (o) at (3, -2.5) {$o$};
- \path[->] (p1) edge [above] node {compile} (p2);
- \path[->] (p2) edge [right] node {interp\_$\mathcal{L}_2$($i$)} (o);
- \path[->] (p1) edge [left] node {interp\_$\mathcal{L}_1$($i$)} (o);
- \end{tikzpicture}
- \end{equation}
- In the next section we see our first example of a compiler.
- \section{Example Compiler: a Partial Evaluator}
- \label{sec:partial-evaluation}
- In this section we consider a compiler that translates \LangInt{}
- programs into \LangInt{} programs that may be more efficient. The
- compiler eagerly computes the parts of the program that do not depend
- on any inputs, a process known as \emph{partial
- evaluation}~\citep{Jones:1993uq}. \index{subject}{partial evaluation}
- For example, given the following program
- {\if\edition\racketEd
- \begin{lstlisting}
- (+ (read) (- (+ 5 3)))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- print(input_int() + -(5 + 3) )
- \end{lstlisting}
- \fi}
- \noindent our compiler translates it into the program
- {\if\edition\racketEd
- \begin{lstlisting}
- (+ (read) -8)
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- print(input_int() + -8)
- \end{lstlisting}
- \fi}
- Figure~\ref{fig:pe-arith} gives the code for a simple partial
- evaluator for the \LangInt{} language. The output of the partial evaluator
- is a program in \LangInt{}. In Figure~\ref{fig:pe-arith}, the structural
- recursion over $\Exp$ is captured in the \code{pe\_exp} function
- whereas the code for partially evaluating the negation and addition
- operations is factored into two auxiliary functions:
- \code{pe\_neg} and \code{pe\_add}. The input to these
- functions is the output of partially evaluating the children.
- The \code{pe\_neg} and \code{pe\_add} functions check whether their
- arguments are integers and if they are, perform the appropriate
- arithmetic. Otherwise, they create an AST node for the arithmetic
- operation.
- \begin{figure}[tp]
- {\if\edition\racketEd
- \begin{lstlisting}
- (define (pe_neg r)
- (match r
- [(Int n) (Int (fx- 0 n))]
- [else (Prim '- (list r))]))
- (define (pe_add r1 r2)
- (match* (r1 r2)
- [((Int n1) (Int n2)) (Int (fx+ n1 n2))]
- [(_ _) (Prim '+ (list r1 r2))]))
- (define (pe_exp e)
- (match e
- [(Int n) (Int n)]
- [(Prim 'read '()) (Prim 'read '())]
- [(Prim '- (list e1)) (pe_neg (pe_exp e1))]
- [(Prim '+ (list e1 e2)) (pe_add (pe_exp e1) (pe_exp e2))]))
- (define (pe_Lint p)
- (match p
- [(Program '() e) (Program '() (pe_exp e))]))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- def pe_neg(r):
- match r:
- case Constant(n):
- return Constant(-n)
- case _:
- return UnaryOp(USub(), r)
-
- def pe_add(r1, r2):
- match (r1, r2):
- case (Constant(n1), Constant(n2)):
- return Constant(n1 + n2)
- case _:
- return BinOp(r1, Add(), r2)
- def pe_exp(e):
- match e:
- case BinOp(left, Add(), right):
- return pe_add(pe_exp(left), pe_exp(right))
- case UnaryOp(USub(), v):
- return pe_neg(pe_exp(v))
- case Constant(value):
- return e
- case Call(Name('input_int'), []):
- return e
- def pe_stmt(s):
- match s:
- case Expr(Call(Name('print'), [arg])):
- return Expr(Call(Name('print'), [pe_exp(arg)]))
- case Expr(value):
- return Expr(pe_exp(value))
- def pe_P_int(p):
- match p:
- case Module(body):
- new_body = [pe_stmt(s) for s in body]
- return Module(new_body)
- \end{lstlisting}
- \fi}
- \caption{A partial evaluator for \LangInt{}.}
- \label{fig:pe-arith}
- \end{figure}
- To gain some confidence that the partial evaluator is correct, we can
- test whether it produces programs that get the same result as the
- input programs. That is, we can test whether it satisfies Diagram
- \ref{eq:compile-correct}.
- %
- {\if\edition\racketEd
- The following code runs the partial evaluator on several examples and
- tests the output program. The \texttt{parse-program} and
- \texttt{assert} functions are defined in
- Appendix~\ref{appendix:utilities}.\\
- \begin{minipage}{1.0\textwidth}
- \begin{lstlisting}
- (define (test_pe p)
- (assert "testing pe_Lint"
- (equal? (interp_Lint p) (interp_Lint (pe_Lint p)))))
- (test_pe (parse-program `(program () (+ 10 (- (+ 5 3))))))
- (test_pe (parse-program `(program () (+ 1 (+ 3 1)))))
- (test_pe (parse-program `(program () (- (+ 3 (- 5))))))
- \end{lstlisting}
- \end{minipage}
- \fi}
- % TODO: python version of testing the PE
- \begin{exercise}\normalfont
- Create three programs in the \LangInt{} language and test whether
- partially evaluating them with \code{pe\_Lint} and then
- interpreting them with \code{interp\_Lint} gives the same result
- as directly interpreting them with \code{interp\_Lint}.
- \end{exercise}
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- \chapter{Integers and Variables}
- \label{ch:Lvar}
- This chapter is about compiling a subset of
- \racket{Racket}\python{Python} to x86-64 assembly
- code~\citep{Intel:2015aa}. The subset, named \LangVar{}, includes
- integer arithmetic and local variables. We often refer to x86-64
- simply as x86. The chapter begins with a description of the
- \LangVar{} language (Section~\ref{sec:s0}) followed by an introduction
- to x86 assembly (Section~\ref{sec:x86}). The x86 assembly language is
- large so we discuss only the instructions needed for compiling
- \LangVar{}. We introduce more x86 instructions in later chapters.
- After introducing \LangVar{} and x86, we reflect on their differences
- and come up with a plan to break down the translation from \LangVar{}
- to x86 into a handful of steps (Section~\ref{sec:plan-s0-x86}). The
- rest of the sections in this chapter give detailed hints regarding
- each step. We hope to give enough hints that the well-prepared
- reader, together with a few friends, can implement a compiler from
- \LangVar{} to x86 in a couple weeks. To give the reader a feeling for
- the scale of this first compiler, the instructor solution for the
- \LangVar{} compiler is approximately \racket{500}\python{300} lines of
- code.
- \section{The \LangVar{} Language}
- \label{sec:s0}
- \index{subject}{variable}
- The \LangVar{} language extends the \LangInt{} language with
- variables. The concrete syntax of the \LangVar{} language is defined
- by the grammar in Figure~\ref{fig:Lvar-concrete-syntax} and the
- abstract syntax is defined in Figure~\ref{fig:Lvar-syntax}. The
- non-terminal \Var{} may be any \racket{Racket}\python{Python} identifier.
- As in \LangInt{}, \READOP{} is a nullary operator, \key{-} is a unary operator, and
- \key{+} is a binary operator. Similar to \LangInt{}, the abstract
- syntax of \LangVar{} includes the \racket{\key{Program}
- struct}\python{\key{Module} instance} to mark the top of the
- program.
- %% The $\itm{info}$
- %% field of the \key{Program} structure contains an \emph{association
- %% list} (a list of key-value pairs) that is used to communicate
- %% auxiliary data from one compiler pass the next.
- Despite the simplicity of the \LangVar{} language, it is rich enough to
- exhibit several compilation techniques.
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- {\if\edition\racketEd
- \[
- \begin{array}{rcl}
- \Exp &::=& \Int{} \MID \CREAD{} \MID \CNEG{\Exp} \MID \CADD{\Exp}{\Exp}\\
- &\MID& \Var{} \MID \CLET{\Var}{\Exp}{\Exp} \\
- \LangVarM{} &::=& \Exp
- \end{array}
- \]
- \fi}
- {\if\edition\pythonEd
- \[
- \begin{array}{rcl}
- \Exp &::=& \Int \MID \key{input\_int}\LP\RP \MID \key{-}\;\Exp \MID \Exp \; \key{+} \; \Exp \MID \Var{} \\
- \Stmt &::=& \key{print}\LP \Exp \RP \MID \Exp \MID \Var\mathop{\key{=}}\Exp\\
- \LangVarM{} &::=& \Stmt^{*}
- \end{array}
- \]
- \fi}
- \end{minipage}
- }
- \caption{The concrete syntax of \LangVar{}.}
- \label{fig:Lvar-concrete-syntax}
- \end{figure}
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- {\if\edition\racketEd
- \[
- \begin{array}{rcl}
- \Exp &::=& \INT{\Int} \MID \READ{} \\
- &\MID& \NEG{\Exp} \MID \ADD{\Exp}{\Exp} \\
- &\MID& \VAR{\Var} \MID \LET{\Var}{\Exp}{\Exp} \\
- \LangVarM{} &::=& \PROGRAM{\code{'()}}{\Exp}
- \end{array}
- \]
- \fi}
- {\if\edition\pythonEd
- \[
- \begin{array}{rcl}
- \Exp{} &::=& \INT{\Int} \MID \READ{} \\
- &\MID& \NEG{\Exp} \MID \ADD{\Exp}{\Exp} \MID \VAR{\Var{}} \\
- \Stmt{} &::=& \PRINT{\Exp} \MID \EXPR{\Exp} \\
- &\MID& \ASSIGN{\VAR{\Var}}{\Exp}\\
- \LangVarM{} &::=& \PROGRAM{}{\Stmt^{*}}
- \end{array}
- \]
- \fi}
- \end{minipage}
- }
- \caption{The abstract syntax of \LangVar{}.}
- \label{fig:Lvar-syntax}
- \end{figure}
- {\if\edition\racketEd
- Let us dive further into the syntax and semantics of the \LangVar{}
- language. The \key{let} feature defines a variable for use within its
- body and initializes the variable with the value of an expression.
- The abstract syntax for \key{let} is defined in
- Figure~\ref{fig:Lvar-syntax}. The concrete syntax for \key{let} is
- \begin{lstlisting}
- (let ([|$\itm{var}$| |$\itm{exp}$|]) |$\itm{exp}$|)
- \end{lstlisting}
- For example, the following program initializes \code{x} to $32$ and then
- evaluates the body \code{(+ 10 x)}, producing $42$.
- \begin{lstlisting}
- (let ([x (+ 12 20)]) (+ 10 x))
- \end{lstlisting}
- \fi}
- %
- {\if\edition\pythonEd
- %
- The \LangVar{} language includes assignment statements, which define a
- variable for use in later statements and initializes the variable with
- the value of an expression. The abstract syntax for assignment is
- defined in Figure~\ref{fig:Lvar-syntax}. The concrete syntax for
- assignment is
- \begin{lstlisting}
- |$\itm{var}$| = |$\itm{exp}$|
- \end{lstlisting}
- For example, the following program initializes the variable \code{x}
- to $32$ and then prints the result of \code{10 + x}, producing $42$.
- \begin{lstlisting}
- x = 12 + 20
- print(10 + x)
- \end{lstlisting}
- \fi}
- {\if\edition\racketEd
- %
- When there are multiple \key{let}'s for the same variable, the closest
- enclosing \key{let} is used. That is, variable definitions overshadow
- prior definitions. Consider the following program with two \key{let}'s
- that define variables named \code{x}. Can you figure out the result?
- \begin{lstlisting}
- (let ([x 32]) (+ (let ([x 10]) x) x))
- \end{lstlisting}
- For the purposes of depicting which variable uses correspond to which
- definitions, the following shows the \code{x}'s annotated with
- subscripts to distinguish them. Double check that your answer for the
- above is the same as your answer for this annotated version of the
- program.
- \begin{lstlisting}
- (let ([x|$_1$| 32]) (+ (let ([x|$_2$| 10]) x|$_2$|) x|$_1$|))
- \end{lstlisting}
- The initializing expression is always evaluated before the body of the
- \key{let}, so in the following, the \key{read} for \code{x} is
- performed before the \key{read} for \code{y}. Given the input
- $52$ then $10$, the following produces $42$ (not $-42$).
- \begin{lstlisting}
- (let ([x (read)]) (let ([y (read)]) (+ x (- y))))
- \end{lstlisting}
- \fi}
- \subsection{Extensible Interpreters via Method Overriding}
- \label{sec:extensible-interp}
- To prepare for discussing the interpreter of \LangVar{}, we explain
- why we implement it in an object-oriented style. Throughout this book
- we define many interpreters, one for each of language that we
- study. Because each language builds on the prior one, there is a lot
- of commonality between these interpreters. We want to write down the
- common parts just once instead of many times. A naive approach would
- be for the interpreter of \LangVar{} to handle the
- \racket{cases for variables and \code{let}}
- \python{case for variables}
- but dispatch to \LangInt{}
- for the rest of the cases. The following code sketches this idea. (We
- explain the \code{env} parameter soon, in
- Section~\ref{sec:interp-Lvar}.)
- \begin{center}
- {\if\edition\racketEd
- \begin{minipage}{0.45\textwidth}
- \begin{lstlisting}
- (define ((interp_Lint env) e)
- (match e
- [(Prim '- (list e1))
- (fx- 0 ((interp_Lint env) e1))]
- ...))
- \end{lstlisting}
- \end{minipage}
- \begin{minipage}{0.45\textwidth}
- \begin{lstlisting}
- (define ((interp_Lvar env) e)
- (match e
- [(Var x)
- (dict-ref env x)]
- [(Let x e body)
- (define v ((interp_exp env) e))
- (define env^ (dict-set env x v))
- ((interp_exp env^) body)]
- [else ((interp_Lint env) e)]))
- \end{lstlisting}
- \end{minipage}
- \fi}
- {\if\edition\pythonEd
- \begin{minipage}{0.45\textwidth}
- \begin{lstlisting}
- def interp_Lint(e, env):
- match e:
- case UnaryOp(USub(), e1):
- return - interp_Lint(e1, env)
- ...
- \end{lstlisting}
- \end{minipage}
- \begin{minipage}{0.45\textwidth}
- \begin{lstlisting}
- def interp_Lvar(e, env):
- match e:
- case Name(id):
- return env[id]
- case _:
- return interp_Lint(e, env)
- \end{lstlisting}
- \end{minipage}
- \fi}
- \end{center}
- The problem with this approach is that it does not handle situations
- in which an \LangVar{} feature, such as a variable, is nested inside
- an \LangInt{} feature, like the \code{-} operator, as in the following
- program.
- %
- {\if\edition\racketEd
- \begin{lstlisting}
- (Let 'y (Int 10) (Prim '- (list (Var 'y))))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- y = 10
- print(-y)
- \end{lstlisting}
- \fi}
- %
- \noindent If we invoke \code{interp\_Lvar} on this program, it
- dispatches to \code{interp\_Lint} to handle the \code{-} operator, but
- then it recursively calls \code{interp\_Lint} again on its argument.
- But there is no case for \code{Var} in \code{interp\_Lint} so we get
- an error!
- To make our interpreters extensible we need something called
- \emph{open recursion}\index{subject}{open recursion}, where the tying of the
- recursive knot is delayed to when the functions are
- composed. Object-oriented languages provide open recursion via
- method overriding\index{subject}{method overriding}. The
- following code uses method overriding to interpret \LangInt{} and
- \LangVar{} using
- %
- \racket{the
- \href{https://docs.racket-lang.org/guide/classes.html}{\code{class}}
- \index{subject}{class} feature of Racket}
- %
- \python{a Python \code{class} definition}.
- %
- We define one class for each language and define a method for
- interpreting expressions inside each class. The class for \LangVar{}
- inherits from the class for \LangInt{} and the method
- \code{interp\_exp} in \LangVar{} overrides the \code{interp\_exp} in
- \LangInt{}. Note that the default case of \code{interp\_exp} in
- \LangVar{} uses \code{super} to invoke \code{interp\_exp}, and because
- \LangVar{} inherits from \LangInt{}, that dispatches to the
- \code{interp\_exp} in \LangInt{}.
- \begin{center}
- \hspace{-20pt}
- {\if\edition\racketEd
- \begin{minipage}{0.45\textwidth}
- \begin{lstlisting}
- (define interp_Lint_class
- (class object%
- (define/public ((interp_exp env) e)
- (match e
- [(Prim '- (list e))
- (fx- 0 ((interp_exp env) e))]
- ...))
- ...))
- \end{lstlisting}
- \end{minipage}
- \begin{minipage}{0.45\textwidth}
- \begin{lstlisting}
- (define interp_Lvar_class
- (class interp_Lint_class
- (define/override ((interp_exp env) e)
- (match e
- [(Var x)
- (dict-ref env x)]
- [(Let x e body)
- (define v ((interp_exp env) e))
- (define env^ (dict-set env x v))
- ((interp_exp env^) body)]
- [else
- (super (interp_exp env) e)]))
- ...
- ))
- \end{lstlisting}
- \end{minipage}
- \fi}
- {\if\edition\pythonEd
- \begin{minipage}{0.45\textwidth}
- \begin{lstlisting}
- class InterpLint:
- def interp_exp(e):
- match e:
- case UnaryOp(USub(), e1):
- return -self.interp_exp(e1)
- ...
- ...
- \end{lstlisting}
- \end{minipage}
- \begin{minipage}{0.45\textwidth}
- \begin{lstlisting}
- def InterpLvar(InterpLint):
- def interp_exp(e):
- match e:
- case Name(id):
- return env[id]
- case _:
- return super().interp_exp(e)
- ...
- \end{lstlisting}
- \end{minipage}
- \fi}
- \end{center}
- Getting back to the troublesome example, repeated here:
- {\if\edition\racketEd
- \begin{lstlisting}
- (Let 'y (Int 10) (Prim '- (Var 'y)))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- y = 10
- print(-y)
- \end{lstlisting}
- \fi}
- \noindent We can invoke the \code{interp\_exp} method for \LangVar{}
- \racket{on this expression,}
- \python{on the \code{-y} expression,}
- %
- call it \code{e0}, by creating an object of the \LangVar{} class
- and calling the \code{interp\_exp} method.
- {\if\edition\racketEd
- \begin{lstlisting}
- (send (new interp_Lvar_class) interp_exp e0)
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- InterpLvar().interp_exp(e0)
- \end{lstlisting}
- \fi}
- \noindent To process the \code{-} operator, the default case of
- \code{interp\_exp} in \LangVar{} dispatches to the \code{interp\_exp}
- method in \LangInt{}. But then for the recursive method call, it
- dispatches back to \code{interp\_exp} in \LangVar{}, where the
- \code{Var} node is handled correctly. Thus, method overriding gives us
- the open recursion that we need to implement our interpreters in an
- extensible way.
- \subsection{Definitional Interpreter for \LangVar{}}
- \label{sec:interp-Lvar}
- {\if\edition\racketEd
- \begin{figure}[tp]
- %\begin{wrapfigure}[26]{r}[0.75in]{0.55\textwidth}
- \small
- \begin{tcolorbox}[title=Association Lists as Dictionaries]
- An \emph{association list} (alist) is a list of key-value pairs.
- For example, we can map people to their ages with an alist.
- \index{subject}{alist}\index{subject}{association list}
- \begin{lstlisting}[basicstyle=\ttfamily]
- (define ages '((jane . 25) (sam . 24) (kate . 45)))
- \end{lstlisting}
- The \emph{dictionary} interface is for mapping keys to values.
- Every alist implements this interface. \index{subject}{dictionary} The package
- \href{https://docs.racket-lang.org/reference/dicts.html}{\code{racket/dict}}
- provides many functions for working with dictionaries. Here
- are a few of them:
- \begin{description}
- \item[$\LP\key{dict-ref}\,\itm{dict}\,\itm{key}\RP$]
- returns the value associated with the given $\itm{key}$.
- \item[$\LP\key{dict-set}\,\itm{dict}\,\itm{key}\,\itm{val}\RP$]
- returns a new dictionary that maps $\itm{key}$ to $\itm{val}$
- but otherwise is the same as $\itm{dict}$.
- \item[$\LP\code{in-dict}\,\itm{dict}\RP$] returns the
- \href{https://docs.racket-lang.org/reference/sequences.html}{sequence}
- of keys and values in $\itm{dict}$. For example, the following
- creates a new alist in which the ages are incremented.
- \end{description}
- \vspace{-10pt}
- \begin{lstlisting}[basicstyle=\ttfamily]
- (for/list ([(k v) (in-dict ages)])
- (cons k (add1 v)))
- \end{lstlisting}
- \end{tcolorbox}
- %\end{wrapfigure}
- \caption{Association lists implement the dictionary interface.}
- \label{fig:alist}
- \end{figure}
- \fi}
- Having justified the use of classes and methods to implement
- interpreters, we revisit the definitional interpreter for \LangInt{}
- in Figure~\ref{fig:interp-Lint-class} and then extend it to create an
- interpreter for \LangVar{} in Figure~\ref{fig:interp-Lvar}. The
- interpreter for \LangVar{} adds two new \key{match} cases for
- variables and \racket{\key{let}}\python{assignment}. For
- \racket{\key{let}}\python{assignment} we need a way to communicate the
- value bound to a variable to all the uses of the variable. To
- accomplish this, we maintain a mapping from variables to values
- called an \emph{environment}\index{subject}{environment}.
- %
- We use%
- %
- \racket{an association list (alist)}
- %
- \python{a Python \href{https://docs.python.org/3.10/library/stdtypes.html\#mapping-types-dict}{dictionary}}
- %
- to represent the environment.
- %
- \racket{Figure~\ref{fig:alist} gives a brief introduction to alists
- and the \code{racket/dict} package.}
- %
- The \code{interp\_exp} function takes the current environment,
- \code{env}, as an extra parameter. When the interpreter encounters a
- variable, it looks up the corresponding value in the dictionary.
- %
- \racket{When the interpreter encounters a \key{Let}, it evaluates the
- initializing expression, extends the environment with the result
- value bound to the variable, using \code{dict-set}, then evaluates
- the body of the \key{Let}.}
- %
- \python{When the interpreter encounters an assignment, it evaluates
- the initializing expression and then associates the resulting value
- with the variable in the environment.}
- \begin{figure}[tp]
- {\if\edition\racketEd
- \begin{lstlisting}
- (define interp_Lint_class
- (class object%
- (super-new)
-
- (define/public ((interp_exp env) e)
- (match e
- [(Int n) n]
- [(Prim 'read '())
- (define r (read))
- (cond [(fixnum? r) r]
- [else (error 'interp_exp "expected an integer" r)])]
- [(Prim '- (list e)) (fx- 0 ((interp_exp env) e))]
- [(Prim '+ (list e1 e2))
- (fx+ ((interp_exp env) e1) ((interp_exp env) e2))]))
- (define/public (interp_program p)
- (match p
- [(Program '() e) ((interp_exp '()) e)]))
- ))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- class InterpLint:
- def interp_exp(self, e, env):
- match e:
- case BinOp(left, Add(), right):
- return self.interp_exp(left, env) + self.interp_exp(right, env)
- case UnaryOp(USub(), v):
- return - self.interp_exp(v, env)
- case Constant(value):
- return value
- case Call(Name('input_int'), []):
- return int(input())
- def interp_stmts(self, ss, env):
- if len(ss) == 0:
- return
- match ss[0]:
- case Expr(Call(Name('print'), [arg])):
- print(self.interp_exp(arg, env), end='')
- return self.interp_stmts(ss[1:], env)
- case Expr(value):
- self.interp_exp(value, env)
- return self.interp_stmts(ss[1:], env)
- def interp(self, p):
- match p:
- case Module(body):
- self.interp_stmts(body, {})
- def interp_Lint(p):
- return InterpLint().interp(p)
- \end{lstlisting}
- \fi}
- \caption{Interpreter for \LangInt{} as a class.}
- \label{fig:interp-Lint-class}
- \end{figure}
- \begin{figure}[tp]
- {\if\edition\racketEd
- \begin{lstlisting}
- (define interp_Lvar_class
- (class interp_Lint_class
- (super-new)
-
- (define/override ((interp_exp env) e)
- (match e
- [(Var x) (dict-ref env x)]
- [(Let x e body)
- (define new-env (dict-set env x ((interp_exp env) e)))
- ((interp_exp new-env) body)]
- [else ((super interp-exp env) e)]))
- ))
- (define (interp_Lvar p)
- (send (new interp_Lvar_class) interp_program p))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- class InterpLvar(InterpLint):
- def interp_exp(self, e, env):
- match e:
- case Name(id):
- return env[id]
- case _:
- return super().interp_exp(e, env)
- def interp_stmts(self, ss, env):
- if len(ss) == 0:
- return
- match ss[0]:
- case Assign([lhs], value):
- env[lhs.id] = self.interp_exp(value, env)
- return self.interp_stmts(ss[1:], env)
- case _:
- return super().interp_stmts(ss, env)
- def interp_Lvar(p):
- return InterpLvar().interp(p)
- \end{lstlisting}
- \fi}
- \caption{Interpreter for the \LangVar{} language.}
- \label{fig:interp-Lvar}
- \end{figure}
- The goal for this chapter is to implement a compiler that translates
- any program $P_1$ written in the \LangVar{} language into an x86 assembly
- program $P_2$ such that $P_2$ exhibits the same behavior when run on a
- computer as the $P_1$ program interpreted by \code{interp\_Lvar}.
- That is, they output the same integer $n$. We depict this correctness
- criteria in the following diagram.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (p1) at (0, 0) {$P_1$};
- \node (p2) at (4, 0) {$P_2$};
- \node (o) at (4, -2) {$n$};
- \path[->] (p1) edge [above] node {\footnotesize compile} (p2);
- \path[->] (p1) edge [left] node {\footnotesize\code{interp\_Lvar}} (o);
- \path[->] (p2) edge [right] node {\footnotesize\code{interp\_x86int}} (o);
- \end{tikzpicture}
- \]
- In the next section we introduce the \LangXInt{} subset of x86 that
- suffices for compiling \LangVar{}.
- \section{The \LangXInt{} Assembly Language}
- \label{sec:x86}
- \index{subject}{x86}
- Figure~\ref{fig:x86-int-concrete} defines the concrete syntax for
- \LangXInt{}. We use the AT\&T syntax expected by the GNU
- assembler.
- %
- A program begins with a \code{main} label followed by a sequence of
- instructions. The \key{globl} directive says that the \key{main}
- procedure is externally visible, which is necessary so that the
- operating system can call it.
- %
- An x86 program is stored in the computer's memory. For our purposes,
- the computer's memory is a mapping of 64-bit addresses to 64-bit
- values. The computer has a \emph{program counter} (PC)\index{subject}{program
- counter}\index{subject}{PC} stored in the \code{rip} register that points to
- the address of the next instruction to be executed. For most
- instructions, the program counter is incremented after the instruction
- is executed, so it points to the next instruction in memory. Most x86
- instructions take two operands, where each operand is either an
- integer constant (called an \emph{immediate value}\index{subject}{immediate
- value}), a \emph{register}\index{subject}{register}, or a memory location.
- \newcommand{\allregisters}{\key{rsp} \MID \key{rbp} \MID \key{rax} \MID \key{rbx} \MID \key{rcx}
- \MID \key{rdx} \MID \key{rsi} \MID \key{rdi} \MID \\
- && \key{r8} \MID \key{r9} \MID \key{r10}
- \MID \key{r11} \MID \key{r12} \MID \key{r13}
- \MID \key{r14} \MID \key{r15}}
- \begin{figure}[tp]
- \fbox{
- \begin{minipage}{0.96\textwidth}
- {\if\edition\racketEd
- \[
- \begin{array}{lcl}
- \Reg &::=& \allregisters{} \\
- \Arg &::=& \key{\$}\Int \MID \key{\%}\Reg \MID \Int\key{(}\key{\%}\Reg\key{)}\\
- \Instr &::=& \key{addq} \; \Arg\key{,} \Arg \MID
- \key{subq} \; \Arg\key{,} \Arg \MID
- \key{negq} \; \Arg \MID \key{movq} \; \Arg\key{,} \Arg \MID \\
- && \key{callq} \; \mathit{label} \MID
- \key{pushq}\;\Arg \MID \key{popq}\;\Arg \MID \key{retq} \MID \key{jmp}\,\itm{label} \\
- && \itm{label}\key{:}\; \Instr \\
- \LangXIntM{} &::= & \key{.globl main}\\
- & & \key{main:} \; \Instr\ldots
- \end{array}
- \]
- \fi}
- {\if\edition\pythonEd
- \[
- \begin{array}{lcl}
- \Reg &::=& \allregisters{} \\
- \Arg &::=& \key{\$}\Int \MID \key{\%}\Reg \MID \Int\key{(}\key{\%}\Reg\key{)}\\
- \Instr &::=& \key{addq} \; \Arg\key{,} \Arg \MID
- \key{subq} \; \Arg\key{,} \Arg \MID
- \key{negq} \; \Arg \MID \key{movq} \; \Arg\key{,} \Arg \MID \\
- && \key{callq} \; \mathit{label} \MID
- \key{pushq}\;\Arg \MID \key{popq}\;\Arg \MID \key{retq} \\
- \LangXIntM{} &::= & \key{.globl main}\\
- & & \key{main:} \; \Instr^{*}
- \end{array}
- \]
- \fi}
- \end{minipage}
- }
- \caption{The syntax of the \LangXInt{} assembly language (AT\&T syntax).}
- \label{fig:x86-int-concrete}
- \end{figure}
- A register is a special kind of variable that holds a 64-bit
- value. There are 16 general-purpose registers in the computer and
- their names are given in Figure~\ref{fig:x86-int-concrete}. A register
- is written with a \key{\%} followed by the register name, such as
- \key{\%rax}.
- An immediate value is written using the notation \key{\$}$n$ where $n$
- is an integer.
- %
- %
- An access to memory is specified using the syntax $n(\key{\%}r)$,
- which obtains the address stored in register $r$ and then adds $n$
- bytes to the address. The resulting address is used to load or store
- to memory depending on whether it occurs as a source or destination
- argument of an instruction.
- An arithmetic instruction such as $\key{addq}\,s\key{,}\,d$ reads from the
- source $s$ and destination $d$, applies the arithmetic operation, then
- writes the result back to the destination $d$. \index{subject}{instruction}
- %
- The move instruction $\key{movq}\,s\key{,}\,d$ reads from $s$ and
- stores the result in $d$.
- %
- The $\key{callq}\,\itm{label}$ instruction jumps to the procedure
- specified by the label and $\key{retq}$ returns from a procedure to
- its caller.
- %
- We discuss procedure calls in more detail later in this chapter and in
- Chapter~\ref{ch:Rfun}.
- %
- \racket{The instruction $\key{jmp}\,\itm{label}$ updates the program
- counter to the address of the instruction after the specified
- label.}
- Appendix~\ref{sec:x86-quick-reference} contains a quick-reference for
- all of the x86 instructions used in this book.
- Figure~\ref{fig:p0-x86} depicts an x86 program that computes
- \racket{\code{(+ 10 32)}}\python{10 + 32}. The instruction
- \lstinline{movq $10, %rax}
- puts $10$ into register \key{rax} and then \lstinline{addq $32, %rax}
- adds $32$ to the $10$ in \key{rax} and
- puts the result, $42$, back into \key{rax}.
- %
- The last instruction, \key{retq}, finishes the \key{main} function by
- returning the integer in \key{rax} to the operating system. The
- operating system interprets this integer as the program's exit
- code. By convention, an exit code of 0 indicates that a program
- completed successfully, and all other exit codes indicate various
- errors.
- %
- \racket{Nevertheless, in this book we return the result of the program
- as the exit code.}
- \begin{figure}[tbp]
- \begin{lstlisting}
- .globl main
- main:
- movq $10, %rax
- addq $32, %rax
- retq
- \end{lstlisting}
- \caption{An x86 program that computes
- \racket{\code{(+ 10 32)}}\python{10 + 32}.}
- \label{fig:p0-x86}
- \end{figure}
- We exhibit the use of memory for storing intermediate results in the
- next example. Figure~\ref{fig:p1-x86} lists an x86 program that
- computes \racket{\code{(+ 52 (- 10))}}\python{52 + -10}. This program
- uses a region of memory called the \emph{procedure call stack} (or
- \emph{stack} for
- short). \index{subject}{stack}\index{subject}{procedure call stack}
- The stack consists of a separate \emph{frame}\index{subject}{frame}
- for each procedure call. The memory layout for an individual frame is
- shown in Figure~\ref{fig:frame}. The register \key{rsp} is called the
- \emph{stack pointer}\index{subject}{stack pointer} and points to the
- item at the top of the stack. The stack grows downward in memory, so
- we increase the size of the stack by subtracting from the stack
- pointer. In the context of a procedure call, the \emph{return
- address}\index{subject}{return address} is the instruction after the
- call instruction on the caller side. The function call instruction,
- \code{callq}, pushes the return address onto the stack prior to
- jumping to the procedure. The register \key{rbp} is the \emph{base
- pointer}\index{subject}{base pointer} and is used to access variables
- that are stored in the frame of the current procedure call. The base
- pointer of the caller is store after the return address. In
- Figure~\ref{fig:frame} we number the variables from $1$ to
- $n$. Variable $1$ is stored at address $-8\key{(\%rbp)}$, variable $2$
- at $-16\key{(\%rbp)}$, etc.
- \begin{figure}[tbp]
- {\if\edition\racketEd
- \begin{lstlisting}
- start:
- movq $10, -8(%rbp)
- negq -8(%rbp)
- movq -8(%rbp), %rax
- addq $52, %rax
- jmp conclusion
- .globl main
- main:
- pushq %rbp
- movq %rsp, %rbp
- subq $16, %rsp
- jmp start
- conclusion:
- addq $16, %rsp
- popq %rbp
- retq
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- .globl main
- main:
- pushq %rbp
- movq %rsp, %rbp
- subq $16, %rsp
- movq $10, -8(%rbp)
- negq -8(%rbp)
- movq -8(%rbp), %rax
- addq $52, %rax
- addq $16, %rsp
- popq %rbp
- retq
- \end{lstlisting}
- \fi}
- \caption{An x86 program that computes
- \racket{\code{(+ 52 (- 10))}}\python{52 + -10}.}
- \label{fig:p1-x86}
- \end{figure}
- \begin{figure}[tbp]
- \centering
- \begin{tabular}{|r|l|} \hline
- Position & Contents \\ \hline
- 8(\key{\%rbp}) & return address \\
- 0(\key{\%rbp}) & old \key{rbp} \\
- -8(\key{\%rbp}) & variable $1$ \\
- -16(\key{\%rbp}) & variable $2$ \\
- \ldots & \ldots \\
- 0(\key{\%rsp}) & variable $n$\\ \hline
- \end{tabular}
- \caption{Memory layout of a frame.}
- \label{fig:frame}
- \end{figure}
- Getting back to the program in Figure~\ref{fig:p1-x86}, consider how
- control is transferred from the operating system to the \code{main}
- function. The operating system issues a \code{callq main} instruction
- which pushes its return address on the stack and then jumps to
- \code{main}. In x86-64, the stack pointer \code{rsp} must be divisible
- by 16 bytes prior to the execution of any \code{callq} instruction, so
- when control arrives at \code{main}, the \code{rsp} is 8 bytes out of
- alignment (because the \code{callq} pushed the return address). The
- first three instructions are the typical \emph{prelude}\index{subject}{prelude}
- for a procedure. The instruction \code{pushq \%rbp} saves the base
- pointer for the caller onto the stack and subtracts $8$ from the stack
- pointer. The next instruction \code{movq \%rsp, \%rbp} sets the
- base pointer to the current stack pointer, which is pointing at the location
- of the old base pointer. The instruction \code{subq \$16, \%rsp} moves the stack
- pointer down to make enough room for storing variables. This program
- needs one variable ($8$ bytes) but we round up to 16 bytes so that
- \code{rsp} is 16-byte aligned and we're ready to make calls to other
- functions.
- \racket{The last instruction of the prelude is \code{jmp start},
- which transfers control to the instructions that were generated from
- the expression \racket{\code{(+ 52 (- 10))}}\python{52 + -10}.}
- \racket{The first instruction under the \code{start} label is}
- %
- \python{The first instruction after the prelude is}
- %
- \code{movq \$10, -8(\%rbp)}, which stores $10$ in variable $1$.
- %
- The instruction \code{negq -8(\%rbp)} changes variable $1$ to $-10$.
- %
- The next instruction moves the $-10$ from variable $1$ into the
- \code{rax} register. Finally, \code{addq \$52, \%rax} adds $52$ to
- the value in \code{rax}, updating its contents to $42$.
- \racket{The three instructions under the label \code{conclusion} are the
- typical \emph{conclusion}\index{subject}{conclusion} of a procedure.}
- %
- \python{The \emph{conclusion}\index{subject}{conclusion} of the
- \code{main} function consists of the last three instructions.}
- %
- The first two restore the \code{rsp} and \code{rbp} registers to the
- state they were in at the beginning of the procedure. In particular,
- \key{addq \$16, \%rsp} moves the stack pointer back to point at the
- old base pointer. Then \key{popq \%rbp} returns the old base pointer
- to \key{rbp} and adds $8$ to the stack pointer. The last instruction,
- \key{retq}, jumps back to the procedure that called this one and adds
- $8$ to the stack pointer.
- Our compiler needs a convenient representation for manipulating x86
- programs, so we define an abstract syntax for x86 in
- Figure~\ref{fig:x86-int-ast}. We refer to this language as
- \LangXInt{}.
- %
- {\if\edition\racketEd
- The main difference compared to the concrete syntax of \LangXInt{}
- (Figure~\ref{fig:x86-int-concrete}) is that labels are not allowed in
- front of every instruction. Instead instructions are grouped into
- \emph{blocks}\index{subject}{block} with a
- label associated with every block, which is why the \key{X86Program}
- struct includes an alist mapping labels to blocks. The reason for this
- organization becomes apparent in Chapter~\ref{ch:Lif} when we
- introduce conditional branching. The \code{Block} structure includes
- an $\itm{info}$ field that is not needed for this chapter, but becomes
- useful in Chapter~\ref{ch:register-allocation-Lvar}. For now, the
- $\itm{info}$ field should contain an empty list.
- \fi}
- %
- Regarding the abstract syntax for \code{callq}, the \code{Callq} AST
- node includes an integer for representing the arity of the function,
- i.e., the number of arguments, which is helpful to know during
- register allocation (Chapter~\ref{ch:register-allocation-Lvar}).
- \begin{figure}[tp]
- \fbox{
- \begin{minipage}{0.98\textwidth}
- \small
- {\if\edition\racketEd
- \[
- \begin{array}{lcl}
- \Reg &::=& \allregisters{} \\
- \Arg &::=& \IMM{\Int} \MID \REG{\Reg}
- \MID \DEREF{\Reg}{\Int} \\
- \Instr &::=& \BININSTR{\code{addq}}{\Arg}{\Arg}
- \MID \BININSTR{\code{subq}}{\Arg}{\Arg} \\
- &\MID& \BININSTR{\code{movq}}{\Arg}{\Arg}
- \MID \UNIINSTR{\code{negq}}{\Arg}\\
- &\MID& \CALLQ{\itm{label}}{\itm{int}} \MID \RETQ{}
- \MID \PUSHQ{\Arg} \MID \POPQ{\Arg} \MID \JMP{\itm{label}} \\
- \Block &::= & \BLOCK{\itm{info}}{\LP\Instr\ldots\RP} \\
- \LangXIntM{} &::= & \XPROGRAM{\itm{info}}{\LP\LP\itm{label} \,\key{.}\, \Block \RP\ldots\RP}
- \end{array}
- \]
- \fi}
- {\if\edition\pythonEd
- \[
- \begin{array}{lcl}
- \Reg &::=& \allregisters{} \\
- \Arg &::=& \IMM{\Int} \MID \REG{\Reg}
- \MID \DEREF{\Reg}{\Int} \\
- \Instr &::=& \BININSTR{\code{addq}}{\Arg}{\Arg}
- \MID \BININSTR{\code{subq}}{\Arg}{\Arg} \\
- &\MID& \BININSTR{\code{movq}}{\Arg}{\Arg}
- \MID \UNIINSTR{\code{negq}}{\Arg}\\
- &\MID& \CALLQ{\itm{label}}{\itm{int}} \MID \RETQ{}
- \MID \PUSHQ{\Arg} \MID \POPQ{\Arg} \MID \JMP{\itm{label}} \\
- \LangXIntM{} &::= & \XPROGRAM{}{\Instr^{*}}{}
- \end{array}
- \]
- \fi}
- \end{minipage}
- }
- \caption{The abstract syntax of \LangXInt{} assembly.}
- \label{fig:x86-int-ast}
- \end{figure}
- \section{Planning the trip to x86}
- \label{sec:plan-s0-x86}
- To compile one language to another it helps to focus on the
- differences between the two languages because the compiler will need
- to bridge those differences. What are the differences between \LangVar{}
- and x86 assembly? Here are some of the most important ones:
- \begin{enumerate}
- \item x86 arithmetic instructions typically have two arguments
- and update the second argument in place. In contrast, \LangVar{}
- arithmetic operations take two arguments and produce a new value.
- An x86 instruction may have at most one memory-accessing argument.
- Furthermore, some instructions place special restrictions on their
- arguments.
- \item An argument of an \LangVar{} operator can be a deeply-nested
- expression, whereas x86 instructions restrict their arguments to be
- integer constants, registers, and memory locations.
- {\if\edition\racketEd
- \item The order of execution in x86 is explicit in the syntax: a
- sequence of instructions and jumps to labeled positions, whereas in
- \LangVar{} the order of evaluation is a left-to-right depth-first
- traversal of the abstract syntax tree.
- \fi}
- \item A program in \LangVar{} can have any number of variables
- whereas x86 has 16 registers and the procedure call stack.
- {\if\edition\racketEd
- \item Variables in \LangVar{} can shadow other variables with the
- same name. In x86, registers have unique names and memory locations
- have unique addresses.
- \fi}
- \end{enumerate}
- We ease the challenge of compiling from \LangVar{} to x86 by breaking down
- the problem into several steps, dealing with the above differences one
- at a time. Each of these steps is called a \emph{pass} of the
- compiler.\index{subject}{pass}\index{subject}{compiler pass}
- %
- This terminology comes from the way each step passes over the AST of
- the program.
- %
- We begin by sketching how we might implement each pass, and give them
- names. We then figure out an ordering of the passes and the
- input/output language for each pass. The very first pass has
- \LangVar{} as its input language and the last pass has \LangXInt{} as
- its output language. In between we can choose whichever language is
- most convenient for expressing the output of each pass, whether that
- be \LangVar{}, \LangXInt{}, or new \emph{intermediate languages} of
- our own design. Finally, to implement each pass we write one
- recursive function per non-terminal in the grammar of the input
- language of the pass. \index{subject}{intermediate language}
- \begin{description}
- {\if\edition\racketEd
- \item[\key{uniquify}] deals with the shadowing of variables by
- renaming every variable to a unique name.
- \fi}
- \item[\key{remove\_complex\_operands}] ensures that each subexpression
- of a primitive operation or function call is a variable or integer,
- that is, an \emph{atomic} expression. We refer to non-atomic
- expressions as \emph{complex}. This pass introduces temporary
- variables to hold the results of complex
- subexpressions.\index{subject}{atomic
- expression}\index{subject}{complex expression}%
-
- {\if\edition\racketEd
- \item[\key{explicate\_control}] makes the execution order of the
- program explicit. It convert the abstract syntax tree representation
- into a control-flow graph in which each node contains a sequence of
- statements and the edges between nodes say which nodes contain jumps
- to other nodes.
- \fi}
- \item[\key{select\_instructions}] handles the difference between
- \LangVar{} operations and x86 instructions. This pass converts each
- \LangVar{} operation to a short sequence of instructions that
- accomplishes the same task.
- \item[\key{assign\_homes}] replaces the variables in \LangVar{} with
- registers or stack locations in x86.
- \end{description}
- The next question is: in what order should we apply these passes? This
- question can be challenging because it is difficult to know ahead of
- time which orderings will be better (easier to implement, produce more
- efficient code, etc.) so oftentimes trial-and-error is
- involved. Nevertheless, we can try to plan ahead and make educated
- choices regarding the ordering.
- \racket{What should be the ordering of \key{explicate\_control} with respect to
- \key{uniquify}? The \key{uniquify} pass should come first because
- \key{explicate\_control} changes all the \key{let}-bound variables to
- become local variables whose scope is the entire program, which would
- confuse variables with the same name.}
- %
- \racket{We place \key{remove\_complex\_opera*} before \key{explicate\_control}
- because the later removes the \key{let} form, but it is convenient to
- use \key{let} in the output of \key{remove\_complex\_opera*}.}
- %
- \racket{The ordering of \key{uniquify} with respect to
- \key{remove\_complex\_opera*} does not matter so we arbitrarily choose
- \key{uniquify} to come first.}
- The \key{select\_instructions} and \key{assign\_homes} passes are
- intertwined.
- %
- In Chapter~\ref{ch:Rfun} we learn that, in x86, registers are used for
- passing arguments to functions and it is preferable to assign
- parameters to their corresponding registers. This suggests that it
- would be better to start with the \key{select\_instructions} pass,
- which generates the instructions for argument passing, before
- performing register allocation.
- %
- On the other hand, by selecting instructions first we may run into a
- dead end in \key{assign\_homes}. Recall that only one argument of an
- x86 instruction may be a memory access but \key{assign\_homes} might
- be forced to assign both arguments to memory locations.
- %
- A sophisticated approach is to iteratively repeat the two passes until
- a solution is found. However, to reduce implementation complexity we
- recommend a simpler approach in which \key{select\_instructions} comes
- first, followed by the \key{assign\_homes}, then a third pass named
- \key{patch\_instructions} that uses a reserved register to fix
- outstanding problems.
- \begin{figure}[tbp]
- {\if\edition\racketEd
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (Lvar) at (0,2) {\large \LangVar{}};
- \node (Lvar-2) at (3,2) {\large \LangVar{}};
- \node (Lvar-3) at (6,2) {\large \LangVarANF{}};
- %\node (Cvar-1) at (6,0) {\large \LangCVar{}};
- \node (Cvar-2) at (3,0) {\large \LangCVar{}};
- \node (x86-2) at (3,-2) {\large \LangXVar{}};
- \node (x86-3) at (6,-2) {\large \LangXVar{}};
- \node (x86-4) at (9,-2) {\large \LangXInt{}};
- \node (x86-5) at (12,-2) {\large \LangXInt{}};
- \path[->,bend left=15] (Lvar) edge [above] node {\ttfamily\footnotesize uniquify} (Lvar-2);
- \path[->,bend left=15] (Lvar-2) edge [above] node {\ttfamily\footnotesize remove\_complex.} (Lvar-3);
- \path[->,bend left=15] (Lvar-3) edge [right] node {\ttfamily\footnotesize explicate\_control} (Cvar-2);
- \path[->,bend right=15] (Cvar-2) edge [left] node {\ttfamily\footnotesize select\_instr.} (x86-2);
- \path[->,bend left=15] (x86-2) edge [above] node {\ttfamily\footnotesize assign\_homes} (x86-3);
- \path[->,bend left=15] (x86-3) edge [above] node {\ttfamily\footnotesize patch\_instr.} (x86-4);
- \path[->,bend left=15] (x86-4) edge [above] node {\ttfamily\footnotesize prelude\_and\_concl.} (x86-5);
- \end{tikzpicture}
- \fi}
- {\if\edition\pythonEd
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (Lvar) at (0,2) {\large \LangVar{}};
- \node (Lvar-2) at (3,2) {\large \LangVarANF{}};
- \node (x86-1) at (3,0) {\large \LangXVar{}};
- \node (x86-2) at (6,0) {\large \LangXVar{}};
- \node (x86-3) at (9,0) {\large \LangXInt{}};
- \node (x86-4) at (12,0) {\large \LangXInt{}};
- \path[->,bend left=15] (Lvar) edge [above] node {\ttfamily\footnotesize remove\_complex.} (Lvar-2);
- \path[->,bend right=15] (Lvar-2) edge [left] node {\ttfamily\footnotesize select\_instr.} (x86-1);
- \path[->,bend right=15] (x86-1) edge [below] node {\ttfamily\footnotesize assign\_homes} (x86-2);
- \path[->,bend left=15] (x86-2) edge [above] node {\ttfamily\footnotesize patch\_instr.} (x86-3);
- \path[->,bend right=15] (x86-3) edge [below] node {\ttfamily\footnotesize prelude\_and\_concl.} (x86-4);
- \end{tikzpicture}
- \fi}
- \caption{Diagram of the passes for compiling \LangVar{}. }
- \label{fig:Lvar-passes}
- \end{figure}
- Figure~\ref{fig:Lvar-passes} presents the ordering of the compiler
- passes and identifies the input and output language of each pass.
- %
- The output of the \key{select\_instructions} pass is the \LangXVar{}
- language, which extends \LangXInt{} with an unbounded number of
- program-scope variables and removes the restrictions regarding
- instruction arguments.
- %
- The last pass, \key{prelude\_and\_conclusion}, places the program
- instructions inside a \code{main} function with instructions for the
- prelude and conclusion.
- %
- \racket{In the following section we discuss the \LangCVar{}
- intermediate language.}
- %
- The remainder of this chapter provides guidance on the implementation
- of each of the compiler passes in Figure~\ref{fig:Lvar-passes}.
- %% The output of \key{uniquify} and \key{remove-complex-opera*}
- %% are programs that are still in the \LangVar{} language, though the
- %% output of the later is a subset of \LangVar{} named \LangVarANF{}
- %% (Section~\ref{sec:remove-complex-opera-Lvar}).
- %% %
- %% The output of \code{explicate\_control} is in an intermediate language
- %% \LangCVar{} designed to make the order of evaluation explicit in its
- %% syntax, which we introduce in the next section. The
- %% \key{select-instruction} pass translates from \LangCVar{} to
- %% \LangXVar{}. The \key{assign-homes} and
- %% \key{patch-instructions}
- %% passes input and output variants of x86 assembly.
- {\if\edition\racketEd
- \subsection{The \LangCVar{} Intermediate Language}
- The output of \code{explicate\_control} is similar to the $C$
- language~\citep{Kernighan:1988nx} in that it has separate syntactic
- categories for expressions and statements, so we name it \LangCVar{}.
- The concrete syntax for \LangCVar{} is defined in
- Figure~\ref{fig:c0-concrete-syntax} and the abstract syntax for
- \LangCVar{} is defined in Figure~\ref{fig:c0-syntax}.
- %
- The \LangCVar{} language supports the same operators as \LangVar{} but
- the arguments of operators are restricted to atomic
- expressions. Instead of \key{let} expressions, \LangCVar{} has
- assignment statements which can be executed in sequence using the
- \key{Seq} form. A sequence of statements always ends with
- \key{Return}, a guarantee that is baked into the grammar rules for
- \itm{tail}. The naming of this non-terminal comes from the term
- \emph{tail position}\index{subject}{tail position}, which refers to an
- expression that is the last one to execute within a function.
- A \LangCVar{} program consists of an alist mapping labels to
- tails. This is more general than necessary for the present chapter, as
- we do not yet introduce \key{goto} for jumping to labels, but it saves
- us from having to change the syntax in Chapter~\ref{ch:Lif}. For now
- there will be just one label, \key{start}, and the whole program is
- its tail.
- %
- The $\itm{info}$ field of the \key{CProgram} form, after the
- \code{explicate\_control} pass, contains a mapping from the symbol
- \key{locals} to a list of variables, that is, a list of all the
- variables used in the program. At the start of the program, these
- variables are uninitialized; they become initialized on their first
- assignment.
- \begin{figure}[tbp]
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \[
- \begin{array}{lcl}
- \Atm &::=& \Int \MID \Var \\
- \Exp &::=& \Atm \MID \key{(read)} \MID \key{(-}~\Atm\key{)} \MID \key{(+}~\Atm~\Atm\key{)}\\
- \Stmt &::=& \Var~\key{=}~\Exp\key{;} \\
- \Tail &::= & \key{return}~\Exp\key{;} \MID \Stmt~\Tail \\
- \LangCVarM{} & ::= & (\itm{label}\key{:}~ \Tail)\ldots
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The concrete syntax of the \LangCVar{} intermediate language.}
- \label{fig:c0-concrete-syntax}
- \end{figure}
- \begin{figure}[tbp]
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \[
- \begin{array}{lcl}
- \Atm &::=& \INT{\Int} \MID \VAR{\Var} \\
- \Exp &::=& \Atm \MID \READ{} \MID \NEG{\Atm} \\
- &\MID& \ADD{\Atm}{\Atm}\\
- \Stmt &::=& \ASSIGN{\VAR{\Var}}{\Exp} \\
- \Tail &::= & \RETURN{\Exp} \MID \SEQ{\Stmt}{\Tail} \\
- \LangCVarM{} & ::= & \CPROGRAM{\itm{info}}{\LP\LP\itm{label}\,\key{.}\,\Tail\RP\ldots\RP}
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The abstract syntax of the \LangCVar{} intermediate language.}
- \label{fig:c0-syntax}
- \end{figure}
- The definitional interpreter for \LangCVar{} is in the support code,
- in the file \code{interp-Cvar.rkt}.
- \fi}
- {\if\edition\racketEd
- \section{Uniquify Variables}
- \label{sec:uniquify-Lvar}
- The \code{uniquify} pass compiles \LangVar{} programs into \LangVar{}
- programs in which every \key{let} binds a unique variable name. For
- example, the \code{uniquify} pass should translate the program on the
- left into the program on the right.
- \begin{transformation}
- \begin{lstlisting}
- (let ([x 32])
- (+ (let ([x 10]) x) x))
- \end{lstlisting}
- \compilesto
- \begin{lstlisting}
- (let ([x.1 32])
- (+ (let ([x.2 10]) x.2) x.1))
- \end{lstlisting}
- \end{transformation}
- The following is another example translation, this time of a program
- with a \key{let} nested inside the initializing expression of another
- \key{let}.
- \begin{transformation}
- \begin{lstlisting}
- (let ([x (let ([x 4])
- (+ x 1))])
- (+ x 2))
- \end{lstlisting}
- \compilesto
- \begin{lstlisting}
- (let ([x.2 (let ([x.1 4])
- (+ x.1 1))])
- (+ x.2 2))
- \end{lstlisting}
- \end{transformation}
- We recommend implementing \code{uniquify} by creating a structurally
- recursive function named \code{uniquify-exp} that mostly just copies
- an expression. However, when encountering a \key{let}, it should
- generate a unique name for the variable and associate the old name
- with the new name in an alist.\footnote{The Racket function
- \code{gensym} is handy for generating unique variable names.} The
- \code{uniquify-exp} function needs to access this alist when it gets
- to a variable reference, so we add a parameter to \code{uniquify-exp}
- for the alist.
- The skeleton of the \code{uniquify-exp} function is shown in
- Figure~\ref{fig:uniquify-Lvar}. The function is curried so that it is
- convenient to partially apply it to an alist and then apply it to
- different expressions, as in the last case for primitive operations in
- Figure~\ref{fig:uniquify-Lvar}. The
- %
- \href{https://docs.racket-lang.org/reference/for.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._for%2Flist%29%29}{\key{for/list}}
- %
- form of Racket is useful for transforming each element of a list to
- produce a new list.\index{subject}{for/list}
- \begin{figure}[tbp]
- \begin{lstlisting}
- (define (uniquify-exp env)
- (lambda (e)
- (match e
- [(Var x) ___]
- [(Int n) (Int n)]
- [(Let x e body) ___]
- [(Prim op es)
- (Prim op (for/list ([e es]) ((uniquify-exp env) e)))])))
- (define (uniquify p)
- (match p
- [(Program '() e) (Program '() ((uniquify-exp '()) e))]))
- \end{lstlisting}
- \caption{Skeleton for the \key{uniquify} pass.}
- \label{fig:uniquify-Lvar}
- \end{figure}
- \begin{exercise}
- \normalfont % I don't like the italics for exercises. -Jeremy
- Complete the \code{uniquify} pass by filling in the blanks in
- Figure~\ref{fig:uniquify-Lvar}, that is, implement the cases for
- variables and for the \key{let} form in the file \code{compiler.rkt}
- in the support code.
- \end{exercise}
- \begin{exercise}
- \normalfont % I don't like the italics for exercises. -Jeremy
- \label{ex:Lvar}
- Create five \LangVar{} programs that exercise the most interesting
- parts of the \key{uniquify} pass, that is, the programs should include
- \key{let} forms, variables, and variables that shadow each other.
- The five programs should be placed in the subdirectory named
- \key{tests} and the file names should start with \code{var\_test\_}
- followed by a unique integer and end with the file extension
- \key{.rkt}.
- %
- The \key{run-tests.rkt} script in the support code checks whether the
- output programs produce the same result as the input programs. The
- script uses the \key{interp-tests} function
- (Appendix~\ref{appendix:utilities}) from \key{utilities.rkt} to test
- your \key{uniquify} pass on the example programs. The \code{passes}
- parameter of \key{interp-tests} is a list that should have one entry
- for each pass in your compiler. For now, define \code{passes} to
- contain just one entry for \code{uniquify} as shown below.
- \begin{lstlisting}
- (define passes
- (list (list "uniquify" uniquify interp_Lvar type-check-Lvar)))
- \end{lstlisting}
- Run the \key{run-tests.rkt} script in the support code to check
- whether the output programs produce the same result as the input
- programs.
- \end{exercise}
- \fi}
- \section{Remove Complex Operands}
- \label{sec:remove-complex-opera-Lvar}
- The \code{remove\_complex\_operands} pass compiles \LangVar{} programs
- into a restricted form in which the arguments of operations are atomic
- expressions. Put another way, this pass removes complex
- operands\index{subject}{complex operand}, such as the expression
- \racket{\code{(- 10)}}\python{\code{-10}}
- in the program below. This is accomplished by introducing a new
- temporary variable, assigning the complex operand to the new
- variable, and then using the new variable in place of the complex
- operand, as shown in the output of \code{remove\_complex\_operands} on the
- right.
- {\if\edition\racketEd
- \begin{transformation}
- % var_test_19.rkt
- \begin{lstlisting}
- (let ([x (+ 42 (- 10))])
- (+ x 10))
- \end{lstlisting}
- \compilesto
- \begin{lstlisting}
- (let ([x (let ([tmp.1 (- 10)])
- (+ 42 tmp.1))])
- (+ x 10))
- \end{lstlisting}
- \end{transformation}
- \fi}
- {\if\edition\pythonEd
- \begin{transformation}
- \begin{lstlisting}
- x = 42 + -10
- print(x + 10)
- \end{lstlisting}
- \compilesto
- \begin{lstlisting}
- tmp_0 = -10
- x = 42 + tmp_0
- tmp_1 = x + 10
- print(tmp_1)
- \end{lstlisting}
- \end{transformation}
- \fi}
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- {\if\edition\racketEd
- \[
- \begin{array}{rcl}
- \Atm &::=& \INT{\Int} \MID \VAR{\Var} \\
- \Exp &::=& \Atm \MID \READ{} \\
- &\MID& \NEG{\Atm} \MID \ADD{\Atm}{\Atm} \\
- &\MID& \LET{\Var}{\Exp}{\Exp} \\
- \LangVarANFM{} &::=& \PROGRAM{\code{'()}}{\Exp}
- \end{array}
- \]
- \fi}
- {\if\edition\pythonEd
- \[
- \begin{array}{rcl}
- \Atm &::=& \INT{\Int} \MID \VAR{\Var} \\
- \Exp{} &::=& \Atm \MID \READ{} \\
- &\MID& \NEG{\Atm} \MID \ADD{\Atm}{\Atm} \\
- \Stmt{} &::=& \PRINT{\Atm} \MID \EXPR{\Exp} \\
- &\MID& \ASSIGN{\VAR{\Var}}{\Exp}\\
- \LangVarANFM{} &::=& \PROGRAM{}{\Stmt^{*}}
- \end{array}
- \]
- \fi}
- \end{minipage}
- }
- \caption{\LangVarANF{} is \LangVar{} with operands restricted to
- atomic expressions.}
- \label{fig:Lvar-anf-syntax}
- \end{figure}
- Figure~\ref{fig:Lvar-anf-syntax} presents the grammar for the output of
- this pass, the language \LangVarANF{}. The only difference is that
- operator arguments are restricted to be atomic expressions that are
- defined by the \Atm{} non-terminal. In particular, integer constants
- and variables are atomic. In the literature, restricting arguments to
- be atomic expressions is one of the ideas in \emph{administrative
- normal form}, or ANF for short~\citep{Danvy:1991fk,Flanagan:1993cg}.
- \index{subject}{administrative normal form} \index{subject}{ANF}
- {\if\edition\racketEd
- We recommend implementing this pass with two mutually recursive
- functions, \code{rco\_atom} and \code{rco\_exp}. The idea is to apply
- \code{rco\_atom} to subexpressions that need to become atomic and to
- apply \code{rco\_exp} to subexpressions that do not. Both functions
- take an \LangVar{} expression as input. The \code{rco\_exp} function
- returns an expression. The \code{rco\_atom} function returns two
- things: an atomic expression and an alist mapping temporary variables to
- complex subexpressions. You can return multiple things from a function
- using Racket's \key{values} form and you can receive multiple things
- from a function call using the \key{define-values} form.
- Also, the
- \href{https://docs.racket-lang.org/reference/for.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._for%2Flists%29%29}{\code{for/lists}}
- form is useful for applying a function to each element of a list, in
- the case where the function returns multiple values.
- \index{subject}{for/lists}
- \fi}
- %
- {\if\edition\pythonEd
- %
- We recommend implementing this pass with an auxiliary method named
- \code{rco\_exp} with two parameters: an \LangVar{} expression and a
- Boolean that specifies whether the expression needs to become atomic
- or not. The \code{rco\_exp} method should return a pair consisting of
- the new expression and a list of pairs, associating new temporary
- variables with their initializing expressions.
- %
- \fi}
- {\if\edition\racketEd
- Returning to the example program with the expression \code{(+ 42 (-
- 10))}, the subexpression \code{(- 10)} should be processed using the
- \code{rco\_atom} function because it is an argument of the \code{+} and
- therefore needs to become atomic. The output of \code{rco\_atom}
- applied to \code{(- 10)} is as follows.
- \begin{transformation}
- \begin{lstlisting}
- (- 10)
- \end{lstlisting}
- \compilesto
- \begin{lstlisting}
- tmp.1
- ((tmp.1 . (- 10)))
- \end{lstlisting}
- \end{transformation}
- \fi}
- %
- {\if\edition\pythonEd
- %
- Returning to the example program with the expression \code{42 + -10},
- the subexpression \code{-10} should be processed using the
- \code{rco\_exp} function with \code{True} as the second argument
- because \code{-10} is an argument of the \code{+} operator and
- therefore needs to become atomic. The output of \code{rco\_exp}
- applied to \code{-10} is as follows.
- \begin{transformation}
- \begin{lstlisting}
- -10
- \end{lstlisting}
- \compilesto
- \begin{lstlisting}
- tmp_1
- [(tmp_1, -10)]
- \end{lstlisting}
- \end{transformation}
- %
- \fi}
- Take special care of programs such as the following that
- %
- \racket{bind a variable to an atomic expression}
- %
- \python{assign an atomic expression to a variable}.
- %
- You should leave such \racket{variable bindings}\python{assignments}
- unchanged, as shown in the program on the right\\
- %
- {\if\edition\racketEd
- \begin{transformation}
- % var_test_20.rkt
- \begin{lstlisting}
- (let ([a 42])
- (let ([b a])
- b))
- \end{lstlisting}
- \compilesto
- \begin{lstlisting}
- (let ([a 42])
- (let ([b a])
- b))
- \end{lstlisting}
- \end{transformation}
- \fi}
- {\if\edition\pythonEd
- \begin{transformation}
- \begin{lstlisting}
- a = 42
- b = a
- print(b)
- \end{lstlisting}
- \compilesto
- \begin{lstlisting}
- a = 42
- b = a
- print(b)
- \end{lstlisting}
- \end{transformation}
- \fi}
- %
- \noindent A careless implementation might produce the following output with
- unnecessary temporary variables.
- \begin{center}
- \begin{minipage}{0.4\textwidth}
- {\if\edition\racketEd
- \begin{lstlisting}
- (let ([tmp.1 42])
- (let ([a tmp.1])
- (let ([tmp.2 a])
- (let ([b tmp.2])
- b))))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- tmp_1 = 42
- a = tmp_1
- tmp_2 = a
- b = tmp_2
- print(b)
- \end{lstlisting}
- \fi}
- \end{minipage}
- \end{center}
- \begin{exercise}
- \normalfont
- {\if\edition\racketEd
- Implement the \code{remove\_complex\_operands} function in
- \code{compiler.rkt}.
- %
- Create three new \LangVar{} programs that exercise the interesting
- code in the \code{remove\_complex\_operands} pass. Follow the guidelines
- regarding file names described in Exercise~\ref{ex:Lvar}.
- %
- In the \code{run-tests.rkt} script, add the following entry to the
- list of \code{passes} and then run the script to test your compiler.
- \begin{lstlisting}
- (list "remove-complex" remove-complex-opera* interp_Lvar type-check-Lvar)
- \end{lstlisting}
- While debugging your compiler, it is often useful to see the
- intermediate programs that are output from each pass. To print the
- intermediate programs, place \lstinline{(debug-level 1)} before the call to
- \code{interp-tests} in \code{run-tests.rkt}.
- \fi}
- %
- {\if\edition\pythonEd
- Implement the \code{remove\_complex\_operands} pass in
- \code{compiler.py}, creating auxiliary functions for each
- non-terminal in the grammar, i.e., \code{rco\_exp}
- and \code{rco\_stmt}.
- \fi}
- \end{exercise}
- {\if\edition\pythonEd
- \begin{exercise}
- \normalfont % I don't like the italics for exercises. -Jeremy
- \label{ex:Lvar}
- Create five \LangVar{} programs that exercise the most interesting
- parts of the \code{remove\_complex\_operands} pass. The five programs
- should be placed in the subdirectory named \key{tests} and the file
- names should start with \code{var\_test\_} followed by a unique
- integer and end with the file extension \key{.py}.
- %% The \key{run-tests.rkt} script in the support code checks whether the
- %% output programs produce the same result as the input programs. The
- %% script uses the \key{interp-tests} function
- %% (Appendix~\ref{appendix:utilities}) from \key{utilities.rkt} to test
- %% your \key{uniquify} pass on the example programs. The \code{passes}
- %% parameter of \key{interp-tests} is a list that should have one entry
- %% for each pass in your compiler. For now, define \code{passes} to
- %% contain just one entry for \code{uniquify} as shown below.
- %% \begin{lstlisting}
- %% (define passes
- %% (list (list "uniquify" uniquify interp_Lvar type-check-Lvar)))
- %% \end{lstlisting}
- Run the \key{run-tests.py} script in the support code to check
- whether the output programs produce the same result as the input
- programs.
- \end{exercise}
- \fi}
- {\if\edition\racketEd
- \section{Explicate Control}
- \label{sec:explicate-control-Lvar}
- The \code{explicate\_control} pass compiles \LangVar{} programs into \LangCVar{}
- programs that make the order of execution explicit in their
- syntax. For now this amounts to flattening \key{let} constructs into a
- sequence of assignment statements. For example, consider the following
- \LangVar{} program.\\
- % var_test_11.rkt
- \begin{minipage}{0.96\textwidth}
- \begin{lstlisting}
- (let ([y (let ([x 20])
- (+ x (let ([x 22]) x)))])
- y)
- \end{lstlisting}
- \end{minipage}\\
- %
- The output of the previous pass and of \code{explicate\_control} is
- shown below. Recall that the right-hand-side of a \key{let} executes
- before its body, so the order of evaluation for this program is to
- assign \code{20} to \code{x.1}, \code{22} to \code{x.2}, and
- \code{(+ x.1 x.2)} to \code{y}, then return \code{y}. Indeed, the
- output of \code{explicate\_control} makes this ordering explicit.
- \begin{transformation}
- \begin{lstlisting}
- (let ([y (let ([x.1 20])
- (let ([x.2 22])
- (+ x.1 x.2)))])
- y)
- \end{lstlisting}
- \compilesto
- \begin{lstlisting}[language=C]
- start:
- x.1 = 20;
- x.2 = 22;
- y = (+ x.1 x.2);
- return y;
- \end{lstlisting}
- \end{transformation}
- \begin{figure}[tbp]
- \begin{lstlisting}
- (define (explicate_tail e)
- (match e
- [(Var x) ___]
- [(Int n) (Return (Int n))]
- [(Let x rhs body) ___]
- [(Prim op es) ___]
- [else (error "explicate_tail unhandled case" e)]))
- (define (explicate_assign e x cont)
- (match e
- [(Var x) ___]
- [(Int n) (Seq (Assign (Var x) (Int n)) cont)]
- [(Let y rhs body) ___]
- [(Prim op es) ___]
- [else (error "explicate_assign unhandled case" e)]))
- (define (explicate_control p)
- (match p
- [(Program info body) ___]))
- \end{lstlisting}
- \caption{Skeleton for the \code{explicate\_control} pass.}
- \label{fig:explicate-control-Lvar}
- \end{figure}
- The organization of this pass depends on the notion of tail position
- that we have alluded to earlier.
- \begin{definition}
- The following rules define when an expression is in \textbf{\emph{tail
- position}}\index{subject}{tail position} for the language \LangVar{}.
- \begin{enumerate}
- \item In $\PROGRAM{\code{()}}{e}$, expression $e$ is in tail position.
- \item If $\LET{x}{e_1}{e_2}$ is in tail position, then so is $e_2$.
- \end{enumerate}
- \end{definition}
- We recommend implementing \code{explicate\_control} using two mutually
- recursive functions, \code{explicate\_tail} and
- \code{explicate\_assign}, as suggested in the skeleton code in
- Figure~\ref{fig:explicate-control-Lvar}. The \code{explicate\_tail}
- function should be applied to expressions in tail position whereas the
- \code{explicate\_assign} should be applied to expressions that occur on
- the right-hand-side of a \key{let}.
- %
- The \code{explicate\_tail} function takes an \Exp{} in \LangVar{} as
- input and produces a \Tail{} in \LangCVar{} (see
- Figure~\ref{fig:c0-syntax}).
- %
- The \code{explicate\_assign} function takes an \Exp{} in \LangVar{},
- the variable that it is to be assigned to, and a \Tail{} in
- \LangCVar{} for the code that comes after the assignment. The
- \code{explicate\_assign} function returns a $\Tail$ in \LangCVar{}.
- The \code{explicate\_assign} function is in accumulator-passing style:
- the \code{cont} parameter is used for accumulating the output. This
- accumulator-passing style plays an important role in how we generate
- high-quality code for conditional expressions in Chapter~\ref{ch:Lif}.
- \begin{exercise}\normalfont
- %
- Implement the \code{explicate\_control} function in
- \code{compiler.rkt}. Create three new \LangInt{} programs that
- exercise the code in \code{explicate\_control}.
- %
- In the \code{run-tests.rkt} script, add the following entry to the
- list of \code{passes} and then run the script to test your compiler.
- \begin{lstlisting}
- (list "explicate control" explicate_control interp_Cvar type-check-Cvar)
- \end{lstlisting}
- \end{exercise}
- \fi}
- \section{Select Instructions}
- \label{sec:select-Lvar}
- \index{subject}{instruction selection}
- In the \code{select\_instructions} pass we begin the work of
- translating \racket{from \LangCVar{}} to \LangXVar{}. The target
- language of this pass is a variant of x86 that still uses variables,
- so we add an AST node of the form $\VAR{\itm{var}}$ to the \Arg{}
- non-terminal of the \LangXInt{} abstract syntax
- (Figure~\ref{fig:x86-int-ast}).
- \racket{We recommend implementing the
- \code{select\_instructions} with three auxiliary functions, one for
- each of the non-terminals of \LangCVar{}: $\Atm$, $\Stmt$, and
- $\Tail$.}
- \python{We recommend implementing an auxiliary function
- named \code{select\_stmt} for the $\Stmt$ non-terminal.}
- \racket{
- The cases for $\Atm$ are straightforward; variables stay
- the same and integer constants change to immediates:
- $\INT{n}$ changes to $\IMM{n}$.}
- We consider the cases for the $\Stmt$ non-terminal, starting with
- arithmetic operations. For example, consider the addition operation
- below, on the left side. There is an \key{addq} instruction in x86,
- but it performs an in-place update. So we could move $\Arg_1$
- into the left-hand side \itm{var} and then add $\Arg_2$ to
- \itm{var}, where $\Arg_1$ and $\Arg_2$ are the translations of
- $\Atm_1$ and $\Atm_2$ respectively.
- \begin{transformation}
- {\if\edition\racketEd
- \begin{lstlisting}
- |$\itm{var}$| = (+ |$\Atm_1$| |$\Atm_2$|);
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- |$\itm{var}$| = |$\Atm_1$| + |$\Atm_2$|
- \end{lstlisting}
- \fi}
- \compilesto
- \begin{lstlisting}
- movq |$\Arg_1$|, |$\itm{var}$|
- addq |$\Arg_2$|, |$\itm{var}$|
- \end{lstlisting}
- \end{transformation}
- There are also cases that require special care to avoid generating
- needlessly complicated code. For example, if one of the arguments of
- the addition is the same variable as the left-hand side of the
- assignment, as shown below, then there is no need for the extra move
- instruction. The assignment statement can be translated into a single
- \key{addq} instruction as follows.
- \begin{transformation}
- {\if\edition\racketEd
- \begin{lstlisting}
- |$\itm{var}$| = (+ |$\Atm_1$| |$\itm{var}$|);
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- |$\itm{var}$| = |$\Atm_1$| + |$\itm{var}$|
- \end{lstlisting}
- \fi}
- \compilesto
- \begin{lstlisting}
- addq |$\Arg_1$|, |$\itm{var}$|
- \end{lstlisting}
- \end{transformation}
- The \READOP{} operation does not have a direct counterpart in x86
- assembly, so we provide this functionality with the function
- \code{read\_int} in the file \code{runtime.c}, written in
- C~\citep{Kernighan:1988nx}. In general, we refer to all of the
- functionality in this file as the \emph{runtime system}\index{subject}{runtime
- system}, or simply the \emph{runtime} for short. When compiling your
- generated x86 assembly code, you need to compile \code{runtime.c} to
- \code{runtime.o} (an ``object file'', using \code{gcc} with option
- \code{-c}) and link it into the executable. For our purposes of code
- generation, all you need to do is translate an assignment of
- \READOP{} into a call to the \code{read\_int} function followed by a
- move from \code{rax} to the left-hand-side variable. (Recall that the
- return value of a function goes into \code{rax}.)
- \begin{transformation}
- {\if\edition\racketEd
- \begin{lstlisting}
- |$\itm{var}$| = (read);
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- |$\itm{var}$| = input_int();
- \end{lstlisting}
- \fi}
- \compilesto
- \begin{lstlisting}
- callq read_int
- movq %rax, |$\itm{var}$|
- \end{lstlisting}
- \end{transformation}
- {\if\edition\pythonEd
- %
- Similarly, we translate the \code{print} operation, shown below, into
- a call to the \code{print\_int} function defined in \code{runtime.c}.
- In x86, the first six arguments to functions are passed in registers,
- with the first argument passed in register \code{rdi}. So we move the
- $\Arg$ into \code{rdi} and then call \code{print\_int} using the
- \code{callq} instruction.
- \begin{transformation}
- \begin{lstlisting}
- print(|$\Atm$|)
- \end{lstlisting}
- \compilesto
- \begin{lstlisting}
- movq |$\Arg$|, %rdi
- callq print_int
- \end{lstlisting}
- \end{transformation}
- %
- \fi}
- {\if\edition\racketEd
- There are two cases for the $\Tail$ non-terminal: \key{Return} and
- \key{Seq}. Regarding \key{Return}, we recommend treating it as an
- assignment to the \key{rax} register followed by a jump to the
- conclusion of the program (so the conclusion needs to be labeled).
- For $\SEQ{s}{t}$, you can translate the statement $s$ and tail $t$
- recursively and then append the resulting instructions.
- \fi}
- \begin{exercise}
- \normalfont
- {\if\edition\racketEd
- Implement the \code{select\_instructions} pass in
- \code{compiler.rkt}. Create three new example programs that are
- designed to exercise all of the interesting cases in this pass.
- %
- In the \code{run-tests.rkt} script, add the following entry to the
- list of \code{passes} and then run the script to test your compiler.
- \begin{lstlisting}
- (list "instruction selection" select_instructions interp_pseudo-x86-0)
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- Implement the \key{select\_instructions} pass in
- \code{compiler.py}. Create three new example programs that are
- designed to exercise all of the interesting cases in this pass.
- Run the \code{run-tests.py} script to to check
- whether the output programs produce the same result as the input
- programs.
- \fi}
- \end{exercise}
- \section{Assign Homes}
- \label{sec:assign-Lvar}
- The \key{assign\_homes} pass compiles \LangXVar{} programs to
- \LangXVar{} programs that no longer use program variables.
- Thus, the \key{assign-homes} pass is responsible for placing all of
- the program variables in registers or on the stack. For runtime
- efficiency, it is better to place variables in registers, but as there
- are only 16 registers, some programs must necessarily resort to
- placing some variables on the stack. In this chapter we focus on the
- mechanics of placing variables on the stack. We study an algorithm for
- placing variables in registers in
- Chapter~\ref{ch:register-allocation-Lvar}.
- Consider again the following \LangVar{} program from
- Section~\ref{sec:remove-complex-opera-Lvar}.
- % var_test_20.rkt
- {\if\edition\racketEd
- \begin{lstlisting}
- (let ([a 42])
- (let ([b a])
- b))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- a = 42
- b = a
- print(b)
- \end{lstlisting}
- \fi}
- %
- The output of \code{select\_instructions} is shown below, on the left,
- and the output of \code{assign\_homes} is on the right. In this
- example, we assign variable \code{a} to stack location
- \code{-8(\%rbp)} and variable \code{b} to location \code{-16(\%rbp)}.
- \begin{transformation}
- \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
- movq $42, a
- movq a, b
- movq b, %rax
- \end{lstlisting}
- \compilesto
- %stack-space: 16
- \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
- movq $42, -8(%rbp)
- movq -8(%rbp), -16(%rbp)
- movq -16(%rbp), %rax
- \end{lstlisting}
- \end{transformation}
- \racket{The \code{locals-types} entry in the $\itm{info}$ of the
- \code{X86Program} node is an alist mapping all the variables in the
- program to their types (for now just \code{Integer}). The
- \code{assign\_homes} pass should replace all uses of those variables
- with stack locations. As an aside, the \code{locals-types} entry is
- computed by \code{type-check-Cvar} in the support code, which
- installs it in the $\itm{info}$ field of the \code{CProgram} node,
- which should be propagated to the \code{X86Program} node.}
- %
- \python{The \code{assign\_homes} pass should replace all uses of
- variables with stack locations.}
- %
- In the process of assigning variables to stack locations, it is
- convenient for you to compute and store the size of the frame (in
- bytes) in%
- \racket{the $\itm{info}$ field of the \key{X86Program} node, with the key \code{stack-space}}
- %
- \python{the field \code{stack\_space} of the \key{X86Program} node},
- which is needed later to generate the conclusion of the \code{main}
- procedure. The x86-64 standard requires the frame size to be a
- multiple of 16 bytes.\index{subject}{frame}
- % TODO: store the number of variables instead? -Jeremy
- \begin{exercise}\normalfont
- Implement the \key{assign\_homes} pass in
- \racket{\code{compiler.rkt}}\python{\code{compiler.py}}, defining
- auxiliary functions for each of the non-terminals in the \LangXVar{}
- grammar. We recommend that the auxiliary functions take an extra
- parameter that maps variable names to homes (stack locations for now).
- %
- {\if\edition\racketEd
- In the \code{run-tests.rkt} script, add the following entry to the
- list of \code{passes} and then run the script to test your compiler.
- \begin{lstlisting}
- (list "assign homes" assign-homes interp_x86-0)
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- Run the \code{run-tests.py} script to to check
- whether the output programs produce the same result as the input
- programs.
- \fi}
- \end{exercise}
- \section{Patch Instructions}
- \label{sec:patch-s0}
- The \code{patch\_instructions} pass compiles from \LangXVar{} to
- \LangXInt{} by making sure that each instruction adheres to the
- restriction that at most one argument of an instruction may be a
- memory reference.
- We return to the following example.\\
- \begin{minipage}{0.5\textwidth}
- % var_test_20.rkt
- {\if\edition\racketEd
- \begin{lstlisting}
- (let ([a 42])
- (let ([b a])
- b))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- a = 42
- b = a
- print(b)
- \end{lstlisting}
- \fi}
- \end{minipage}\\
- The \key{assign\_homes} pass produces the following translation. \\
- \begin{minipage}{0.5\textwidth}
- {\if\edition\racketEd
- \begin{lstlisting}
- movq $42, -8(%rbp)
- movq -8(%rbp), -16(%rbp)
- movq -16(%rbp), %rax
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- movq 42, -8(%rbp)
- movq -8(%rbp), -16(%rbp)
- movq -16(%rbp), %rdi
- callq print_int
- \end{lstlisting}
- \fi}
- \end{minipage}\\
- The second \key{movq} instruction is problematic because both
- arguments are stack locations. We suggest fixing this problem by
- moving from the source location to the register \key{rax} and then
- from \key{rax} to the destination location, as follows.
- \begin{lstlisting}
- movq -8(%rbp), %rax
- movq %rax, -16(%rbp)
- \end{lstlisting}
- \begin{exercise}
- \normalfont Implement the \key{patch\_instructions} pass in
- \racket{\code{compiler.rkt}}\python{\code{compiler.py}}.
- Create three new example programs that are
- designed to exercise all of the interesting cases in this pass.
- %
- {\if\edition\racketEd
- In the \code{run-tests.rkt} script, add the following entry to the
- list of \code{passes} and then run the script to test your compiler.
- \begin{lstlisting}
- (list "patch instructions" patch_instructions interp_x86-0)
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- Run the \code{run-tests.py} script to to check
- whether the output programs produce the same result as the input
- programs.
- \fi}
- \end{exercise}
- \section{Generate Prelude and Conclusion}
- \label{sec:print-x86}
- \index{subject}{prelude}\index{subject}{conclusion}
- The last step of the compiler from \LangVar{} to x86 is to generate
- the \code{main} function with a prelude and conclusion wrapped around
- the rest of the program, as shown in Figure~\ref{fig:p1-x86} and
- discussed in Section~\ref{sec:x86}.
- When running on Mac OS X, your compiler should prefix an underscore to
- all labels, e.g., changing \key{main} to \key{\_main}.
- %
- \racket{The Racket call \code{(system-type 'os)} is useful for
- determining which operating system the compiler is running on. It
- returns \code{'macosx}, \code{'unix}, or \code{'windows}.}
- %
- \python{The Python \code{platform} library includes a \code{system()}
- function that returns \code{'Linux'}, \code{'Windows'}, or
- \code{'Darwin'} (for Mac).}
- \begin{exercise}\normalfont
- %
- Implement the \key{prelude\_and\_conclusion} pass in
- \racket{\code{compiler.rkt}}\python{\code{compiler.py}}.
- %
- {\if\edition\racketEd
- In the \code{run-tests.rkt} script, add the following entry to the
- list of \code{passes} and then run the script to test your compiler.
- \begin{lstlisting}
- (list "prelude and conclusion" prelude-and-conclusion interp_x86-0)
- \end{lstlisting}
- %
- Uncomment the call to the \key{compiler-tests} function
- (Appendix~\ref{appendix:utilities}), which tests your complete
- compiler by executing the generated x86 code. It translates the x86
- AST that you produce into a string by invoking the \code{print-x86}
- method of the \code{print-x86-class} in \code{utilities.rkt}. Compile
- the provided \key{runtime.c} file to \key{runtime.o} using
- \key{gcc}. Run the script to test your compiler.
- %
- \fi}
- {\if\edition\pythonEd
- %
- Run the \code{run-tests.py} script to to check whether the output
- programs produce the same result as the input programs. That script
- translates the x86 AST that you produce into a string by invoking the
- \code{repr} method that is implemented by the x86 AST classes in
- \code{x86\_ast.py}.
- %
- \fi}
- \end{exercise}
- \section{Challenge: Partial Evaluator for \LangVar{}}
- \label{sec:pe-Lvar}
- \index{subject}{partial evaluation}
- This section describes two optional challenge exercises that involve
- adapting and improving the partial evaluator for \LangInt{} that was
- introduced in Section~\ref{sec:partial-evaluation}.
- \begin{exercise}\label{ex:pe-Lvar}
- \normalfont
-
- Adapt the partial evaluator from Section~\ref{sec:partial-evaluation}
- (Figure~\ref{fig:pe-arith}) so that it applies to \LangVar{} programs
- instead of \LangInt{} programs. Recall that \LangVar{} adds variables and
- %
- \racket{\key{let} binding}\python{assignment}
- %
- to the \LangInt{} language, so you will need to add cases for them in
- the \code{pe\_exp}
- %
- \racket{function}
- %
- \python{and \code{pe\_stmt} functions}.
- %
- Once complete, add the partial evaluation pass to the front of your
- compiler and make sure that your compiler still passes all of the
- tests.
- \end{exercise}
- \begin{exercise}
- \normalfont
- Improve on the partial evaluator by replacing the \code{pe\_neg} and
- \code{pe\_add} auxiliary functions with functions that know more about
- arithmetic. For example, your partial evaluator should translate
- {\if\edition\racketEd
- \[
- \code{(+ 1 (+ (read) 1))} \qquad \text{into} \qquad
- \code{(+ 2 (read))}
- \]
- \fi}
- {\if\edition\pythonEd
- \[
- \code{1 + (input\_int() + 1)} \qquad \text{into} \qquad
- \code{2 + input\_int()}
- \]
- \fi}
- To accomplish this, the \code{pe\_exp} function should produce output
- in the form of the $\itm{residual}$ non-terminal of the following
- grammar. The idea is that when processing an addition expression, we
- can always produce either 1) an integer constant, 2) an addition
- expression with an integer constant on the left-hand side but not the
- right-hand side, or 3) or an addition expression in which neither
- subexpression is a constant.
- {\if\edition\racketEd
- \[
- \begin{array}{lcl}
- \itm{inert} &::=& \Var
- \MID \LP\key{read}\RP
- \MID \LP\key{-} ~\Var\RP
- \MID \LP\key{-} ~\LP\key{read}\RP\RP
- \MID \LP\key{+} ~ \itm{inert} ~ \itm{inert}\RP\\
- &\MID& \LP\key{let}~\LP\LS\Var~\itm{residual}\RS\RP~ \itm{residual} \RP \\
- \itm{residual} &::=& \Int
- \MID \LP\key{+}~ \Int~ \itm{inert}\RP
- \MID \itm{inert}
- \end{array}
- \]
- \fi}
- {\if\edition\pythonEd
- \[
- \begin{array}{lcl}
- \itm{inert} &::=& \Var
- \MID \key{input\_int}\LP\RP
- \MID \key{-} \Var
- \MID \key{-} \key{input\_int}\LP\RP
- \MID \itm{inert} ~ \key{+} ~ \itm{inert}\\
- \itm{residual} &::=& \Int
- \MID \Int ~ \key{+} ~ \itm{inert}
- \MID \itm{inert}
- \end{array}
- \]
- \fi}
- The \code{pe\_add} and \code{pe\_neg} functions may assume that their
- inputs are $\itm{residual}$ expressions and they should return
- $\itm{residual}$ expressions. Once the improvements are complete,
- make sure that your compiler still passes all of the tests. After
- all, fast code is useless if it produces incorrect results!
- \end{exercise}
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- \chapter{Register Allocation}
- \label{ch:register-allocation-Lvar}
- \index{subject}{register allocation}
- In Chapter~\ref{ch:Lvar} we learned how to store variables on the
- stack. In this chapter we learn how to improve the performance of the
- generated code by assigning some variables to registers. The CPU can
- access a register in a single cycle, whereas accessing the stack can
- take 10s to 100s of cycles. The program in Figure~\ref{fig:reg-eg}
- serves as a running example. The source program is on the left and the
- output of instruction selection is on the right. The program is almost
- in the x86 assembly language but it still uses variables.
- \begin{figure}
- \begin{minipage}{0.45\textwidth}
- Example \LangVar{} program:
- % var_test_28.rkt
- {\if\edition\racketEd
- \begin{lstlisting}
- (let ([v 1])
- (let ([w 42])
- (let ([x (+ v 7)])
- (let ([y x])
- (let ([z (+ x w)])
- (+ z (- y)))))))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- v = 1
- w = 42
- x = v + 7
- y = x
- z = x + w
- print(z + (- y))
- \end{lstlisting}
- \fi}
- \end{minipage}
- \begin{minipage}{0.45\textwidth}
- After instruction selection:
- {\if\edition\racketEd
- \begin{lstlisting}
- locals-types:
- x : Integer, y : Integer,
- z : Integer, t : Integer,
- v : Integer, w : Integer
- start:
- movq $1, v
- movq $42, w
- movq v, x
- addq $7, x
- movq x, y
- movq x, z
- addq w, z
- movq y, t
- negq t
- movq z, %rax
- addq t, %rax
- jmp conclusion
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- movq $1, v
- movq $42, w
- movq v, x
- addq $7, x
- movq x, y
- movq x, z
- addq w, z
- movq y, tmp_0
- negq tmp_0
- movq z, tmp_1
- addq tmp_0, tmp_1
- movq tmp_1, %rdi
- callq print_int
- \end{lstlisting}
- \fi}
- \end{minipage}
- \caption{A running example for register allocation.}
- \label{fig:reg-eg}
- \end{figure}
- The goal of register allocation is to fit as many variables into
- registers as possible. Some programs have more variables than
- registers so we cannot always map each variable to a different
- register. Fortunately, it is common for different variables to be
- needed during different periods of time during program execution, and
- in such cases several variables can be mapped to the same register.
- Consider variables \code{x} and \code{z} in Figure~\ref{fig:reg-eg}.
- After the variable \code{x} is moved to \code{z} it is no longer
- needed. Variable \code{z}, on the other hand, is used only after this
- point, so \code{x} and \code{z} could share the same register. The
- topic of Section~\ref{sec:liveness-analysis-Lvar} is how to compute
- where a variable is needed. Once we have that information, we compute
- which variables are needed at the same time, i.e., which ones
- \emph{interfere} with each other, and represent this relation as an
- undirected graph whose vertices are variables and edges indicate when
- two variables interfere (Section~\ref{sec:build-interference}). We
- then model register allocation as a graph coloring problem
- (Section~\ref{sec:graph-coloring}).
- If we run out of registers despite these efforts, we place the
- remaining variables on the stack, similar to what we did in
- Chapter~\ref{ch:Lvar}. It is common to use the verb \emph{spill} for
- assigning a variable to a stack location. The decision to spill a
- variable is handled as part of the graph coloring process.
- We make the simplifying assumption that each variable is assigned to
- one location (a register or stack address). A more sophisticated
- approach is to assign a variable to one or more locations in different
- regions of the program. For example, if a variable is used many times
- in short sequence and then only used again after many other
- instructions, it could be more efficient to assign the variable to a
- register during the initial sequence and then move it to the stack for
- the rest of its lifetime. We refer the interested reader to
- \citet{Cooper:2011aa} Chapter 13 for more information about that
- approach.
- % discuss prioritizing variables based on how much they are used.
- \section{Registers and Calling Conventions}
- \label{sec:calling-conventions}
- \index{subject}{calling conventions}
- As we perform register allocation, we need to be aware of the
- \emph{calling conventions} \index{subject}{calling conventions} that govern how
- functions calls are performed in x86.
- %
- Even though \LangVar{} does not include programmer-defined functions,
- our generated code includes a \code{main} function that is called by
- the operating system and our generated code contains calls to the
- \code{read\_int} function.
- Function calls require coordination between two pieces of code that
- may be written by different programmers or generated by different
- compilers. Here we follow the System V calling conventions that are
- used by the GNU C compiler on Linux and
- MacOS~\citep{Bryant:2005aa,Matz:2013aa}.
- %
- The calling conventions include rules about how functions share the
- use of registers. In particular, the caller is responsible for freeing
- up some registers prior to the function call for use by the callee.
- These are called the \emph{caller-saved registers}
- \index{subject}{caller-saved registers}
- and they are
- \begin{lstlisting}
- rax rcx rdx rsi rdi r8 r9 r10 r11
- \end{lstlisting}
- On the other hand, the callee is responsible for preserving the values
- of the \emph{callee-saved registers}, \index{subject}{callee-saved registers}
- which are
- \begin{lstlisting}
- rsp rbp rbx r12 r13 r14 r15
- \end{lstlisting}
- We can think about this caller/callee convention from two points of
- view, the caller view and the callee view:
- \begin{itemize}
- \item The caller should assume that all the caller-saved registers get
- overwritten with arbitrary values by the callee. On the other hand,
- the caller can safely assume that all the callee-saved registers
- contain the same values after the call that they did before the
- call.
- \item The callee can freely use any of the caller-saved registers.
- However, if the callee wants to use a callee-saved register, the
- callee must arrange to put the original value back in the register
- prior to returning to the caller. This can be accomplished by saving
- the value to the stack in the prelude of the function and restoring
- the value in the conclusion of the function.
- \end{itemize}
- In x86, registers are also used for passing arguments to a function
- and for the return value. In particular, the first six arguments to a
- function are passed in the following six registers, in this order.
- \begin{lstlisting}
- rdi rsi rdx rcx r8 r9
- \end{lstlisting}
- If there are more than six arguments, then the convention is to use
- space on the frame of the caller for the rest of the
- arguments. However, in Chapter~\ref{ch:Rfun} we arrange never to
- need more than six arguments.
- %
- \racket{For now, the only function we care about is \code{read\_int}
- and it takes zero arguments.}
- %
- \python{For now, the only functions we care about are \code{read\_int}
- and \code{print\_int}, which take zero and one argument, respectively.}
- %
- The register \code{rax} is used for the return value of a function.
- The next question is how these calling conventions impact register
- allocation. Consider the \LangVar{} program in
- Figure~\ref{fig:example-calling-conventions}. We first analyze this
- example from the caller point of view and then from the callee point
- of view.
- The program makes two calls to \READOP{}. Also, the variable \code{x}
- is in use during the second call to \READOP{}, so we need to make sure
- that the value in \code{x} does not get accidentally wiped out by the
- call to \READOP{}. One obvious approach is to save all the values in
- caller-saved registers to the stack prior to each function call, and
- restore them after each call. That way, if the register allocator
- chooses to assign \code{x} to a caller-saved register, its value will
- be preserved across the call to \READOP{}. However, saving and
- restoring to the stack is relatively slow. If \code{x} is not used
- many times, it may be better to assign \code{x} to a stack location in
- the first place. Or better yet, if we can arrange for \code{x} to be
- placed in a callee-saved register, then it won't need to be saved and
- restored during function calls.
- The approach that we recommend for variables that are in use during a
- function call is to either assign them to callee-saved registers or to
- spill them to the stack. On the other hand, for variables that are not
- in use during a function call, we try the following alternatives in
- order 1) look for an available caller-saved register (to leave room
- for other variables in the callee-saved register), 2) look for a
- callee-saved register, and 3) spill the variable to the stack.
- It is straightforward to implement this approach in a graph coloring
- register allocator. First, we know which variables are in use during
- every function call because we compute that information for every
- instruction (Section~\ref{sec:liveness-analysis-Lvar}). Second, when
- we build the interference graph
- (Section~\ref{sec:build-interference}), we can place an edge between
- each of these call-live variables and the caller-saved registers in
- the interference graph. This will prevent the graph coloring algorithm
- from assigning them to caller-saved registers.
- Returning to the example in
- Figure~\ref{fig:example-calling-conventions}, let us analyze the
- generated x86 code on the right-hand side. Notice that variable
- \code{x} is assigned to \code{rbx}, a callee-saved register. Thus, it
- is already in a safe place during the second call to
- \code{read\_int}. Next, notice that variable \code{y} is assigned to
- \code{rcx}, a caller-saved register, because there are no function
- calls in the remainder of the block.
- Next we analyze the example from the callee point of view, focusing on
- the prelude and conclusion of the \code{main} function. As usual the
- prelude begins with saving the \code{rbp} register to the stack and
- setting the \code{rbp} to the current stack pointer. We now know why
- it is necessary to save the \code{rbp}: it is a callee-saved register.
- The prelude then pushes \code{rbx} to the stack because 1) \code{rbx}
- is a callee-saved register and 2) \code{rbx} is assigned to a variable
- (\code{x}). The other callee-saved registers are not saved in the
- prelude because they are not used. The prelude subtracts 8 bytes from
- the \code{rsp} to make it 16-byte aligned. Shifting attention to the
- conclusion, we see that \code{rbx} is restored from the stack with a
- \code{popq} instruction.
- \index{subject}{prelude}\index{subject}{conclusion}
- \begin{figure}[tp]
- \begin{minipage}{0.45\textwidth}
- Example \LangVar{} program:
- %var_test_14.rkt
- {\if\edition\racketEd
- \begin{lstlisting}
- (let ([x (read)])
- (let ([y (read)])
- (+ (+ x y) 42)))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- x = input_int()
- y = input_int()
- print((x + y) + 42)
- \end{lstlisting}
- \fi}
- \end{minipage}
- \begin{minipage}{0.45\textwidth}
- Generated x86 assembly:
- {\if\edition\racketEd
- \begin{lstlisting}
- start:
- callq read_int
- movq %rax, %rbx
- callq read_int
- movq %rax, %rcx
- addq %rcx, %rbx
- movq %rbx, %rax
- addq $42, %rax
- jmp _conclusion
- .globl main
- main:
- pushq %rbp
- movq %rsp, %rbp
- pushq %rbx
- subq $8, %rsp
- jmp start
- conclusion:
- addq $8, %rsp
- popq %rbx
- popq %rbp
- retq
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- .globl main
- main:
- pushq %rbp
- movq %rsp, %rbp
- pushq %rbx
- subq $8, %rsp
- callq read_int
- movq %rax, %rbx
- callq read_int
- movq %rax, %rcx
- movq %rbx, %rdx
- addq %rcx, %rdx
- movq %rdx, %rcx
- addq $42, %rcx
- movq %rcx, %rdi
- callq print_int
- addq $8, %rsp
- popq %rbx
- popq %rbp
- retq
- \end{lstlisting}
- \fi}
- \end{minipage}
- \caption{An example with function calls.}
- \label{fig:example-calling-conventions}
- \end{figure}
- %\clearpage
- \section{Liveness Analysis}
- \label{sec:liveness-analysis-Lvar}
- \index{subject}{liveness analysis}
- The \code{uncover\_live} \racket{pass}\python{function}
- performs \emph{liveness analysis}, that
- is, it discovers which variables are in-use in different regions of a
- program.
- %
- A variable or register is \emph{live} at a program point if its
- current value is used at some later point in the program. We refer to
- variables, stack locations, and registers collectively as
- \emph{locations}.
- %
- Consider the following code fragment in which there are two writes to
- \code{b}. Are \code{a} and \code{b} both live at the same time?
- \begin{center}
- \begin{minipage}{0.96\textwidth}
- \begin{lstlisting}[numbers=left,numberstyle=\tiny]
- movq $5, a
- movq $30, b
- movq a, c
- movq $10, b
- addq b, c
- \end{lstlisting}
- \end{minipage}
- \end{center}
- The answer is no because \code{a} is live from line 1 to 3 and
- \code{b} is live from line 4 to 5. The integer written to \code{b} on
- line 2 is never used because it is overwritten (line 4) before the
- next read (line 5).
- The live locations can be computed by traversing the instruction
- sequence back to front (i.e., backwards in execution order). Let
- $I_1,\ldots, I_n$ be the instruction sequence. We write
- $L_{\mathsf{after}}(k)$ for the set of live locations after
- instruction $I_k$ and $L_{\mathsf{before}}(k)$ for the set of live
- locations before instruction $I_k$.
- \racket{We recommend representing these
- sets with the Racket \code{set} data structure described in
- Figure~\ref{fig:set}.}
- \python{We recommend representing these sets with the Python
- \href{https://docs.python.org/3.10/library/stdtypes.html\#set-types-set-frozenset}{\code{set}}
- data structure.}
- {\if\edition\racketEd
- \begin{figure}[tp]
- %\begin{wrapfigure}[19]{l}[0.75in]{0.55\textwidth}
- \small
- \begin{tcolorbox}[title=\href{https://docs.racket-lang.org/reference/sets.html}{The Racket Set Package}]
- A \emph{set} is an unordered collection of elements without duplicates.
- Here are some of the operations defined on sets.
- \index{subject}{set}
- \begin{description}
- \item[$\LP\code{set}~v~\ldots\RP$] constructs a set containing the specified elements.
- \item[$\LP\code{set-union}~set_1~set_2\RP$] returns the union of the two sets.
- \item[$\LP\code{set-subtract}~set_1~set_2\RP$] returns the set
- difference of the two sets.
- \item[$\LP\code{set-member?}~set~v\RP$] answers whether element $v$ is in $set$.
- \item[$\LP\code{set-count}~set\RP$] returns the number of unique elements in $set$.
- \item[$\LP\code{set->list}~set\RP$] converts $set$ to a list.
- \end{description}
- \end{tcolorbox}
- %\end{wrapfigure}
- \caption{The \code{set} data structure.}
- \label{fig:set}
- \end{figure}
- \fi}
- The live locations after an instruction are always the same as the
- live locations before the next instruction.
- \index{subject}{live-after} \index{subject}{live-before}
- \begin{equation} \label{eq:live-after-before-next}
- L_{\mathsf{after}}(k) = L_{\mathsf{before}}(k+1)
- \end{equation}
- To start things off, there are no live locations after the last
- instruction, so
- \begin{equation}\label{eq:live-last-empty}
- L_{\mathsf{after}}(n) = \emptyset
- \end{equation}
- We then apply the following rule repeatedly, traversing the
- instruction sequence back to front.
- \begin{equation}\label{eq:live-before-after-minus-writes-plus-reads}
- L_{\mathtt{before}}(k) = (L_{\mathtt{after}}(k) - W(k)) \cup R(k),
- \end{equation}
- where $W(k)$ are the locations written to by instruction $I_k$ and
- $R(k)$ are the locations read by instruction $I_k$.
- {\if\edition\racketEd
- There is a special case for \code{jmp} instructions. The locations
- that are live before a \code{jmp} should be the locations in
- $L_{\mathtt{before}}$ at the target of the jump. So we recommend
- maintaining an alist named \code{label->live} that maps each label to
- the $L_{\mathtt{before}}$ for the first instruction in its block. For
- now the only \code{jmp} in a \LangXVar{} program is the one at the
- end, to the conclusion. (For example, see Figure~\ref{fig:reg-eg}.)
- The conclusion reads from \ttm{rax} and \ttm{rsp}, so the alist should
- map \code{conclusion} to the set $\{\ttm{rax},\ttm{rsp}\}$.
- \fi}
- Let us walk through the above example, applying these formulas
- starting with the instruction on line 5. We collect the answers in
- Figure~\ref{fig:liveness-example-0}. The $L_{\mathsf{after}}$ for the
- \code{addq b, c} instruction is $\emptyset$ because it is the last
- instruction (formula~\ref{eq:live-last-empty}). The
- $L_{\mathsf{before}}$ for this instruction is $\{\ttm{b},\ttm{c}\}$
- because it reads from variables \code{b} and \code{c}
- (formula~\ref{eq:live-before-after-minus-writes-plus-reads}), that is
- \[
- L_{\mathsf{before}}(5) = (\emptyset - \{\ttm{c}\}) \cup \{ \ttm{b}, \ttm{c} \} = \{ \ttm{b}, \ttm{c} \}
- \]
- Moving on the the instruction \code{movq \$10, b} at line 4, we copy
- the live-before set from line 5 to be the live-after set for this
- instruction (formula~\ref{eq:live-after-before-next}).
- \[
- L_{\mathsf{after}}(4) = \{ \ttm{b}, \ttm{c} \}
- \]
- This move instruction writes to \code{b} and does not read from any
- variables, so we have the following live-before set
- (formula~\ref{eq:live-before-after-minus-writes-plus-reads}).
- \[
- L_{\mathsf{before}}(4) = (\{\ttm{b},\ttm{c}\} - \{\ttm{b}\}) \cup \emptyset = \{ \ttm{c} \}
- \]
- The live-before for instruction \code{movq a, c}
- is $\{\ttm{a}\}$ because it writes to $\{\ttm{c}\}$ and reads from $\{\ttm{a}\}$
- (formula~\ref{eq:live-before-after-minus-writes-plus-reads}). The
- live-before for \code{movq \$30, b} is $\{\ttm{a}\}$ because it writes to a
- variable that is not live and does not read from a variable.
- Finally, the live-before for \code{movq \$5, a} is $\emptyset$
- because it writes to variable \code{a}.
- \begin{figure}[tbp]
- \begin{minipage}{0.45\textwidth}
- \begin{lstlisting}[numbers=left,numberstyle=\tiny]
- movq $5, a
- movq $30, b
- movq a, c
- movq $10, b
- addq b, c
- \end{lstlisting}
- \end{minipage}
- \vrule\hspace{10pt}
- \begin{minipage}{0.45\textwidth}
- \begin{align*}
- L_{\mathsf{before}}(1)= \emptyset,
- L_{\mathsf{after}}(1)= \{\ttm{a}\}\\
- L_{\mathsf{before}}(2)= \{\ttm{a}\},
- L_{\mathsf{after}}(2)= \{\ttm{a}\}\\
- L_{\mathsf{before}}(3)= \{\ttm{a}\},
- L_{\mathsf{after}}(2)= \{\ttm{c}\}\\
- L_{\mathsf{before}}(4)= \{\ttm{c}\},
- L_{\mathsf{after}}(4)= \{\ttm{b},\ttm{c}\}\\
- L_{\mathsf{before}}(5)= \{\ttm{b},\ttm{c}\},
- L_{\mathsf{after}}(5)= \emptyset
- \end{align*}
- \end{minipage}
- \caption{Example output of liveness analysis on a short example.}
- \label{fig:liveness-example-0}
- \end{figure}
- \begin{exercise}\normalfont
- Perform liveness analysis on the running example in
- Figure~\ref{fig:reg-eg}, computing the live-before and live-after
- sets for each instruction. Compare your answers to the solution
- shown in Figure~\ref{fig:live-eg}.
- \end{exercise}
- \begin{figure}[tp]
- \hspace{20pt}
- \begin{minipage}{0.45\textwidth}
- {\if\edition\racketEd
- \begin{lstlisting}
- |$\{\ttm{rsp}\}$|
- movq $1, v
- |$\{\ttm{v},\ttm{rsp}\}$|
- movq $42, w
- |$\{\ttm{v},\ttm{w},\ttm{rsp}\}$|
- movq v, x
- |$\{\ttm{w},\ttm{x},\ttm{rsp}\}$|
- addq $7, x
- |$\{\ttm{w},\ttm{x},\ttm{rsp}\}$|
- movq x, y
- |$\{\ttm{w},\ttm{x},\ttm{y},\ttm{rsp}\}$|
- movq x, z
- |$\{\ttm{w},\ttm{y},\ttm{z},\ttm{rsp}\}$|
- addq w, z
- |$\{\ttm{y},\ttm{z},\ttm{rsp}\}$|
- movq y, t
- |$\{\ttm{t},\ttm{z},\ttm{rsp}\}$|
- negq t
- |$\{\ttm{t},\ttm{z},\ttm{rsp}\}$|
- movq z, %rax
- |$\{\ttm{rax},\ttm{t},\ttm{rsp}\}$|
- addq t, %rax
- |$\{\ttm{rax},\ttm{rsp}\}$|
- jmp conclusion
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- movq $1, v
- |$\{\ttm{v}\}$|
- movq $42, w
- |$\{\ttm{w}, \ttm{v}\}$|
- movq v, x
- |$\{\ttm{w}, \ttm{x}\}$|
- addq $7, x
- |$\{\ttm{w}, \ttm{x}\}$|
- movq x, y
- |$\{\ttm{w}, \ttm{x}, \ttm{y}\}$|
- movq x, z
- |$\{\ttm{w}, \ttm{y}, \ttm{z}\}$|
- addq w, z
- |$\{\ttm{y}, \ttm{z}\}$|
- movq y, tmp_0
- |$\{\ttm{tmp\_0}, \ttm{z}\}$|
- negq tmp_0
- |$\{\ttm{tmp\_0}, \ttm{z}\}$|
- movq z, tmp_1
- |$\{\ttm{tmp\_0}, \ttm{tmp\_1}\}$|
- addq tmp_0, tmp_1
- |$\{\ttm{tmp\_1}\}$|
- movq tmp_1, %rdi
- |$\{\ttm{rdi}\}$|
- callq print_int
- |$\{\}$|
- \end{lstlisting}
- \fi}
- \end{minipage}
- \caption{The running example annotated with live-after sets.}
- \label{fig:live-eg}
- \end{figure}
- \begin{exercise}\normalfont
- Implement the \code{uncover\_live} \racket{pass}\python{function}.
- %
- \racket{Store the sequence of live-after sets in the $\itm{info}$
- field of the \code{Block} structure.}
- %
- \python{Return a dictionary that maps each instruction to its
- live-after set.}
- %
- \racket{We recommend creating an auxiliary function that takes a list
- of instructions and an initial live-after set (typically empty) and
- returns the list of live-after sets.}
- %
- We recommend creating auxiliary functions to 1) compute the set
- of locations that appear in an \Arg{}, 2) compute the locations read
- by an instruction (the $R$ function), and 3) the locations written by
- an instruction (the $W$ function). The \code{callq} instruction should
- include all of the caller-saved registers in its write-set $W$ because
- the calling convention says that those registers may be written to
- during the function call. Likewise, the \code{callq} instruction
- should include the appropriate argument-passing registers in its
- read-set $R$, depending on the arity of the function being
- called. (This is why the abstract syntax for \code{callq} includes the
- arity.)
- \end{exercise}
- %\clearpage
- \section{Build the Interference Graph}
- \label{sec:build-interference}
- {\if\edition\racketEd
- \begin{figure}[tp]
- %\begin{wrapfigure}[23]{r}[0.75in]{0.55\textwidth}
- \small
- \begin{tcolorbox}[title=\href{https://docs.racket-lang.org/graph/index.html}{The Racket Graph Library}]
- A \emph{graph} is a collection of vertices and edges where each
- edge connects two vertices. A graph is \emph{directed} if each
- edge points from a source to a target. Otherwise the graph is
- \emph{undirected}.
- \index{subject}{graph}\index{subject}{directed graph}\index{subject}{undirected graph}
- \begin{description}
- %% We currently don't use directed graphs. We instead use
- %% directed multi-graphs. -Jeremy
- \item[$\LP\code{directed-graph}\,\itm{edges}\RP$] constructs a
- directed graph from a list of edges. Each edge is a list
- containing the source and target vertex.
- \item[$\LP\code{undirected-graph}\,\itm{edges}\RP$] constructs a
- undirected graph from a list of edges. Each edge is represented by
- a list containing two vertices.
- \item[$\LP\code{add-vertex!}\,\itm{graph}\,\itm{vertex}\RP$]
- inserts a vertex into the graph.
- \item[$\LP\code{add-edge!}\,\itm{graph}\,\itm{source}\,\itm{target}\RP$]
- inserts an edge between the two vertices.
- \item[$\LP\code{in-neighbors}\,\itm{graph}\,\itm{vertex}\RP$]
- returns a sequence of vertices adjacent to the vertex.
- \item[$\LP\code{in-vertices}\,\itm{graph}\RP$]
- returns a sequence of all vertices in the graph.
- \end{description}
- \end{tcolorbox}
- %\end{wrapfigure}
- \caption{The Racket \code{graph} package.}
- \label{fig:graph}
- \end{figure}
- \fi}
- Based on the liveness analysis, we know where each location is live.
- However, during register allocation, we need to answer questions of
- the specific form: are locations $u$ and $v$ live at the same time?
- (And therefore cannot be assigned to the same register.) To make this
- question more efficient to answer, we create an explicit data
- structure, an \emph{interference graph}\index{subject}{interference
- graph}. An interference graph is an undirected graph that has an
- edge between two locations if they are live at the same time, that is,
- if they interfere with each other.
- %
- \racket{We recommend using the Racket \code{graph} package
- (Figure~\ref{fig:graph}) to represent the interference graph.}
- %
- \python{We provide implementations of directed and undirected graph
- data structures in the file \code{graph.py} of the support code.}
- A straightforward way to compute the interference graph is to look at
- the set of live locations between each instruction and add an edge to
- the graph for every pair of variables in the same set. This approach
- is less than ideal for two reasons. First, it can be expensive because
- it takes $O(n^2)$ time to consider at every pair in a set of $n$ live
- locations. Second, in the special case where two locations hold the
- same value (because one was assigned to the other), they can be live
- at the same time without interfering with each other.
- A better way to compute the interference graph is to focus on
- writes~\citep{Appel:2003fk}. The writes performed by an instruction
- must not overwrite something in a live location. So for each
- instruction, we create an edge between the locations being written to
- and the live locations. (Except that one should not create self
- edges.) Note that for the \key{callq} instruction, we consider all of
- the caller-saved registers as being written to, so an edge is added
- between every live variable and every caller-saved register. Also, for
- \key{movq} there is the above-mentioned special case to deal with. If
- a live variable $v$ is the same as the source of the \key{movq}, then
- there is no need to add an edge between $v$ and the destination,
- because they both hold the same value.
- %
- So we have the following two rules.
- \begin{enumerate}
- \item If instruction $I_k$ is a move instruction, \key{movq} $s$\key{,}
- $d$, then add the edge $(d,v)$ for every $v \in
- L_{\mathsf{after}}(k)$ unless $v = d$ or $v = s$.
- \item For any other instruction $I_k$, for every $d \in W(k)$
- add an edge $(d,v)$ for every $v \in L_{\mathsf{after}}(k)$ unless $v = d$.
-
- %% \item If instruction $I_k$ is an arithmetic instruction such as
- %% \code{addq} $s$\key{,} $d$, then add the edge $(d,v)$ for every $v \in
- %% L_{\mathsf{after}}(k)$ unless $v = d$.
- %% \item If instruction $I_k$ is of the form \key{callq}
- %% $\mathit{label}$, then add an edge $(r,v)$ for every caller-saved
- %% register $r$ and every variable $v \in L_{\mathsf{after}}(k)$.
- \end{enumerate}
- Working from the top to bottom of Figure~\ref{fig:live-eg}, we apply
- the above rules to each instruction. We highlight a few of the
- instructions. \racket{The first instruction is \lstinline{movq $1, v}
- and the live-after set is $\{\ttm{v},\ttm{rsp}\}$. Rule 1 applies,
- so \code{v} interferes with \code{rsp}.}
- %
- \python{The first instruction is \lstinline{movq $1, v} and the
- live-after set is $\{\ttm{v}\}$. Rule 1 applies but there is
- no interference because $\ttm{v}$ is the destination of the move.}
- %
- \racket{The fourth instruction is \lstinline{addq $7, x} and the
- live-after set is $\{\ttm{w},\ttm{x},\ttm{rsp}\}$. Rule 2 applies so
- $\ttm{x}$ interferes with \ttm{w} and \ttm{rsp}.}
- %
- \python{The fourth instruction is \lstinline{addq $7, x} and the
- live-after set is $\{\ttm{w},\ttm{x}\}$. Rule 2 applies so
- $\ttm{x}$ interferes with \ttm{w}.}
- %
- \racket{The next instruction is \lstinline{movq x, y} and the
- live-after set is $\{\ttm{w},\ttm{x},\ttm{y},\ttm{rsp}\}$. Rule 1
- applies, so \ttm{y} interferes with \ttm{w} and \ttm{rsp} but not
- \ttm{x} because \ttm{x} is the source of the move and therefore
- \ttm{x} and \ttm{y} hold the same value.}
- %
- \python{The next instruction is \lstinline{movq x, y} and the
- live-after set is $\{\ttm{w},\ttm{x},\ttm{y}\}$. Rule 1
- applies, so \ttm{y} interferes with \ttm{w} but not
- \ttm{x} because \ttm{x} is the source of the move and therefore
- \ttm{x} and \ttm{y} hold the same value.}
- %
- Figure~\ref{fig:interference-results} lists the interference results
- for all of the instructions and the resulting interference graph is
- shown in Figure~\ref{fig:interfere}.
- \begin{figure}[tbp]
- \begin{quote}
- {\if\edition\racketEd
- \begin{tabular}{ll}
- \lstinline!movq $1, v!& \ttm{v} interferes with \ttm{rsp},\\
- \lstinline!movq $42, w!& \ttm{w} interferes with \ttm{v} and \ttm{rsp},\\
- \lstinline!movq v, x!& \ttm{x} interferes with \ttm{w} and \ttm{rsp},\\
- \lstinline!addq $7, x!& \ttm{x} interferes with \ttm{w} and \ttm{rsp},\\
- \lstinline!movq x, y!& \ttm{y} interferes with \ttm{w} and \ttm{rsp} but not \ttm{x},\\
- \lstinline!movq x, z!& \ttm{z} interferes with \ttm{w}, \ttm{y}, and \ttm{rsp},\\
- \lstinline!addq w, z!& \ttm{z} interferes with \ttm{y} and \ttm{rsp}, \\
- \lstinline!movq y, t!& \ttm{t} interferes with \ttm{z} and \ttm{rsp}, \\
- \lstinline!negq t!& \ttm{t} interferes with \ttm{z} and \ttm{rsp}, \\
- \lstinline!movq z, %rax! & \ttm{rax} interferes with \ttm{t} and \ttm{rsp}, \\
- \lstinline!addq t, %rax! & \ttm{rax} interferes with \ttm{rsp}. \\
- \lstinline!jmp conclusion!& no interference.
- \end{tabular}
- \fi}
- {\if\edition\pythonEd
- \begin{tabular}{ll}
- \lstinline!movq $1, v!& no interference\\
- \lstinline!movq $42, w!& \ttm{w} interferes with \ttm{v}\\
- \lstinline!movq v, x!& \ttm{x} interferes with \ttm{w}\\
- \lstinline!addq $7, x!& \ttm{x} interferes with \ttm{w}\\
- \lstinline!movq x, y!& \ttm{y} interferes with \ttm{w} but not \ttm{x}\\
- \lstinline!movq x, z!& \ttm{z} interferes with \ttm{w} and \ttm{y}\\
- \lstinline!addq w, z!& \ttm{z} interferes with \ttm{y} \\
- \lstinline!movq y, tmp_0!& \ttm{t} interferes with \ttm{z} \\
- \lstinline!negq tmp_0!& \ttm{t} interferes with \ttm{z} \\
- \lstinline!movq z, tmp_1! & \ttm{tmp\_0} interferes with \ttm{tmp\_1} \\
- \lstinline!addq tmp_0, tmp_1! & no interference\\
- \lstinline!movq tmp_1, %rdi! & no interference \\
- \lstinline!callq print_int!& no interference.
- \end{tabular}
- \fi}
- \end{quote}
- \caption{Interference results for the running example.}
- \label{fig:interference-results}
- \end{figure}
- \begin{figure}[tbp]
- \large
- {\if\edition\racketEd
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (rax) at (0,0) {$\ttm{rax}$};
- \node (rsp) at (9,2) {$\ttm{rsp}$};
- \node (t1) at (0,2) {$\ttm{t}$};
- \node (z) at (3,2) {$\ttm{z}$};
- \node (x) at (6,2) {$\ttm{x}$};
- \node (y) at (3,0) {$\ttm{y}$};
- \node (w) at (6,0) {$\ttm{w}$};
- \node (v) at (9,0) {$\ttm{v}$};
- \draw (t1) to (rax);
- \draw (t1) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \draw (v) to (rsp);
- \draw (w) to (rsp);
- \draw (x) to (rsp);
- \draw (y) to (rsp);
- \path[-.,bend left=15] (z) edge node {} (rsp);
- \path[-.,bend left=10] (t1) edge node {} (rsp);
- \draw (rax) to (rsp);
- \end{tikzpicture}
- \]
- \fi}
- {\if\edition\pythonEd
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (t0) at (0,2) {$\ttm{tmp\_0}$};
- \node (t1) at (0,0) {$\ttm{tmp\_1}$};
- \node (z) at (3,2) {$\ttm{z}$};
- \node (x) at (6,2) {$\ttm{x}$};
- \node (y) at (3,0) {$\ttm{y}$};
- \node (w) at (6,0) {$\ttm{w}$};
- \node (v) at (9,0) {$\ttm{v}$};
- \draw (t0) to (t1);
- \draw (t0) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \end{tikzpicture}
- \]
- \fi}
- \caption{The interference graph of the example program.}
- \label{fig:interfere}
- \end{figure}
- %% Our next concern is to choose a data structure for representing the
- %% interference graph. There are many choices for how to represent a
- %% graph, for example, \emph{adjacency matrix}, \emph{adjacency list},
- %% and \emph{edge set}~\citep{Cormen:2001uq}. The right way to choose a
- %% data structure is to study the algorithm that uses the data structure,
- %% determine what operations need to be performed, and then choose the
- %% data structure that provide the most efficient implementations of
- %% those operations. Often times the choice of data structure can have an
- %% effect on the time complexity of the algorithm, as it does here. If
- %% you skim the next section, you will see that the register allocation
- %% algorithm needs to ask the graph for all of its vertices and, given a
- %% vertex, it needs to known all of the adjacent vertices. Thus, the
- %% correct choice of graph representation is that of an adjacency
- %% list. There are helper functions in \code{utilities.rkt} for
- %% representing graphs using the adjacency list representation:
- %% \code{make-graph}, \code{add-edge}, and \code{adjacent}
- %% (Appendix~\ref{appendix:utilities}).
- %% %
- %% \margincomment{\footnotesize To do: change to use the
- %% Racket graph library. \\ --Jeremy}
- %% %
- %% In particular, those functions use a hash table to map each vertex to
- %% the set of adjacent vertices, and the sets are represented using
- %% Racket's \key{set}, which is also a hash table.
- \begin{exercise}\normalfont
- \racket{Implement the compiler pass named \code{build\_interference} according
- to the algorithm suggested above. We recommend using the Racket
- \code{graph} package to create and inspect the interference graph.
- The output graph of this pass should be stored in the $\itm{info}$ field of
- the program, under the key \code{conflicts}.}
- %
- \python{Implement a function named \code{build\_interference}
- according to the algorithm suggested above that
- returns the interference graph.}
- \end{exercise}
-
- \section{Graph Coloring via Sudoku}
- \label{sec:graph-coloring}
- \index{subject}{graph coloring}
- \index{subject}{Sudoku}
- \index{subject}{color}
- We come to the main event, mapping variables to registers and stack
- locations. Variables that interfere with each other must be mapped to
- different locations. In terms of the interference graph, this means
- that adjacent vertices must be mapped to different locations. If we
- think of locations as colors, the register allocation problem becomes
- the graph coloring problem~\citep{Balakrishnan:1996ve,Rosen:2002bh}.
- The reader may be more familiar with the graph coloring problem than he
- or she realizes; the popular game of Sudoku is an instance of the
- graph coloring problem. The following describes how to build a graph
- out of an initial Sudoku board.
- \begin{itemize}
- \item There is one vertex in the graph for each Sudoku square.
- \item There is an edge between two vertices if the corresponding squares
- are in the same row, in the same column, or if the squares are in
- the same $3\times 3$ region.
- \item Choose nine colors to correspond to the numbers $1$ to $9$.
- \item Based on the initial assignment of numbers to squares in the
- Sudoku board, assign the corresponding colors to the corresponding
- vertices in the graph.
- \end{itemize}
- If you can color the remaining vertices in the graph with the nine
- colors, then you have also solved the corresponding game of Sudoku.
- Figure~\ref{fig:sudoku-graph} shows an initial Sudoku game board and
- the corresponding graph with colored vertices. We map the Sudoku
- number 1 to black, 2 to white, and 3 to gray. We only show edges for a
- sampling of the vertices (the colored ones) because showing edges for
- all of the vertices would make the graph unreadable.
- \begin{figure}[tbp]
- \includegraphics[width=0.45\textwidth]{figs/sudoku}
- \includegraphics[width=0.5\textwidth]{figs/sudoku-graph-bw}
- \caption{A Sudoku game board and the corresponding colored graph.}
- \label{fig:sudoku-graph}
- \end{figure}
- Some techniques for playing Sudoku correspond to heuristics used in
- graph coloring algorithms. For example, one of the basic techniques
- for Sudoku is called Pencil Marks. The idea is to use a process of
- elimination to determine what numbers are no longer available for a
- square and write down those numbers in the square (writing very
- small). For example, if the number $1$ is assigned to a square, then
- write the pencil mark $1$ in all the squares in the same row, column,
- and region to indicate that $1$ is no longer an option for those other
- squares.
- %
- The Pencil Marks technique corresponds to the notion of
- \emph{saturation}\index{subject}{saturation} due to \cite{Brelaz:1979eu}. The
- saturation of a vertex, in Sudoku terms, is the set of numbers that
- are no longer available. In graph terminology, we have the following
- definition:
- \begin{equation*}
- \mathrm{saturation}(u) = \{ c \;|\; \exists v. v \in \mathrm{adjacent}(u)
- \text{ and } \mathrm{color}(v) = c \}
- \end{equation*}
- where $\mathrm{adjacent}(u)$ is the set of vertices that share an
- edge with $u$.
- The Pencil Marks technique leads to a simple strategy for filling in
- numbers: if there is a square with only one possible number left, then
- choose that number! But what if there are no squares with only one
- possibility left? One brute-force approach is to try them all: choose
- the first one and if that ultimately leads to a solution, great. If
- not, backtrack and choose the next possibility. One good thing about
- Pencil Marks is that it reduces the degree of branching in the search
- tree. Nevertheless, backtracking can be terribly time consuming. One
- way to reduce the amount of backtracking is to use the
- most-constrained-first heuristic (aka. minimum remaining
- values)~\citep{Russell2003}. That is, when choosing a square, always
- choose one with the fewest possibilities left (the vertex with the
- highest saturation). The idea is that choosing highly constrained
- squares earlier rather than later is better because later on there may
- not be any possibilities left in the highly saturated squares.
- However, register allocation is easier than Sudoku because the
- register allocator can fall back to assigning variables to stack
- locations when the registers run out. Thus, it makes sense to replace
- backtracking with greedy search: make the best choice at the time and
- keep going. We still wish to minimize the number of colors needed, so
- we use the most-constrained-first heuristic in the greedy search.
- Figure~\ref{fig:satur-algo} gives the pseudo-code for a simple greedy
- algorithm for register allocation based on saturation and the
- most-constrained-first heuristic. It is roughly equivalent to the
- DSATUR graph coloring algorithm~\citep{Brelaz:1979eu}.
- %,Gebremedhin:1999fk,Omari:2006uq
- Just as in Sudoku, the algorithm represents colors with integers. The
- integers $0$ through $k-1$ correspond to the $k$ registers that we use
- for register allocation. The integers $k$ and larger correspond to
- stack locations. The registers that are not used for register
- allocation, such as \code{rax}, are assigned to negative integers. In
- particular, we assign $-1$ to \code{rax} and $-2$ to \code{rsp}.
- %% One might wonder why we include registers at all in the liveness
- %% analysis and interference graph. For example, we never allocate a
- %% variable to \code{rax} and \code{rsp}, so it would be harmless to
- %% leave them out. As we see in Chapter~\ref{ch:Rvec}, when we begin
- %% to use register for passing arguments to functions, it will be
- %% necessary for those registers to appear in the interference graph
- %% because those registers will also be assigned to variables, and we
- %% don't want those two uses to encroach on each other. Regarding
- %% registers such as \code{rax} and \code{rsp} that are not used for
- %% variables, we could omit them from the interference graph but that
- %% would require adding special cases to our algorithm, which would
- %% complicate the logic for little gain.
- \begin{figure}[btp]
- \centering
- \begin{lstlisting}[basicstyle=\rmfamily,deletekeywords={for,from,with,is,not,in,find},morekeywords={while},columns=fullflexible]
- Algorithm: DSATUR
- Input: a graph |$G$|
- Output: an assignment |$\mathrm{color}[v]$| for each vertex |$v \in G$|
- |$W \gets \mathrm{vertices}(G)$|
- while |$W \neq \emptyset$| do
- pick a vertex |$u$| from |$W$| with the highest saturation,
- breaking ties randomly
- find the lowest color |$c$| that is not in |$\{ \mathrm{color}[v] \;:\; v \in \mathrm{adjacent}(u)\}$|
- |$\mathrm{color}[u] \gets c$|
- |$W \gets W - \{u\}$|
- \end{lstlisting}
- \caption{The saturation-based greedy graph coloring algorithm.}
- \label{fig:satur-algo}
- \end{figure}
- {\if\edition\racketEd
- With the DSATUR algorithm in hand, let us return to the running
- example and consider how to color the interference graph in
- Figure~\ref{fig:interfere}.
- %
- We start by assigning the register nodes to their own color. For
- example, \code{rax} is assigned the color $-1$ and \code{rsp} is
- assigned $-2$. The variables are not yet colored, so they are
- annotated with a dash. We then update the saturation for vertices that
- are adjacent to a register, obtaining the following annotated
- graph. For example, the saturation for \code{t} is $\{-1,-2\}$ because
- it interferes with both \code{rax} and \code{rsp}.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (rax) at (0,0) {$\ttm{rax}:-1,\{-2\}$};
- \node (rsp) at (10,2) {$\ttm{rsp}:-2,\{-1\}$};
- \node (t1) at (0,2) {$\ttm{t}:-,\{-1,-2\}$};
- \node (z) at (3,2) {$\ttm{z}:-,\{-2\}$};
- \node (x) at (6,2) {$\ttm{x}:-,\{-2\}$};
- \node (y) at (3,0) {$\ttm{y}:-,\{-2\}$};
- \node (w) at (6,0) {$\ttm{w}:-,\{-2\}$};
- \node (v) at (10,0) {$\ttm{v}:-,\{-2\}$};
- \draw (t1) to (rax);
- \draw (t1) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \draw (v) to (rsp);
- \draw (w) to (rsp);
- \draw (x) to (rsp);
- \draw (y) to (rsp);
- \path[-.,bend left=15] (z) edge node {} (rsp);
- \path[-.,bend left=10] (t1) edge node {} (rsp);
- \draw (rax) to (rsp);
- \end{tikzpicture}
- \]
- The algorithm says to select a maximally saturated vertex. So we pick
- $\ttm{t}$ and color it with the first available integer, which is
- $0$. We mark $0$ as no longer available for $\ttm{z}$, $\ttm{rax}$,
- and \ttm{rsp} because they interfere with $\ttm{t}$.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (rax) at (0,0) {$\ttm{rax}:-1,\{0,-2\}$};
- \node (rsp) at (10,2) {$\ttm{rsp}:-2,\{-1,0\}$};
- \node (t1) at (0,2) {$\ttm{t}:0,\{-1,-2\}$};
- \node (z) at (3,2) {$\ttm{z}:-,\{0,-2\}$};
- \node (x) at (6,2) {$\ttm{x}:-,\{-2\}$};
- \node (y) at (3,0) {$\ttm{y}:-,\{-2\}$};
- \node (w) at (6,0) {$\ttm{w}:-,\{-2\}$};
- \node (v) at (10,0) {$\ttm{v}:-,\{-2\}$};
- \draw (t1) to (rax);
- \draw (t1) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \draw (v) to (rsp);
- \draw (w) to (rsp);
- \draw (x) to (rsp);
- \draw (y) to (rsp);
- \path[-.,bend left=15] (z) edge node {} (rsp);
- \path[-.,bend left=10] (t1) edge node {} (rsp);
- \draw (rax) to (rsp);
- \end{tikzpicture}
- \]
- We repeat the process, selecting a maximally saturated vertex,
- choosing is \code{z}, and color it with the first available number, which
- is $1$. We add $1$ to the saturation for the neighboring vertices
- \code{t}, \code{y}, \code{w}, and \code{rsp}.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (rax) at (0,0) {$\ttm{rax}:-1,\{0,-2\}$};
- \node (rsp) at (10,2) {$\ttm{rsp}:-2,\{-1,0,1\}$};
- \node (t1) at (0,2) {$\ttm{t}:0,\{-1,1,-2\}$};
- \node (z) at (3,2) {$\ttm{z}:1,\{0,-2\}$};
- \node (x) at (6,2) {$\ttm{x}:-,\{-2\}$};
- \node (y) at (3,0) {$\ttm{y}:-,\{1,-2\}$};
- \node (w) at (6,0) {$\ttm{w}:-,\{1,-2\}$};
- \node (v) at (10,0) {$\ttm{v}:-,\{-2\}$};
- \draw (t1) to (rax);
- \draw (t1) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \draw (v) to (rsp);
- \draw (w) to (rsp);
- \draw (x) to (rsp);
- \draw (y) to (rsp);
- \path[-.,bend left=15] (z) edge node {} (rsp);
- \path[-.,bend left=10] (t1) edge node {} (rsp);
- \draw (rax) to (rsp);
- \end{tikzpicture}
- \]
- The most saturated vertices are now \code{w} and \code{y}. We color
- \code{w} with the first available color, which is $0$.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (rax) at (0,0) {$\ttm{rax}:-1,\{0,-2\}$};
- \node (rsp) at (10,2) {$\ttm{rsp}:-2,\{-1,0,1\}$};
- \node (t1) at (0,2) {$\ttm{t}:0,\{-1,1,-2\}$};
- \node (z) at (3,2) {$\ttm{z}:1,\{0,-2\}$};
- \node (x) at (6,2) {$\ttm{x}:-,\{0,-2\}$};
- \node (y) at (3,0) {$\ttm{y}:-,\{0,1,-2\}$};
- \node (w) at (6,0) {$\ttm{w}:0,\{1,-2\}$};
- \node (v) at (10,0) {$\ttm{v}:-,\{0,-2\}$};
- \draw (t1) to (rax);
- \draw (t1) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \draw (v) to (rsp);
- \draw (w) to (rsp);
- \draw (x) to (rsp);
- \draw (y) to (rsp);
- \path[-.,bend left=15] (z) edge node {} (rsp);
- \path[-.,bend left=10] (t1) edge node {} (rsp);
- \draw (rax) to (rsp);
- \end{tikzpicture}
- \]
- Vertex \code{y} is now the most highly saturated, so we color \code{y}
- with $2$. We cannot choose $0$ or $1$ because those numbers are in
- \code{y}'s saturation set. Indeed, \code{y} interferes with \code{w}
- and \code{z}, whose colors are $0$ and $1$ respectively.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (rax) at (0,0) {$\ttm{rax}:-1,\{0,-2\}$};
- \node (rsp) at (10,2) {$\ttm{rsp}:-2,\{-1,0,1,2\}$};
- \node (t1) at (0,2) {$\ttm{t}:0,\{-1,1,-2\}$};
- \node (z) at (3,2) {$\ttm{z}:1,\{0,2,-2\}$};
- \node (x) at (6,2) {$\ttm{x}:-,\{0,-2\}$};
- \node (y) at (3,0) {$\ttm{y}:2,\{0,1,-2\}$};
- \node (w) at (6,0) {$\ttm{w}:0,\{1,2,-2\}$};
- \node (v) at (10,0) {$\ttm{v}:-,\{0,-2\}$};
- \draw (t1) to (rax);
- \draw (t1) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \draw (v) to (rsp);
- \draw (w) to (rsp);
- \draw (x) to (rsp);
- \draw (y) to (rsp);
- \path[-.,bend left=15] (z) edge node {} (rsp);
- \path[-.,bend left=10] (t1) edge node {} (rsp);
- \draw (rax) to (rsp);
- \end{tikzpicture}
- \]
- Now \code{x} and \code{v} are the most saturated, so we color \code{v} with $1$.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (rax) at (0,0) {$\ttm{rax}:-1,\{0,-2\}$};
- \node (rsp) at (10,2) {$\ttm{rsp}:-2,\{-1,0,1,2\}$};
- \node (t1) at (0,2) {$\ttm{t}:0,\{-1,1,-2\}$};
- \node (z) at (3,2) {$\ttm{z}:1,\{0,2,-2\}$};
- \node (x) at (6,2) {$\ttm{x}:-,\{0,-2\}$};
- \node (y) at (3,0) {$\ttm{y}:2,\{0,1,-2\}$};
- \node (w) at (6,0) {$\ttm{w}:0,\{1,2,-2\}$};
- \node (v) at (10,0) {$\ttm{v}:1,\{0,-2\}$};
- \draw (t1) to (rax);
- \draw (t1) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \draw (v) to (rsp);
- \draw (w) to (rsp);
- \draw (x) to (rsp);
- \draw (y) to (rsp);
- \path[-.,bend left=15] (z) edge node {} (rsp);
- \path[-.,bend left=10] (t1) edge node {} (rsp);
- \draw (rax) to (rsp);
- \end{tikzpicture}
- \]
- In the last step of the algorithm, we color \code{x} with $1$.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (rax) at (0,0) {$\ttm{rax}:-1,\{0,-2\}$};
- \node (rsp) at (10,2) {$\ttm{rsp}:-2,\{-1,0,1,2\}$};
- \node (t1) at (0,2) {$\ttm{t}:0,\{-1,1,-2\}$};
- \node (z) at (3,2) {$\ttm{z}:1,\{0,2,-2\}$};
- \node (x) at (6,2) {$\ttm{x}:1,\{0,-2\}$};
- \node (y) at (3,0) {$\ttm{y}:2,\{0,1,-2\}$};
- \node (w) at (6,0) {$\ttm{w}:0,\{1,2,-2\}$};
- \node (v) at (10,0) {$\ttm{v}:1,\{0,-2\}$};
- \draw (t1) to (rax);
- \draw (t1) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \draw (v) to (rsp);
- \draw (w) to (rsp);
- \draw (x) to (rsp);
- \draw (y) to (rsp);
- \path[-.,bend left=15] (z) edge node {} (rsp);
- \path[-.,bend left=10] (t1) edge node {} (rsp);
- \draw (rax) to (rsp);
- \end{tikzpicture}
- \]
- So we obtain the following coloring:
- \[
- \{
- \ttm{rax} \mapsto -1,
- \ttm{rsp} \mapsto -2,
- \ttm{t} \mapsto 0,
- \ttm{z} \mapsto 1,
- \ttm{x} \mapsto 1,
- \ttm{y} \mapsto 2,
- \ttm{w} \mapsto 0,
- \ttm{v} \mapsto 1
- \}
- \]
- \fi}
- %
- {\if\edition\pythonEd
- %
- With the DSATUR algorithm in hand, let us return to the running
- example and consider how to color the interference graph in
- Figure~\ref{fig:interfere}. We annotate each variable node with a dash
- to indicate that it has not yet been assigned a color. The saturation
- sets are also shown for each node; all of them start as the empty set.
- (We do not include the register nodes in the graph below because there
- were no interference edges involving registers in this program, but in
- general there can be.)
- %
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (t0) at (0,2) {$\ttm{tmp\_0}: -, \{\}$};
- \node (t1) at (0,0) {$\ttm{tmp\_1}: -, \{\}$};
- \node (z) at (3,2) {$\ttm{z}: -, \{\}$};
- \node (x) at (6,2) {$\ttm{x}: -, \{\}$};
- \node (y) at (3,0) {$\ttm{y}: -, \{\}$};
- \node (w) at (6,0) {$\ttm{w}: -, \{\}$};
- \node (v) at (9,0) {$\ttm{v}: -, \{\}$};
- \draw (t0) to (t1);
- \draw (t0) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \end{tikzpicture}
- \]
- The algorithm says to select a maximally saturated vertex, but they
- are all equally saturated. So we flip a coin and pick $\ttm{tmp\_0}$
- then color it with the first available integer, which is $0$. We mark
- $0$ as no longer available for $\ttm{tmp\_1}$ and $\ttm{z}$ because
- they interfere with $\ttm{tmp\_0}$.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (t0) at (0,2) {$\ttm{tmp\_0}: 0, \{\}$};
- \node (t1) at (0,0) {$\ttm{tmp\_1}: -, \{0\}$};
- \node (z) at (3,2) {$\ttm{z}: -, \{0\}$};
- \node (x) at (6,2) {$\ttm{x}: -, \{\}$};
- \node (y) at (3,0) {$\ttm{y}: -, \{\}$};
- \node (w) at (6,0) {$\ttm{w}: -, \{\}$};
- \node (v) at (9,0) {$\ttm{v}: -, \{\}$};
- \draw (t0) to (t1);
- \draw (t0) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \end{tikzpicture}
- \]
- We repeat the process. The most saturated vertices are \code{z} and
- \code{tmp\_1}, so we choose \code{z} and color it with the first
- available number, which is $1$. We add $1$ to the saturation for the
- neighboring vertices \code{tmp\_0}, \code{y}, and \code{w}.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (t0) at (0,2) {$\ttm{tmp\_0}: 0, \{1\}$};
- \node (t1) at (0,0) {$\ttm{tmp\_1}: -, \{0\}$};
- \node (z) at (3,2) {$\ttm{z}: 1, \{0\}$};
- \node (x) at (6,2) {$\ttm{x}: -, \{\}$};
- \node (y) at (3,0) {$\ttm{y}: -, \{1\}$};
- \node (w) at (6,0) {$\ttm{w}: -, \{1\}$};
- \node (v) at (9,0) {$\ttm{v}: -, \{\}$};
- \draw (t0) to (t1);
- \draw (t0) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \end{tikzpicture}
- \]
- The most saturated vertices are now \code{tmp\_1}, \code{w}, and
- \code{y}. We color \code{w} with the first available color, which
- is $0$.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (t0) at (0,2) {$\ttm{tmp\_0}: 0, \{1\}$};
- \node (t1) at (0,0) {$\ttm{tmp\_1}: -, \{0\}$};
- \node (z) at (3,2) {$\ttm{z}: 1, \{0\}$};
- \node (x) at (6,2) {$\ttm{x}: -, \{0\}$};
- \node (y) at (3,0) {$\ttm{y}: -, \{0,1\}$};
- \node (w) at (6,0) {$\ttm{w}: 0, \{1\}$};
- \node (v) at (9,0) {$\ttm{v}: -, \{0\}$};
- \draw (t0) to (t1);
- \draw (t0) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \end{tikzpicture}
- \]
- Now \code{y} is the most saturated, so we color it with $2$.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (t0) at (0,2) {$\ttm{tmp\_0}: 0, \{1\}$};
- \node (t1) at (0,0) {$\ttm{tmp\_1}: -, \{0\}$};
- \node (z) at (3,2) {$\ttm{z}: 1, \{0,2\}$};
- \node (x) at (6,2) {$\ttm{x}: -, \{0\}$};
- \node (y) at (3,0) {$\ttm{y}: 2, \{0,1\}$};
- \node (w) at (6,0) {$\ttm{w}: 0, \{1,2\}$};
- \node (v) at (9,0) {$\ttm{v}: -, \{0\}$};
- \draw (t0) to (t1);
- \draw (t0) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \end{tikzpicture}
- \]
- The most saturated vertices are \code{tmp\_1}, \code{x}, and \code{v}.
- We choose to color \code{v} with $1$.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (t0) at (0,2) {$\ttm{tmp\_0}: 0, \{1\}$};
- \node (t1) at (0,0) {$\ttm{tmp\_1}: -, \{0\}$};
- \node (z) at (3,2) {$\ttm{z}: 1, \{0,2\}$};
- \node (x) at (6,2) {$\ttm{x}: -, \{0\}$};
- \node (y) at (3,0) {$\ttm{y}: 2, \{0,1\}$};
- \node (w) at (6,0) {$\ttm{w}: 0, \{1,2\}$};
- \node (v) at (9,0) {$\ttm{v}: 1, \{0\}$};
- \draw (t0) to (t1);
- \draw (t0) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \end{tikzpicture}
- \]
- We color the remaining two variables, \code{tmp\_1} and \code{x}, with $1$.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (t0) at (0,2) {$\ttm{tmp\_0}: 0, \{1\}$};
- \node (t1) at (0,0) {$\ttm{tmp\_1}: 1, \{0\}$};
- \node (z) at (3,2) {$\ttm{z}: 1, \{0,2\}$};
- \node (x) at (6,2) {$\ttm{x}: 1, \{0\}$};
- \node (y) at (3,0) {$\ttm{y}: 2, \{0,1\}$};
- \node (w) at (6,0) {$\ttm{w}: 0, \{1,2\}$};
- \node (v) at (9,0) {$\ttm{v}: 1, \{0\}$};
- \draw (t0) to (t1);
- \draw (t0) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \end{tikzpicture}
- \]
- So we obtain the following coloring:
- \[
- \{ \ttm{tmp\_0} \mapsto 0,
- \ttm{tmp\_1} \mapsto 1,
- \ttm{z} \mapsto 1,
- \ttm{x} \mapsto 1,
- \ttm{y} \mapsto 2,
- \ttm{w} \mapsto 0,
- \ttm{v} \mapsto 1 \}
- \]
- \fi}
- We recommend creating an auxiliary function named \code{color\_graph}
- that takes an interference graph and a list of all the variables in
- the program. This function should return a mapping of variables to
- their colors (represented as natural numbers). By creating this helper
- function, you will be able to reuse it in Chapter~\ref{ch:Rfun}
- when we add support for functions.
- To prioritize the processing of highly saturated nodes inside the
- \code{color\_graph} function, we recommend using the priority queue
- data structure \racket{described in Figure~\ref{fig:priority-queue}}\python{in the file \code{priority\_queue.py} of the support code}. \racket{In
- addition, you will need to maintain a mapping from variables to their
- ``handles'' in the priority queue so that you can notify the priority
- queue when their saturation changes.}
- {\if\edition\racketEd
- \begin{figure}[tp]
- %\begin{wrapfigure}[25]{r}[0.75in]{0.55\textwidth}
- \small
- \begin{tcolorbox}[title=Priority Queue]
- A \emph{priority queue} is a collection of items in which the
- removal of items is governed by priority. In a ``min'' queue,
- lower priority items are removed first. An implementation is in
- \code{priority\_queue.rkt} of the support code. \index{subject}{priority
- queue} \index{subject}{minimum priority queue}
- \begin{description}
- \item[$\LP\code{make-pqueue}\,\itm{cmp}\RP$] constructs an empty
- priority queue that uses the $\itm{cmp}$ predicate to determine
- whether its first argument has lower or equal priority to its
- second argument.
- \item[$\LP\code{pqueue-count}\,\itm{queue}\RP$] returns the number of
- items in the queue.
- \item[$\LP\code{pqueue-push!}\,\itm{queue}\,\itm{item}\RP$] inserts
- the item into the queue and returns a handle for the item in the
- queue.
- \item[$\LP\code{pqueue-pop!}\,\itm{queue}\RP$] returns the item with
- the lowest priority.
- \item[$\LP\code{pqueue-decrease-key!}\,\itm{queue}\,\itm{handle}\RP$]
- notifies the queue that the priority has decreased for the item
- associated with the given handle.
- \end{description}
- \end{tcolorbox}
- %\end{wrapfigure}
- \caption{The priority queue data structure.}
- \label{fig:priority-queue}
- \end{figure}
- \fi}
- With the coloring complete, we finalize the assignment of variables to
- registers and stack locations. We map the first $k$ colors to the $k$
- registers and the rest of the colors to stack locations. Suppose for
- the moment that we have just one register to use for register
- allocation, \key{rcx}. Then we have the following map from colors to
- locations.
- \[
- \{ 0 \mapsto \key{\%rcx}, \; 1 \mapsto \key{-8(\%rbp)}, \; 2 \mapsto \key{-16(\%rbp)} \}
- \]
- Composing this mapping with the coloring, we arrive at the following
- assignment of variables to locations.
- {\if\edition\racketEd
- \begin{gather*}
- \{ \ttm{v} \mapsto \key{-8(\%rbp)}, \,
- \ttm{w} \mapsto \key{\%rcx}, \,
- \ttm{x} \mapsto \key{-8(\%rbp)}, \,
- \ttm{y} \mapsto \key{-16(\%rbp)}, \\
- \ttm{z} \mapsto \key{-8(\%rbp)}, \,
- \ttm{t} \mapsto \key{\%rcx} \}
- \end{gather*}
- \fi}
- {\if\edition\pythonEd
- \begin{gather*}
- \{ \ttm{v} \mapsto \key{-8(\%rbp)}, \,
- \ttm{w} \mapsto \key{\%rcx}, \,
- \ttm{x} \mapsto \key{-8(\%rbp)}, \,
- \ttm{y} \mapsto \key{-16(\%rbp)}, \\
- \ttm{z} \mapsto \key{-8(\%rbp)}, \,
- \ttm{tmp\_0} \mapsto \key{\%rcx}, \,
- \ttm{tmp\_1} \mapsto \key{-8(\%rbp)} \}
- \end{gather*}
- \fi}
- Adapt the code from the \code{assign\_homes} pass
- (Section~\ref{sec:assign-Lvar}) to replace the variables with their
- assigned location. Applying the above assignment to our running
- example, on the left, yields the program on the right.
- % why frame size of 32? -JGS
- \begin{center}
- {\if\edition\racketEd
- \begin{minipage}{0.3\textwidth}
- \begin{lstlisting}
- movq $1, v
- movq $42, w
- movq v, x
- addq $7, x
- movq x, y
- movq x, z
- addq w, z
- movq y, t
- negq t
- movq z, %rax
- addq t, %rax
- jmp conclusion
- \end{lstlisting}
- \end{minipage}
- $\Rightarrow\qquad$
- \begin{minipage}{0.45\textwidth}
- \begin{lstlisting}
- movq $1, -8(%rbp)
- movq $42, %rcx
- movq -8(%rbp), -8(%rbp)
- addq $7, -8(%rbp)
- movq -8(%rbp), -16(%rbp)
- movq -8(%rbp), -8(%rbp)
- addq %rcx, -8(%rbp)
- movq -16(%rbp), %rcx
- negq %rcx
- movq -8(%rbp), %rax
- addq %rcx, %rax
- jmp conclusion
- \end{lstlisting}
- \end{minipage}
- \fi}
- {\if\edition\pythonEd
- \begin{minipage}{0.3\textwidth}
- \begin{lstlisting}
- movq $1, v
- movq $42, w
- movq v, x
- addq $7, x
- movq x, y
- movq x, z
- addq w, z
- movq y, tmp_0
- negq tmp_0
- movq z, tmp_1
- addq tmp_0, tmp_1
- movq tmp_1, %rdi
- callq print_int
- \end{lstlisting}
- \end{minipage}
- $\Rightarrow\qquad$
- \begin{minipage}{0.45\textwidth}
- \begin{lstlisting}
- movq $1, -8(%rbp)
- movq $42, %rcx
- movq -8(%rbp), -8(%rbp)
- addq $7, -8(%rbp)
- movq -8(%rbp), -16(%rbp)
- movq -8(%rbp), -8(%rbp)
- addq %rcx, -8(%rbp)
- movq -16(%rbp), %rcx
- negq %rcx
- movq -8(%rbp), -8(%rbp)
- addq %rcx, -8(%rbp)
- movq -8(%rbp), %rdi
- callq print_int
- \end{lstlisting}
- \end{minipage}
- \fi}
- \end{center}
- \begin{exercise}\normalfont
- %
- Implement the compiler pass \code{allocate\_registers}.
- %
- Create five programs that exercise all aspects of the register
- allocation algorithm, including spilling variables to the stack.
- %
- \racket{Replace \code{assign\_homes} in the list of \code{passes} in the
- \code{run-tests.rkt} script with the three new passes:
- \code{uncover\_live}, \code{build\_interference}, and
- \code{allocate\_registers}.
- %
- Temporarily remove the \code{print\_x86} pass from the list of passes
- and the call to \code{compiler-tests}.
- Run the script to test the register allocator.
- }
- %
- \python{Run the \code{run-tests.py} script to to check whether the
- output programs produce the same result as the input programs.}
- \end{exercise}
- \section{Patch Instructions}
- \label{sec:patch-instructions}
- The remaining step in the compilation to x86 is to ensure that the
- instructions have at most one argument that is a memory access.
- %
- In the running example, the instruction \code{movq -8(\%rbp),
- -16(\%rbp)} is problematic. Recall from Section~\ref{sec:patch-s0}
- that the fix is to first move \code{-8(\%rbp)} into \code{rax} and
- then move \code{rax} into \code{-16(\%rbp)}.
- %
- The moves from \code{-8(\%rbp)} to \code{-8(\%rbp)} are also
- problematic, but they can simply be deleted. In general, we recommend
- deleting all the trivial moves whose source and destination are the
- same location.
- %
- The following is the output of \code{patch\_instructions} on the
- running example.
- \begin{center}
- {\if\edition\racketEd
- \begin{minipage}{0.4\textwidth}
- \begin{lstlisting}
- movq $1, -8(%rbp)
- movq $42, %rcx
- movq -8(%rbp), -8(%rbp)
- addq $7, -8(%rbp)
- movq -8(%rbp), -16(%rbp)
- movq -8(%rbp), -8(%rbp)
- addq %rcx, -8(%rbp)
- movq -16(%rbp), %rcx
- negq %rcx
- movq -8(%rbp), %rax
- addq %rcx, %rax
- jmp conclusion
- \end{lstlisting}
- \end{minipage}
- $\Rightarrow\qquad$
- \begin{minipage}{0.45\textwidth}
- \begin{lstlisting}
- movq $1, -8(%rbp)
- movq $42, %rcx
- addq $7, -8(%rbp)
- movq -8(%rbp), %rax
- movq %rax, -16(%rbp)
- addq %rcx, -8(%rbp)
- movq -16(%rbp), %rcx
- negq %rcx
- movq -8(%rbp), %rax
- addq %rcx, %rax
- jmp conclusion
- \end{lstlisting}
- \end{minipage}
- \fi}
- {\if\edition\pythonEd
- \begin{minipage}{0.4\textwidth}
- \begin{lstlisting}
- movq $1, -8(%rbp)
- movq $42, %rcx
- movq -8(%rbp), -8(%rbp)
- addq $7, -8(%rbp)
- movq -8(%rbp), -16(%rbp)
- movq -8(%rbp), -8(%rbp)
- addq %rcx, -8(%rbp)
- movq -16(%rbp), %rcx
- negq %rcx
- movq -8(%rbp), -8(%rbp)
- addq %rcx, -8(%rbp)
- movq -8(%rbp), %rdi
- callq print_int
- \end{lstlisting}
- \end{minipage}
- $\Rightarrow\qquad$
- \begin{minipage}{0.45\textwidth}
- \begin{lstlisting}
- movq $1, -8(%rbp)
- movq $42, %rcx
- addq $7, -8(%rbp)
- movq -8(%rbp), %rax
- movq %rax, -16(%rbp)
- addq %rcx, -8(%rbp)
- movq -16(%rbp), %rcx
- negq %rcx
- addq %rcx, -8(%rbp)
- movq -8(%rbp), %rdi
- callq print_int
- \end{lstlisting}
- \end{minipage}
- \fi}
- \end{center}
- \begin{exercise}\normalfont
- %
- Update the \code{patch\_instructions} compiler pass to delete trivial moves.
- %
- %Insert it after \code{allocate\_registers} in the list of \code{passes}
- %in the \code{run-tests.rkt} script.
- %
- Run the script to test the \code{patch\_instructions} pass.
- \end{exercise}
- \section{Print x86}
- \label{sec:print-x86-reg-alloc}
- \index{subject}{calling conventions}
- \index{subject}{prelude}\index{subject}{conclusion}
- Recall that the \code{print\_x86} pass generates the prelude and
- conclusion instructions to satisfy the x86 calling conventions
- (Section~\ref{sec:calling-conventions}). With the addition of the
- register allocator, the callee-saved registers used by the register
- allocator must be saved in the prelude and restored in the conclusion.
- In the \code{allocate\_registers} pass,
- %
- \racket{add an entry to the \itm{info}
- of \code{X86Program} named \code{used\_callee}}
- %
- \python{add a field named \code{used\_callee} to the \code{X86Program} AST node}
- %
- that stores the set of
- callee-saved registers that were assigned to variables. The
- \code{print\_x86} pass can then access this information to decide which
- callee-saved registers need to be saved and restored.
- %
- When calculating the size of the frame to adjust the \code{rsp} in the
- prelude, make sure to take into account the space used for saving the
- callee-saved registers. Also, don't forget that the frame needs to be
- a multiple of 16 bytes!
- \racket{An overview of all of the passes involved in register
- allocation is shown in Figure~\ref{fig:reg-alloc-passes}.}
- {\if\edition\racketEd
- \begin{figure}[tbp]
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (Lvar) at (0,2) {\large \LangVar{}};
- \node (Lvar-2) at (3,2) {\large \LangVar{}};
- \node (Lvar-3) at (6,2) {\large \LangVar{}};
- \node (Cvar-1) at (3,0) {\large \LangCVar{}};
- \node (x86-2) at (3,-2) {\large \LangXVar{}};
- \node (x86-3) at (6,-2) {\large \LangXVar{}};
- \node (x86-4) at (9,-2) {\large \LangXInt{}};
- \node (x86-5) at (9,-4) {\large \LangXInt{}};
- \node (x86-2-1) at (3,-4) {\large \LangXVar{}};
- \node (x86-2-2) at (6,-4) {\large \LangXVar{}};
- \path[->,bend left=15] (Lvar) edge [above] node {\ttfamily\footnotesize uniquify} (Lvar-2);
- \path[->,bend left=15] (Lvar-2) edge [above] node {\ttfamily\footnotesize remove\_complex.} (Lvar-3);
- \path[->,bend left=15] (Lvar-3) edge [right] node {\ttfamily\footnotesize explicate\_control} (Cvar-1);
- \path[->,bend right=15] (Cvar-1) edge [left] node {\ttfamily\footnotesize select\_instr.} (x86-2);
- \path[->,bend left=15] (x86-2) edge [right] node {\ttfamily\footnotesize uncover\_live} (x86-2-1);
- \path[->,bend right=15] (x86-2-1) edge [below] node {\ttfamily\footnotesize build\_inter.} (x86-2-2);
- \path[->,bend right=15] (x86-2-2) edge [right] node {\ttfamily\footnotesize allocate\_reg.} (x86-3);
- \path[->,bend left=15] (x86-3) edge [above] node {\ttfamily\footnotesize patch\_instr.} (x86-4);
- \path[->,bend left=15] (x86-4) edge [right] node {\ttfamily\footnotesize print\_x86} (x86-5);
- \end{tikzpicture}
- \caption{Diagram of the passes for \LangVar{} with register allocation.}
- \label{fig:reg-alloc-passes}
- \end{figure}
- \fi}
- Figure~\ref{fig:running-example-x86} shows the x86 code generated for
- the running example (Figure~\ref{fig:reg-eg}). To demonstrate both the
- use of registers and the stack, we limit the register allocator for
- this example to use just two registers: \code{rbx} and \code{rcx}. In
- the prelude\index{subject}{prelude} of the \code{main} function, we
- push \code{rbx} onto the stack because it is a callee-saved register
- and it was assigned to variable by the register allocator. We
- subtract \code{8} from the \code{rsp} at the end of the prelude to
- reserve space for the one spilled variable. After that subtraction,
- the \code{rsp} is aligned to 16 bytes.
- Moving on to the program proper, we see how the registers were
- allocated.
- %
- \racket{Variables \code{v}, \code{x}, and \code{y} were assigned to
- \code{rbx} and variable \code{z} was assigned to \code{rcx}.}
- %
- \python{Variables \code{v}, \code{x}, \code{y}, and \code{tmp\_0}
- were assigned to \code{rcx} and variables \code{w} and \code{tmp\_1}
- were assigned to \code{rbx}.}
- %
- Variable \racket{\code{w}}\python{\code{z}} was spilled to the stack
- location \code{-16(\%rbp)}. Recall that the prelude saved the
- callee-save register \code{rbx} onto the stack. The spilled variables
- must be placed lower on the stack than the saved callee-save
- registers, so in this case \racket{\code{w}}\python{z} is placed at
- \code{-16(\%rbp)}.
- In the conclusion\index{subject}{conclusion}, we undo the work that was
- done in the prelude. We move the stack pointer up by \code{8} bytes
- (the room for spilled variables), then we pop the old values of
- \code{rbx} and \code{rbp} (callee-saved registers), and finish with
- \code{retq} to return control to the operating system.
-
- \begin{figure}[tbp]
- % var_test_28.rkt
- % (use-minimal-set-of-registers! #t)
- % and only rbx rcx
- % tmp 0 rbx
- % z 1 rcx
- % y 0 rbx
- % w 2 16(%rbp)
- % v 0 rbx
- % x 0 rbx
- {\if\edition\racketEd
- \begin{lstlisting}
- start:
- movq $1, %rbx
- movq $42, -16(%rbp)
- addq $7, %rbx
- movq %rbx, %rcx
- addq -16(%rbp), %rcx
- negq %rbx
- movq %rcx, %rax
- addq %rbx, %rax
- jmp conclusion
- .globl main
- main:
- pushq %rbp
- movq %rsp, %rbp
- pushq %rbx
- subq $8, %rsp
- jmp start
-
- conclusion:
- addq $8, %rsp
- popq %rbx
- popq %rbp
- retq
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- %{v: %rcx, x: %rcx, z: -16(%rbp), w: %rbx, tmp_1: %rbx, y: %rcx, tmp_0: %rcx}
- \begin{lstlisting}
- .globl main
- main:
- pushq %rbp
- movq %rsp, %rbp
- pushq %rbx
- subq $8, %rsp
- movq $1, %rcx
- movq $42, %rbx
- addq $7, %rcx
- movq %rcx, -16(%rbp)
- addq %rbx, -16(%rbp)
- negq %rcx
- movq -16(%rbp), %rbx
- addq %rcx, %rbx
- movq %rbx, %rdi
- callq print_int
- addq $8, %rsp
- popq %rbx
- popq %rbp
- retq
- \end{lstlisting}
- \fi}
- \caption{The x86 output from the running example
- (Figure~\ref{fig:reg-eg}), limiting allocation to just \code{rbx}
- and \code{rcx}.}
- \label{fig:running-example-x86}
- \end{figure}
- \begin{exercise}\normalfont
- Update the \code{print\_x86} pass as described in this section.
- %
- \racket{
- In the \code{run-tests.rkt} script, reinstate \code{print\_x86} in the
- list of passes and the call to \code{compiler-tests}.}
- %
- Run the script to test the complete compiler for \LangVar{} that
- performs register allocation.
- \end{exercise}
- \section{Challenge: Move Biasing}
- \label{sec:move-biasing}
- \index{subject}{move biasing}
- This section describes an enhancement to the register allocator,
- called move biasing, for students who are looking for an extra
- challenge.
- {\if\edition\racketEd
- To motivate the need for move biasing we return to the running example
- but this time use all of the general purpose registers. So we have
- the following mapping of color numbers to registers.
- \[
- \{ 0 \mapsto \key{\%rcx}, \; 1 \mapsto \key{\%rdx}, \; 2 \mapsto \key{\%rsi} \}
- \]
- Using the same assignment of variables to color numbers that was
- produced by the register allocator described in the last section, we
- get the following program.
- \begin{center}
- \begin{minipage}{0.3\textwidth}
- \begin{lstlisting}
- movq $1, v
- movq $42, w
- movq v, x
- addq $7, x
- movq x, y
- movq x, z
- addq w, z
- movq y, t
- negq t
- movq z, %rax
- addq t, %rax
- jmp conclusion
- \end{lstlisting}
- \end{minipage}
- $\Rightarrow\qquad$
- \begin{minipage}{0.45\textwidth}
- \begin{lstlisting}
- movq $1, %rdx
- movq $42, %rcx
- movq %rdx, %rdx
- addq $7, %rdx
- movq %rdx, %rsi
- movq %rdx, %rdx
- addq %rcx, %rdx
- movq %rsi, %rcx
- negq %rcx
- movq %rdx, %rax
- addq %rcx, %rax
- jmp conclusion
- \end{lstlisting}
- \end{minipage}
- \end{center}
- In the above output code there are two \key{movq} instructions that
- can be removed because their source and target are the same. However,
- if we had put \key{t}, \key{v}, \key{x}, and \key{y} into the same
- register, we could instead remove three \key{movq} instructions. We
- can accomplish this by taking into account which variables appear in
- \key{movq} instructions with which other variables.
- \fi}
- {\if\edition\pythonEd
- %
- To motivate the need for move biasing we return to the running example
- and recall that in Section~\ref{sec:patch-instructions} we were able to
- remove three trivial move instructions from the running
- example. However, we could remove another trivial move if we were able
- to allocate \code{y} and \code{tmp\_0} to the same register. \fi}
- We say that two variables $p$ and $q$ are \emph{move
- related}\index{subject}{move related} if they participate together in
- a \key{movq} instruction, that is, \key{movq} $p$\key{,} $q$ or
- \key{movq} $q$\key{,} $p$. When deciding which variable to color next,
- when there are multiple variables with the same saturation, prefer
- variables that can be assigned to a color that is the same as the
- color of a move related variable. Furthermore, when the register
- allocator chooses a color for a variable, it should prefer a color
- that has already been used for a move-related variable (assuming that
- they do not interfere). Of course, this preference should not override
- the preference for registers over stack locations. So this preference
- should be used as a tie breaker when choosing between registers or
- when choosing between stack locations.
- We recommend representing the move relationships in a graph, similar
- to how we represented interference. The following is the \emph{move
- graph} for our running example.
- {\if\edition\racketEd
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (rax) at (0,0) {$\ttm{rax}$};
- \node (rsp) at (9,2) {$\ttm{rsp}$};
- \node (t) at (0,2) {$\ttm{t}$};
- \node (z) at (3,2) {$\ttm{z}$};
- \node (x) at (6,2) {$\ttm{x}$};
- \node (y) at (3,0) {$\ttm{y}$};
- \node (w) at (6,0) {$\ttm{w}$};
- \node (v) at (9,0) {$\ttm{v}$};
- \draw (v) to (x);
- \draw (x) to (y);
- \draw (x) to (z);
- \draw (y) to (t);
- \end{tikzpicture}
- \]
- \fi}
- %
- {\if\edition\pythonEd
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (t0) at (0,2) {$\ttm{tmp\_0}$};
- \node (t1) at (0,0) {$\ttm{tmp\_1}$};
- \node (z) at (3,2) {$\ttm{z}$};
- \node (x) at (6,2) {$\ttm{x}$};
- \node (y) at (3,0) {$\ttm{y}$};
- \node (w) at (6,0) {$\ttm{w}$};
- \node (v) at (9,0) {$\ttm{v}$};
- \draw (y) to (t0);
- \draw (z) to (x);
- \draw (z) to (t1);
- \draw (x) to (y);
- \draw (x) to (v);
- \end{tikzpicture}
- \]
- \fi}
- {\if\edition\racketEd
- Now we replay the graph coloring, pausing to see the coloring of
- \code{y}. Recall the following configuration. The most saturated vertices
- were \code{w} and \code{y}.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (rax) at (0,0) {$\ttm{rax}:-1,\{0,-2\}$};
- \node (rsp) at (9,2) {$\ttm{rsp}:-2,\{-1,0,1,2\}$};
- \node (t1) at (0,2) {$\ttm{t}:0,\{1,-2\}$};
- \node (z) at (3,2) {$\ttm{z}:1,\{0,-2\}$};
- \node (x) at (6,2) {$\ttm{x}:-,\{-2\}$};
- \node (y) at (3,0) {$\ttm{y}:-,\{1,-2\}$};
- \node (w) at (6,0) {$\ttm{w}:-,\{1,-2\}$};
- \node (v) at (9,0) {$\ttm{v}:-,\{-2\}$};
- \draw (t1) to (rax);
- \draw (t1) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \draw (v) to (rsp);
- \draw (w) to (rsp);
- \draw (x) to (rsp);
- \draw (y) to (rsp);
- \path[-.,bend left=15] (z) edge node {} (rsp);
- \path[-.,bend left=10] (t1) edge node {} (rsp);
- \draw (rax) to (rsp);
- \end{tikzpicture}
- \]
- %
- Last time we chose to color \code{w} with $0$. But this time we see
- that \code{w} is not move related to any vertex, but \code{y} is move
- related to \code{t}. So we choose to color \code{y} the same color as
- \code{t}, $0$.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (rax) at (0,0) {$\ttm{rax}:-1,\{0,-2\}$};
- \node (rsp) at (9,2) {$\ttm{rsp}:-2,\{-1,0,1,2\}$};
- \node (t1) at (0,2) {$\ttm{t}:0,\{1,-2\}$};
- \node (z) at (3,2) {$\ttm{z}:1,\{0,-2\}$};
- \node (x) at (6,2) {$\ttm{x}:-,\{-2\}$};
- \node (y) at (3,0) {$\ttm{y}:0,\{1,-2\}$};
- \node (w) at (6,0) {$\ttm{w}:-,\{0,1,-2\}$};
- \node (v) at (9,0) {$\ttm{v}:-,\{-2\}$};
- \draw (t1) to (rax);
- \draw (t1) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \draw (v) to (rsp);
- \draw (w) to (rsp);
- \draw (x) to (rsp);
- \draw (y) to (rsp);
- \path[-.,bend left=15] (z) edge node {} (rsp);
- \path[-.,bend left=10] (t1) edge node {} (rsp);
- \draw (rax) to (rsp);
- \end{tikzpicture}
- \]
- Now \code{w} is the most saturated, so we color it $2$.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (rax) at (0,0) {$\ttm{rax}:-1,\{0,-2\}$};
- \node (rsp) at (9,2) {$\ttm{rsp}:-2,\{-1,0,1,2\}$};
- \node (t1) at (0,2) {$\ttm{t}:0,\{1,-2\}$};
- \node (z) at (3,2) {$\ttm{z}:1,\{0,2,-2\}$};
- \node (x) at (6,2) {$\ttm{x}:-,\{2,-2\}$};
- \node (y) at (3,0) {$\ttm{y}:0,\{1,2,-2\}$};
- \node (w) at (6,0) {$\ttm{w}:2,\{0,1,-2\}$};
- \node (v) at (9,0) {$\ttm{v}:-,\{2,-2\}$};
- \draw (t1) to (rax);
- \draw (t1) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \draw (v) to (rsp);
- \draw (w) to (rsp);
- \draw (x) to (rsp);
- \draw (y) to (rsp);
- \path[-.,bend left=15] (z) edge node {} (rsp);
- \path[-.,bend left=10] (t1) edge node {} (rsp);
- \draw (rax) to (rsp);
- \end{tikzpicture}
- \]
- At this point, vertices \code{x} and \code{v} are most saturated, but
- \code{x} is move related to \code{y} and \code{z}, so we color
- \code{x} to $0$ to match \code{y}. Finally, we color \code{v} to $0$.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (rax) at (0,0) {$\ttm{rax}:-1,\{0,-2\}$};
- \node (rsp) at (9,2) {$\ttm{rsp}:-2,\{-1,0,1,2\}$};
- \node (t) at (0,2) {$\ttm{t}:0,\{1,-2\}$};
- \node (z) at (3,2) {$\ttm{z}:1,\{0,2,-2\}$};
- \node (x) at (6,2) {$\ttm{x}:0,\{2,-2\}$};
- \node (y) at (3,0) {$\ttm{y}:0,\{1,2,-2\}$};
- \node (w) at (6,0) {$\ttm{w}:2,\{0,1,-2\}$};
- \node (v) at (9,0) {$\ttm{v}:0,\{2,-2\}$};
- \draw (t1) to (rax);
- \draw (t) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \draw (v) to (rsp);
- \draw (w) to (rsp);
- \draw (x) to (rsp);
- \draw (y) to (rsp);
- \path[-.,bend left=15] (z) edge node {} (rsp);
- \path[-.,bend left=10] (t1) edge node {} (rsp);
- \draw (rax) to (rsp);
- \end{tikzpicture}
- \]
- \fi}
- %
- {\if\edition\pythonEd
- Now we replay the graph coloring, pausing before the coloring of
- \code{w}. Recall the following configuration. The most saturated vertices
- were \code{tmp\_1}, \code{w}, and \code{y}.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (t0) at (0,2) {$\ttm{tmp\_0}: 0, \{1\}$};
- \node (t1) at (0,0) {$\ttm{tmp\_1}: -, \{0\}$};
- \node (z) at (3,2) {$\ttm{z}: 1, \{0\}$};
- \node (x) at (6,2) {$\ttm{x}: -, \{\}$};
- \node (y) at (3,0) {$\ttm{y}: -, \{1\}$};
- \node (w) at (6,0) {$\ttm{w}: -, \{1\}$};
- \node (v) at (9,0) {$\ttm{v}: -, \{\}$};
- \draw (t0) to (t1);
- \draw (t0) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \end{tikzpicture}
- \]
- We have arbitrarily chosen to color \code{w} instead of \code{tmp\_1}
- or \code{y}, but note that \code{w} is not move related to any
- variables, whereas \code{y} and \code{tmp\_1} are move related to
- \code{tmp\_0} and \code{z}, respectively. If we instead choose
- \code{y} and color it $0$, we can delete another move instruction.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (t0) at (0,2) {$\ttm{tmp\_0}: 0, \{1\}$};
- \node (t1) at (0,0) {$\ttm{tmp\_1}: -, \{0\}$};
- \node (z) at (3,2) {$\ttm{z}: 1, \{0\}$};
- \node (x) at (6,2) {$\ttm{x}: -, \{\}$};
- \node (y) at (3,0) {$\ttm{y}: 0, \{1\}$};
- \node (w) at (6,0) {$\ttm{w}: -, \{0,1\}$};
- \node (v) at (9,0) {$\ttm{v}: -, \{\}$};
- \draw (t0) to (t1);
- \draw (t0) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \end{tikzpicture}
- \]
- Now \code{w} is the most saturated, so we color it $2$.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (t0) at (0,2) {$\ttm{tmp\_0}: 0, \{1\}$};
- \node (t1) at (0,0) {$\ttm{tmp\_1}: -, \{0\}$};
- \node (z) at (3,2) {$\ttm{z}: 1, \{0\}$};
- \node (x) at (6,2) {$\ttm{x}: -, \{2\}$};
- \node (y) at (3,0) {$\ttm{y}: 0, \{1,2\}$};
- \node (w) at (6,0) {$\ttm{w}: 2, \{0,1\}$};
- \node (v) at (9,0) {$\ttm{v}: -, \{2\}$};
- \draw (t0) to (t1);
- \draw (t0) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \end{tikzpicture}
- \]
- To finish the coloring, \code{x} and \code{v} get $0$ and
- \code{tmp\_1} gets $1$.
- \[
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (t0) at (0,2) {$\ttm{tmp\_0}: 0, \{1\}$};
- \node (t1) at (0,0) {$\ttm{tmp\_1}: 1, \{0\}$};
- \node (z) at (3,2) {$\ttm{z}: 1, \{0\}$};
- \node (x) at (6,2) {$\ttm{x}: 0, \{2\}$};
- \node (y) at (3,0) {$\ttm{y}: 0, \{1,2\}$};
- \node (w) at (6,0) {$\ttm{w}: 2, \{0,1\}$};
- \node (v) at (9,0) {$\ttm{v}: 0, \{2\}$};
- \draw (t0) to (t1);
- \draw (t0) to (z);
- \draw (z) to (y);
- \draw (z) to (w);
- \draw (x) to (w);
- \draw (y) to (w);
- \draw (v) to (w);
- \end{tikzpicture}
- \]
- \fi}
- So we have the following assignment of variables to registers.
- {\if\edition\racketEd
- \begin{gather*}
- \{ \ttm{v} \mapsto \key{\%rcx}, \,
- \ttm{w} \mapsto \key{\%rsi}, \,
- \ttm{x} \mapsto \key{\%rcx}, \,
- \ttm{y} \mapsto \key{\%rcx}, \,
- \ttm{z} \mapsto \key{\%rdx}, \,
- \ttm{t} \mapsto \key{\%rcx} \}
- \end{gather*}
- \fi}
- {\if\edition\pythonEd
- \begin{gather*}
- \{ \ttm{v} \mapsto \key{\%rcx}, \,
- \ttm{w} \mapsto \key{-16(\%rbp)}, \,
- \ttm{x} \mapsto \key{\%rcx}, \,
- \ttm{y} \mapsto \key{\%rcx}, \\
- \ttm{z} \mapsto \key{-8(\%rbp)}, \,
- \ttm{tmp\_0} \mapsto \key{\%rcx}, \,
- \ttm{tmp\_1} \mapsto \key{-8(\%rbp)} \}
- \end{gather*}
- \fi}
- We apply this register assignment to the running example, on the left,
- to obtain the code in the middle. The \code{patch\_instructions} then
- deletes the trivial moves to obtain the code on the right.
- {\if\edition\racketEd
- \begin{minipage}{0.25\textwidth}
- \begin{lstlisting}
- movq $1, v
- movq $42, w
- movq v, x
- addq $7, x
- movq x, y
- movq x, z
- addq w, z
- movq y, t
- negq t
- movq z, %rax
- addq t, %rax
- jmp conclusion
- \end{lstlisting}
- \end{minipage}
- $\Rightarrow\qquad$
- \begin{minipage}{0.25\textwidth}
- \begin{lstlisting}
- movq $1, %rcx
- movq $42, %rsi
- movq %rcx, %rcx
- addq $7, %rcx
- movq %rcx, %rcx
- movq %rcx, %rdx
- addq %rsi, %rdx
- movq %rcx, %rcx
- negq %rcx
- movq %rdx, %rax
- addq %rcx, %rax
- jmp conclusion
- \end{lstlisting}
- \end{minipage}
- $\Rightarrow\qquad$
- \begin{minipage}{0.25\textwidth}
- \begin{lstlisting}
- movq $1, %rcx
- movq $42, %rsi
- addq $7, %rcx
- movq %rcx, %rdx
- addq %rsi, %rdx
- negq %rcx
- movq %rdx, %rax
- addq %rcx, %rax
- jmp conclusion
- \end{lstlisting}
- \end{minipage}
- \fi}
- {\if\edition\pythonEd
- \begin{minipage}{0.20\textwidth}
- \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
- movq $1, v
- movq $42, w
- movq v, x
- addq $7, x
- movq x, y
- movq x, z
- addq w, z
- movq y, tmp_0
- negq tmp_0
- movq z, tmp_1
- addq tmp_0, tmp_1
- movq tmp_1, %rdi
- callq _print_int
- \end{lstlisting}
- \end{minipage}
- ${\Rightarrow\qquad}$
- \begin{minipage}{0.30\textwidth}
- \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
- movq $1, %rcx
- movq $42, -16(%rbp)
- movq %rcx, %rcx
- addq $7, %rcx
- movq %rcx, %rcx
- movq %rcx, -8(%rbp)
- addq -16(%rbp), -8(%rbp)
- movq %rcx, %rcx
- negq %rcx
- movq -8(%rbp), -8(%rbp)
- addq %rcx, -8(%rbp)
- movq -8(%rbp), %rdi
- callq _print_int
- \end{lstlisting}
- \end{minipage}
- ${\Rightarrow\qquad}$
- \begin{minipage}{0.20\textwidth}
- \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
- movq $1, %rcx
- movq $42, -16(%rbp)
- addq $7, %rcx
- movq %rcx, -8(%rbp)
- movq -16(%rbp), %rax
- addq %rax, -8(%rbp)
- negq %rcx
- addq %rcx, -8(%rbp)
- movq -8(%rbp), %rdi
- callq print_int
- \end{lstlisting}
- \end{minipage}
- \fi}
- \begin{exercise}\normalfont
- Change your implementation of \code{allocate\_registers} to take move
- biasing into account. Create two new tests that include at least one
- opportunity for move biasing and visually inspect the output x86
- programs to make sure that your move biasing is working properly. Make
- sure that your compiler still passes all of the tests.
- \end{exercise}
- %To do: another neat challenge would be to do
- % live range splitting~\citep{Cooper:1998ly}. \\ --Jeremy
- %% \subsection{Output of the Running Example}
- %% \label{sec:reg-alloc-output}
- % challenge: prioritize variables based on execution frequencies
- % and the number of uses of a variable
- % challenge: enhance the coloring algorithm using Chaitin's
- % approach of prioritizing high-degree variables
- % by removing low-degree variables (coloring them later)
- % from the interference graph
- \section{Further Reading}
- \label{sec:register-allocation-further-reading}
- Early register allocation algorithms were developed for Fortran
- compilers in the 1950s~\citep{Horwitz:1966aa,Backus:1978aa}. The use
- of graph coloring began in the late 1970s and early 1980s with the
- work of \citet{Chaitin:1981vl} on an optimizing compiler for PL/I. The
- algorithm is based on the following observation of
- \citet{Kempe:1879aa}. If a graph $G$ has a vertex $v$ with degree
- lower than $k$, then $G$ is $k$ colorable if the subgraph of $G$ with
- $v$ removed is also $k$ colorable. To see why, suppose that the
- subgraph is $k$ colorable. At worst the neighbors of $v$ are assigned
- different colors, but since there are less than $k$ neighbors, there
- will be one or more colors left over to use for coloring $v$ in $G$.
- The algorithm of \citet{Chaitin:1981vl} removes a vertex $v$ of degree
- less than $k$ from the graph and recursively colors the rest of the
- graph. Upon returning from the recursion, it colors $v$ with one of
- the available colors and returns. \citet{Chaitin:1982vn} augments
- this algorithm to handle spilling as follows. If there are no vertices
- of degree lower than $k$ then pick a vertex at random, spill it,
- remove it from the graph, and proceed recursively to color the rest of
- the graph.
- Prior to coloring, \citet{Chaitin:1981vl} merge variables that are
- move-related and that don't interfere with each other, a process
- called \emph{coalescing}. While coalescing decreases the number of
- moves, it can make the graph more difficult to
- color. \citet{Briggs:1994kx} propose \emph{conservative coalescing} in
- which two variables are merged only if they have fewer than $k$
- neighbors of high degree. \citet{George:1996aa} observe that
- conservative coalescing is sometimes too conservative and make it more
- aggressive by iterating the coalescing with the removal of low-degree
- vertices.
- %
- Attacking the problem from a different angle, \citet{Briggs:1994kx}
- also propose \emph{biased coloring} in which a variable is assigned to
- the same color as another move-related variable if possible, as
- discussed in Section~\ref{sec:move-biasing}.
- %
- The algorithm of \citet{Chaitin:1981vl} and its successors iteratively
- performs coalescing, graph coloring, and spill code insertion until
- all variables have been assigned a location.
- \citet{Briggs:1994kx} observes that \citet{Chaitin:1982vn} sometimes
- spills variables that don't have to be: a high-degree variable can be
- colorable if many of its neighbors are assigned the same color.
- \citet{Briggs:1994kx} propose \emph{optimistic coloring}, in which a
- high-degree vertex is not immediately spilled. Instead the decision is
- deferred until after the recursive call, at which point it is apparent
- whether there is actually an available color or not. We observe that
- this algorithm is equivalent to the smallest-last ordering
- algorithm~\citep{Matula:1972aa} if one takes the first $k$ colors to
- be registers and the rest to be stack locations.
- %% biased coloring
- Earlier editions of the compiler course at Indiana University
- \citep{Dybvig:2010aa} were based on the algorithm of
- \citet{Briggs:1994kx}.
- The smallest-last ordering algorithm is one of many \emph{greedy}
- coloring algorithms. A greedy coloring algorithm visits all the
- vertices in a particular order and assigns each one the first
- available color. An \emph{offline} greedy algorithm chooses the
- ordering up-front, prior to assigning colors. The algorithm of
- \citet{Chaitin:1981vl} should be considered offline because the vertex
- ordering does not depend on the colors assigned. Other orderings are
- possible. For example, \citet{Chow:1984ys} order variables according
- to an estimate of runtime cost.
- An \emph{online} greedy coloring algorithm uses information about the
- current assignment of colors to influence the order in which the
- remaining vertices are colored. The saturation-based algorithm
- described in this chapter is one such algorithm. We choose to use
- saturation-based coloring because it is fun to introduce graph
- coloring via Sudoku!
- A register allocator may choose to map each variable to just one
- location, as in \citet{Chaitin:1981vl}, or it may choose to map a
- variable to one or more locations. The later can be achieved by
- \emph{live range splitting}, where a variable is replaced by several
- variables that each handle part of its live
- range~\citep{Chow:1984ys,Briggs:1994kx,Cooper:1998ly}.
- %% 1950s, Sheldon Best, Fortran \cite{Backus:1978aa}, Belady's page
- %% replacement algorithm, bottom-up local
- %% \citep{Horwitz:1966aa} straight-line programs, single basic block,
- %% Cooper: top-down (priority bassed), bottom-up
- %% top-down
- %% order variables by priority (estimated cost)
- %% caveat: split variables into two groups:
- %% constrained (>k neighbors) and unconstrained (<k neighbors)
- %% color the constrained ones first
- %% \citet{Schwartz:1975aa} graph-coloring, no spill
- %% cite J. Cocke for an algorithm that colors variables
- %% in a high-degree first ordering
- %Register Allocation via Usage Counts, Freiburghouse CACM
- \citet{Palsberg:2007si} observe that many of the interference graphs
- that arise from Java programs in the JoeQ compiler are \emph{chordal},
- that is, every cycle with four or more edges has an edge which is not
- part of the cycle but which connects two vertices on the cycle. Such
- graphs can be optimally colored by the greedy algorithm with a vertex
- ordering determined by maximum cardinality search.
- In situations where compile time is of utmost importance, such as in
- just-in-time compilers, graph coloring algorithms can be too expensive
- and the linear scan algorithm of \citet{Poletto:1999uq} may be more
- appropriate.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- \chapter{Booleans and Conditionals}
- \label{ch:Lif}
- \index{subject}{Boolean}
- \index{subject}{control flow}
- \index{subject}{conditional expression}
- The \LangInt{} and \LangVar{} languages only have a single kind of
- value, the integers. In this chapter we add a second kind of value,
- the Booleans, to create the \LangIf{} language. The Boolean values
- \emph{true} and \emph{false} are written \TRUE{} and \FALSE{}
- respectively in \racket{Racket}\python{Python}. The \LangIf{}
- language includes several operations that involve Booleans (\key{and},
- \key{not}, \racket{\key{eq?}}\python{==}, \key{<}, etc.) and the
- \key{if} expression \python{and statement}. With the addition of
- \key{if}, programs can have non-trivial control flow which
- %
- \racket{impacts \code{explicate\_control} and liveness analysis}
- %
- \python{impacts liveness analysis and motivates a new pass named
- \code{explicate\_control}}.
- %
- Also, because we now have two kinds of values, we need to handle
- programs that apply an operation to the wrong kind of value, such as
- \racket{\code{(not 1)}}\python{\code{not 1}}.
- There are two language design options for such situations. One option
- is to signal an error and the other is to provide a wider
- interpretation of the operation. \racket{The Racket
- language}\python{Python} uses a mixture of these two options,
- depending on the operation and the kind of value. For example, the
- result of \racket{\code{(not 1)}}\python{\code{not 1}} is
- \racket{\code{\#f}}\python{False} because \racket{Racket}\python{Python}
- treats non-zero integers as if they were \racket{\code{\#t}}\python{\code{True}}.
- %
- \racket{On the other hand, \code{(car 1)} results in a run-time error
- in Racket because \code{car} expects a pair.}
- %
- \python{On the other hand, \code{1[0]} results in a run-time error
- in Python because an ``\code{int} object is not subscriptable''.}
- \racket{Typed Racket}\python{The MyPy type checker} makes similar
- design choices as \racket{Racket}\python{Python}, except much of the
- error detection happens at compile time instead of run
- time\python{~\citep{Lehtosalo2021:MyPy}}. \racket{Typed Racket}\python{MyPy}
- accepts \racket{\code{(not 1)}}\python{\code{not 1}}. But in the case
- of \racket{\code{(car 1)}}\python{\code{1[0]}}, \racket{Typed
- Racket}\python{MyPy} reports a compile-time error
- %
- \racket{because Racket expects the type of the argument to be of the form
- \code{(Listof T)} or \code{(Pairof T1 T2)}.}
- %
- \python{stating that a ``value of type \code{int} is not indexable''.}
- The \LangIf{} language performs type checking during compilation like
- \racket{Typed Racket}\python{MyPy}. In Chapter~\ref{ch:Rdyn} we study the
- alternative choice, that is, a dynamically typed language like
- \racket{Racket}\python{Python}.
- The \LangIf{} language is a subset of \racket{Typed Racket}\python{MyPy};
- for some operations we are more restrictive, for example, rejecting
- \racket{\code{(not 1)}}\python{\code{not 1}}.
- This chapter is organized as follows. We begin by defining the syntax
- and interpreter for the \LangIf{} language
- (Section~\ref{sec:lang-if}). We then introduce the idea of type
- checking and define a type checker for \LangIf{}
- (Section~\ref{sec:type-check-Lif}).
- %
- \racket{To compile \LangIf{} we need to enlarge the intermediate
- language \LangCVar{} into \LangCIf{} (Section~\ref{sec:Cif}) and
- \LangXInt{} into \LangXIf{} (Section~\ref{sec:x86-if}).}
- %
- The remaining sections of this chapter discuss how the addition of
- Booleans and conditional control flow to the language requires changes
- to the existing compiler passes and the addition of new ones. In
- particular, we introduce the \code{shrink} pass to translates some
- operators into others, thereby reducing the number of operators that
- need to be handled in later passes.
- %
- The main event of this chapter is the \code{explicate\_control} pass
- that is responsible for translating \code{if}'s into conditional
- \code{goto}'s (Section~\ref{sec:explicate-control-Lif}).
- %
- Regarding register allocation, there is the interesting question of
- how to handle conditional \code{goto}'s during liveness analysis.
- \section{The \LangIf{} Language}
- \label{sec:lang-if}
- The concrete syntax of the \LangIf{} language is defined in
- Figure~\ref{fig:Lif-concrete-syntax} and the abstract syntax is defined
- in Figure~\ref{fig:Lif-syntax}. The \LangIf{} language includes all of
- \LangVar{}\racket{(shown in gray)}, the Boolean literals \TRUE{} and
- \FALSE{}, and the \code{if} expression \python{and statement}. We expand the
- operators to include
- \begin{enumerate}
- \item subtraction on integers,
- \item the logical operators \key{and}, \key{or} and \key{not},
- \item the \racket{\key{eq?} operation}\python{\key{==} and \key{!=} operations}
- for comparing integers or Booleans for equality, and
- \item the \key{<}, \key{<=}, \key{>}, and \key{>=} operations for
- comparing integers.
- \end{enumerate}
- \racket{We reorganize the abstract syntax for the primitive
- operations in Figure~\ref{fig:Lif-syntax}, using only one grammar
- rule for all of them. This means that the grammar no longer checks
- whether the arity of an operators matches the number of
- arguments. That responsibility is moved to the type checker for
- \LangIf{}, which we introduce in Section~\ref{sec:type-check-Lif}.}
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- {\if\edition\racketEd
- \[
- \begin{array}{lcl}
- \itm{bool} &::=& \TRUE \MID \FALSE \\
- \itm{cmp} &::= & \key{eq?} \MID \key{<} \MID \key{<=} \MID \key{>} \MID \key{>=} \\
- \Exp &::=& \gray{ \Int \MID \CREAD{} \MID \CNEG{\Exp} \MID \CADD{\Exp}{\Exp} } \MID \CSUB{\Exp}{\Exp} \\
- &\MID& \gray{ \Var \MID \CLET{\Var}{\Exp}{\Exp} } \\
- &\MID& \itm{bool}
- \MID (\key{and}\;\Exp\;\Exp) \MID (\key{or}\;\Exp\;\Exp)
- \MID (\key{not}\;\Exp) \\
- &\MID& (\itm{cmp}\;\Exp\;\Exp) \MID \CIF{\Exp}{\Exp}{\Exp} \\
- \LangIfM{} &::=& \Exp
- \end{array}
- \]
- \fi}
- {\if\edition\pythonEd
- \[
- \begin{array}{rcl}
- \itm{binop} &::= & \key{+} \MID \key{-} \MID \key{==} \MID \key{!=} \MID \key{<} \MID \key{<=} \MID \key{>} \MID \key{>=} \\
- \itm{uniop} &::= & \key{-} \MID \key{not} \\
- \Exp &::=& \Int \MID \key{input\_int}\LP\RP \MID \CUNIOP{\itm{uniop}}{\Exp} \MID \CBINOP{\itm{binop}}{\Exp}{\Exp} \MID \Var{} \\
- &\MID& \TRUE \MID \FALSE \MID \CIF{\Exp}{\Exp}{\Exp} \\
- \Stmt &::=& \key{print}\LP \Exp \RP \MID \Exp \MID \CASSIGN{\Var}{\Exp}
- \MID \key{if}~ \Exp \key{:}~ \Stmt^{+} ~\key{else:}~ \Stmt^{+}\\
- \LangVarM{} &::=& \Stmt^{*}
- \end{array}
- \]
- \fi}
- \end{minipage}
- }
- \caption{The concrete syntax of \LangIf{}, extending \LangVar{}
- (Figure~\ref{fig:Lvar-concrete-syntax}) with Booleans and conditionals.}
- \label{fig:Lif-concrete-syntax}
- \end{figure}
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- {\if\edition\racketEd
- \[
- \begin{array}{lcl}
- \itm{bool} &::=& \code{\#t} \MID \code{\#f} \\
- \itm{cmp} &::= & \code{eq?} \MID \code{<} \MID \code{<=} \MID \code{>} \MID \code{>=} \\
- \itm{op} &::= & \itm{cmp} \MID \code{read} \MID \code{+} \MID \code{-}
- \MID \code{and} \MID \code{or} \MID \code{not} \\
- \Exp &::=& \gray{ \INT{\Int} \MID \VAR{\Var} \MID \LET{\Var}{\Exp}{\Exp} } \\
- &\MID& \PRIM{\itm{op}}{\Exp\ldots}\\
- &\MID& \BOOL{\itm{bool}} \MID \IF{\Exp}{\Exp}{\Exp} \\
- \LangIfM{} &::=& \PROGRAM{\code{'()}}{\Exp}
- \end{array}
- \]
- \fi}
- {\if\edition\pythonEd
- \[
- \begin{array}{lcl}
- \itm{binop} &::=& \code{Add()} \MID \code{Sub()} \\
- \itm{uniop} &::=& \code{USub()} \MID \code{Not()} \\
- \itm{bool} &::=& \code{True} \MID \code{False} \\
- \itm{boolop} &::=& \code{And()} \MID \code{Or()} \\
- \itm{cmp} &::= & \code{Eq()} \MID \code{NotEq()} \MID \code{Lt()} \MID \code{LtE()} \MID \code{Gt()} \MID \code{GtE()} \\
- \Exp &::=& \INT{\Int} \MID \READ{} \MID \VAR{\Var} \\
- &\MID& \BINOP{\Exp}{\itm{binop}}{\Exp}
- \MID \UNIOP{\itm{uniop}}{\Exp}\\
- &\MID& \CMP{\Exp}{\itm{cmp}}{\Exp}
- \MID \BOOLOP{\itm{boolop}}{\Exp}{\Exp}\\
- &\MID& \BOOL{\itm{bool}} \MID \IF{\Exp}{\Exp}{\Exp} \\
- \Stmt{} &::=& \PRINT{\Exp} \MID \EXPR{\Exp} \\
- &\MID& \ASSIGN{\VAR{\Var}}{\Exp} \MID \IFSTMT{\Exp}{\Stmt^{*}}{\Stmt^{*}}\\
- \LangIfM{} &::=& \PROGRAM{\code{'()}}{\Stmt^{*}}
- \end{array}
- \]
- \fi}
- \end{minipage}
- }
- \caption{The abstract syntax of \LangIf{}.}
- \label{fig:Lif-syntax}
- \end{figure}
- Figure~\ref{fig:interp-Lif} defines the interpreter for \LangIf{},
- which inherits from the interpreter for \LangVar{}
- (Figure~\ref{fig:interp-Lvar}). The literals \TRUE{} and \FALSE{}
- evaluate to the corresponding Boolean values. The conditional
- expression $(\CIF{e_1}{e_2}{\itm{e_3}})$ evaluates expression $e_1$
- and then either evaluates $e_2$ or $e_3$ depending on whether
- $e_1$ produced \TRUE{} or \FALSE{}. The logical operations
- \code{and}, \code{or}, and \code{not} behave as you might expect, but
- note that the \code{and} and \code{or} operations are
- short-circuiting.
- %
- That is, given the expression $\CAND{e_1}{e_2}$, the expression $e_2$
- is not evaluated if $e_1$ evaluates to \FALSE{}.
- %
- Similarly, given $\COR{e_1}{e_2}$, the expression $e_2$ is not
- evaluated if $e_1$ evaluates to \TRUE{}.
- \racket{With the increase in the number of primitive operations, the
- interpreter would become repetitive without some care. We refactor
- the case for \code{Prim}, moving the code that differs with each
- operation into the \code{interp\_op} method shown in in
- Figure~\ref{fig:interp-op-Lif}. We handle the \code{and} operation
- separately because of its short-circuiting behavior.}
- \begin{figure}[tbp]
- {\if\edition\racketEd
- \begin{lstlisting}
- (define interp_Lif_class
- (class interp_Lvar_class
- (super-new)
- (define/public (interp_op op) ...)
- (define/override ((interp_exp env) e)
- (define recur (interp_exp env))
- (match e
- [(Bool b) b]
- [(If cnd thn els)
- (match (recur cnd)
- [#t (recur thn)]
- [#f (recur els)])]
- [(Prim 'and (list e1 e2))
- (match (recur e1)
- [#t (match (recur e2) [#t #t] [#f #f])]
- [#f #f])]
- [(Prim op args)
- (apply (interp_op op) (for/list ([e args]) (recur e)))]
- [else ((super interp_exp env) e)]))
- ))
- (define (interp_Lif p)
- (send (new interp_Lif_class) interp_program p))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- class InterpLif(InterpLvar):
- def interp_exp(self, e, env):
- match e:
- case IfExp(test, body, orelse):
- if self.interp_exp(test, env):
- return self.interp_exp(body, env)
- else:
- return self.interp_exp(orelse, env)
- case BinOp(left, Sub(), right):
- return self.interp_exp(left, env) - self.interp_exp(right, env)
- case UnaryOp(Not(), v):
- return not self.interp_exp(v, env)
- case BoolOp(And(), values):
- if self.interp_exp(values[0], env):
- return self.interp_exp(values[1], env)
- else:
- return False
- case BoolOp(Or(), values):
- if self.interp_exp(values[0], env):
- return True
- else:
- return self.interp_exp(values[1], env)
- case Compare(left, [cmp], [right]):
- l = self.interp_exp(left, env)
- r = self.interp_exp(right, env)
- return self.interp_cmp(cmp)(l, r)
- case _:
- return super().interp_exp(e, env)
- def interp_stmts(self, ss, env):
- if len(ss) == 0:
- return
- match ss[0]:
- case If(test, body, orelse):
- if self.interp_exp(test, env):
- return self.interp_stmts(body + ss[1:], env)
- else:
- return self.interp_stmts(orelse + ss[1:], env)
- case _:
- return super().interp_stmts(ss, env)
- ...
- \end{lstlisting}
- \fi}
- \caption{Interpreter for the \LangIf{} language. \racket{(See
- Figure~\ref{fig:interp-op-Lif} for \code{interp-op}.)}
- \python{(See Figure~\ref{fig:interp-cmp-Lif} for \code{interp\_cmp}.)}}
- \label{fig:interp-Lif}
- \end{figure}
- {\if\edition\racketEd
- \begin{figure}[tbp]
- \begin{lstlisting}
- (define/public (interp_op op)
- (match op
- ['+ fx+]
- ['- fx-]
- ['read read-fixnum]
- ['not (lambda (v) (match v [#t #f] [#f #t]))]
- ['or (lambda (v1 v2)
- (cond [(and (boolean? v1) (boolean? v2))
- (or v1 v2)]))]
- ['eq? (lambda (v1 v2)
- (cond [(or (and (fixnum? v1) (fixnum? v2))
- (and (boolean? v1) (boolean? v2))
- (and (vector? v1) (vector? v2)))
- (eq? v1 v2)]))]
- ['< (lambda (v1 v2)
- (cond [(and (fixnum? v1) (fixnum? v2))
- (< v1 v2)]))]
- ['<= (lambda (v1 v2)
- (cond [(and (fixnum? v1) (fixnum? v2))
- (<= v1 v2)]))]
- ['> (lambda (v1 v2)
- (cond [(and (fixnum? v1) (fixnum? v2))
- (> v1 v2)]))]
- ['>= (lambda (v1 v2)
- (cond [(and (fixnum? v1) (fixnum? v2))
- (>= v1 v2)]))]
- [else (error 'interp_op "unknown operator")]))
- \end{lstlisting}
- \caption{Interpreter for the primitive operators in the \LangIf{} language.}
- \label{fig:interp-op-Lif}
- \end{figure}
- \fi}
- {\if\edition\pythonEd
- \begin{figure}
- \begin{lstlisting}
- class InterpLif(InterpLvar):
- ...
- def interp_cmp(self, cmp):
- match cmp:
- case Lt():
- return lambda x, y: x < y
- case LtE():
- return lambda x, y: x <= y
- case Gt():
- return lambda x, y: x > y
- case GtE():
- return lambda x, y: x >= y
- case Eq():
- return lambda x, y: x == y
- case NotEq():
- return lambda x, y: x != y
- \end{lstlisting}
- \caption{Interpreter for the comparison operators in the \LangIf{} language.}
- \label{fig:interp-cmp-Lif}
- \end{figure}
- \fi}
- \section{Type Checking \LangIf{} Programs}
- \label{sec:type-check-Lif}
- \index{subject}{type checking}
- \index{subject}{semantic analysis}
- It is helpful to think about type checking in two complementary
- ways. A type checker predicts the type of value that will be produced
- by each expression in the program. For \LangIf{}, we have just two types,
- \INTTY{} and \BOOLTY{}. So a type checker should predict that
- {\if\edition\racketEd
- \begin{lstlisting}
- (+ 10 (- (+ 12 20)))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- 10 + -(12 + 20)
- \end{lstlisting}
- \fi}
- \noindent produces a value of type \INTTY{} while
- {\if\edition\racketEd
- \begin{lstlisting}
- (and (not #f) #t)
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- (not False) and True
- \end{lstlisting}
- \fi}
- \noindent produces a value of type \BOOLTY{}.
- A second way to think about type checking is that it enforces a set of
- rules about which operators can be applied to which kinds of
- values. For example, our type checker for \LangIf{} signals an error
- for the below expression {\if\edition\racketEd
- \begin{lstlisting}
- (not (+ 10 (- (+ 12 20))))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- not (10 + -(12 + 20))
- \end{lstlisting}
- \fi}
- The subexpression
- \racket{\code{(+ 10 (- (+ 12 20)))}}\python{\code{(10 + -(12 + 20))}}
- has type \INTTY{} but the type checker enforces the rule that the argument of
- \code{not} must be an expression of type \BOOLTY{}.
- We implement type checking using classes and methods because they
- provide the open recursion needed to reuse code as we extend the type
- checker in later chapters, analogous to the use of classes and methods
- for the interpreters (Section~\ref{sec:extensible-interp}).
- We separate the type checker for the \LangVar{} subset into its own
- class, shown in Figure~\ref{fig:type-check-Lvar}. The type checker for
- \LangIf{} is shown in Figure~\ref{fig:type-check-Lif} and it inherits
- from the type checker for \LangVar{}. These type checkers are in the
- files
- \racket{\code{type-check-Lvar.rkt}}\python{\code{type\_check\_Lvar.py}}
- and
- \racket{\code{type-check-Lif.rkt}}\python{\code{type\_check\_Lif.py}}
- of the support code.
- %
- Each type checker is a structurally recursive function over the AST.
- Given an input expression \code{e}, the type checker either signals an
- error or returns \racket{an expression and} its type (\INTTY{} or
- \BOOLTY{}).
- %
- \racket{It returns an expression because there are situations in which
- we want to change or update the expression.}
- Next we discuss the \code{type\_check\_exp} function of \LangVar{} in
- Figure~\ref{fig:type-check-Lvar}. The type of an integer constant is
- \INTTY{}. To handle variables, the type checker uses the environment
- \code{env} to map variables to types.
- %
- \racket{Consider the case for \key{let}. We type check the
- initializing expression to obtain its type \key{T} and then
- associate type \code{T} with the variable \code{x} in the
- environment used to type check the body of the \key{let}. Thus,
- when the type checker encounters a use of variable \code{x}, it can
- find its type in the environment.}
- %
- \python{Consider the case for assignment. We type check the
- initializing expression to obtain its type \key{t}. If the variable
- \code{lhs.id} is already in the environment because there was a
- prior assignment, we check that this initializer has the same type
- as the prior one. If this is the first assignment to the variable,
- we associate type \code{t} with the variable \code{lhs.id} in the
- environment. Thus, when the type checker encounters a use of
- variable \code{x}, it can find its type in the environment.}
- %
- \racket{Regarding primitive operators, we recursively analyze the
- arguments and then invoke \code{type\_check\_op} to check whether
- the argument types are allowed.}
- %
- \python{Regarding addition and negation, we recursively analyze the
- arguments, check that they have type \INT{}, and return \INT{}.}
- \racket{Several auxiliary methods are used in the type checker. The
- method \code{operator-types} defines a dictionary that maps the
- operator names to their parameter and return types. The
- \code{type-equal?} method determines whether two types are equal,
- which for now simply dispatches to \code{equal?} (deep
- equality). The \code{check-type-equal?} method triggers an error if
- the two types are not equal. The \code{type-check-op} method looks
- up the operator in the \code{operator-types} dictionary and then
- checks whether the argument types are equal to the parameter types.
- The result is the return type of the operator.}
- %
- \python{The auxiliary method \code{check\_type\_equal} method triggers
- an error if the two types are not equal.}
- \begin{figure}[tbp]
- {\if\edition\racketEd
- \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
- (define type-check-Lvar_class
- (class object%
- (super-new)
- (define/public (operator-types)
- '((+ . ((Integer Integer) . Integer))
- (- . ((Integer) . Integer))
- (read . (() . Integer))))
- (define/public (type-equal? t1 t2) (equal? t1 t2))
- (define/public (check-type-equal? t1 t2 e)
- (unless (type-equal? t1 t2)
- (error 'type-check "~a != ~a\nin ~v" t1 t2 e)))
- (define/public (type-check-op op arg-types e)
- (match (dict-ref (operator-types) op)
- [`(,param-types . ,return-type)
- (for ([at arg-types] [pt param-types])
- (check-type-equal? at pt e))
- return-type]
- [else (error 'type-check-op "unrecognized ~a" op)]))
- (define/public (type-check-exp env)
- (lambda (e)
- (match e
- [(Int n) (values (Int n) 'Integer)]
- [(Var x) (values (Var x) (dict-ref env x))]
- [(Let x e body)
- (define-values (e^ Te) ((type-check-exp env) e))
- (define-values (b Tb) ((type-check-exp (dict-set env x Te)) body))
- (values (Let x e^ b) Tb)]
- [(Prim op es)
- (define-values (new-es ts)
- (for/lists (exprs types) ([e es]) ((type-check-exp env) e)))
- (values (Prim op new-es) (type-check-op op ts e))]
- [else (error 'type-check-exp "couldn't match" e)])))
- (define/public (type-check-program e)
- (match e
- [(Program info body)
- (define-values (body^ Tb) ((type-check-exp '()) body))
- (check-type-equal? Tb 'Integer body)
- (Program info body^)]
- [else (error 'type-check-Lvar "couldn't match ~a" e)]))
- ))
- (define (type-check-Lvar p)
- (send (new type-check-Lvar_class) type-check-program p))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- class TypeCheckLvar:
- def check_type_equal(self, t1, t2, e):
- if t1 != t2:
- msg = 'error: ' + repr(t1) + ' != ' + repr(t2) + ' in ' + repr(e)
- raise Exception(msg)
-
- def type_check_exp(self, e, env):
- match e:
- case BinOp(left, Add(), right):
- l = self.type_check_exp(left, env)
- check_type_equal(l, int, left)
- r = self.type_check_exp(right, env)
- check_type_equal(r, int, right)
- return int
- case UnaryOp(USub(), v):
- t = self.type_check_exp(v, env)
- check_type_equal(t, int, v)
- return int
- case Name(id):
- return env[id]
- case Constant(value) if isinstance(value, int):
- return int
- case Call(Name('input_int'), []):
- return int
- def type_check_stmts(self, ss, env):
- if len(ss) == 0:
- return
- match ss[0]:
- case Assign([lhs], value):
- t = self.type_check_exp(value, env)
- if lhs.id in env:
- check_type_equal(env[lhs.id], t, value)
- else:
- env[lhs.id] = t
- return self.type_check_stmts(ss[1:], env)
- case Expr(Call(Name('print'), [arg])):
- t = self.type_check_exp(arg, env)
- check_type_equal(t, int, arg)
- return self.type_check_stmts(ss[1:], env)
- case Expr(value):
- self.type_check_exp(value, env)
- return self.type_check_stmts(ss[1:], env)
- def type_check_P(self, p):
- match p:
- case Module(body):
- self.type_check_stmts(body, {})
- \end{lstlisting}
- \fi}
- \caption{Type checker for the \LangVar{} language.}
- \label{fig:type-check-Lvar}
- \end{figure}
- \begin{figure}[tbp]
- {\if\edition\racketEd
- \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
- (define type-check-Lif_class
- (class type-check-Lvar_class
- (super-new)
- (inherit check-type-equal?)
-
- (define/override (operator-types)
- (append '((- . ((Integer Integer) . Integer))
- (and . ((Boolean Boolean) . Boolean))
- (or . ((Boolean Boolean) . Boolean))
- (< . ((Integer Integer) . Boolean))
- (<= . ((Integer Integer) . Boolean))
- (> . ((Integer Integer) . Boolean))
- (>= . ((Integer Integer) . Boolean))
- (not . ((Boolean) . Boolean))
- )
- (super operator-types)))
- (define/override (type-check-exp env)
- (lambda (e)
- (match e
- [(Bool b) (values (Bool b) 'Boolean)]
- [(Prim 'eq? (list e1 e2))
- (define-values (e1^ T1) ((type-check-exp env) e1))
- (define-values (e2^ T2) ((type-check-exp env) e2))
- (check-type-equal? T1 T2 e)
- (values (Prim 'eq? (list e1^ e2^)) 'Boolean)]
- [(If cnd thn els)
- (define-values (cnd^ Tc) ((type-check-exp env) cnd))
- (define-values (thn^ Tt) ((type-check-exp env) thn))
- (define-values (els^ Te) ((type-check-exp env) els))
- (check-type-equal? Tc 'Boolean e)
- (check-type-equal? Tt Te e)
- (values (If cnd^ thn^ els^) Te)]
- [else ((super type-check-exp env) e)])))
- ))
- (define (type-check-Lif p)
- (send (new type-check-Lif_class) type-check-program p))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- class TypeCheckLif(TypeCheckLvar):
- def type_check_exp(self, e, env):
- match e:
- case Constant(value) if isinstance(value, bool):
- return bool
- case BinOp(left, Sub(), right):
- l = self.type_check_exp(left, env); check_type_equal(l, int, left)
- r = self.type_check_exp(right, env); check_type_equal(r, int, right)
- return int
- case UnaryOp(Not(), v):
- t = self.type_check_exp(v, env); check_type_equal(t, bool, v)
- return bool
- case BoolOp(op, values):
- left = values[0] ; right = values[1]
- l = self.type_check_exp(left, env); check_type_equal(l, bool, left)
- r = self.type_check_exp(right, env); check_type_equal(r, bool, right)
- return bool
- case Compare(left, [cmp], [right]) if isinstance(cmp, Eq) \
- or isinstance(cmp, NotEq):
- l = self.type_check_exp(left, env)
- r = self.type_check_exp(right, env)
- check_type_equal(l, r, e)
- return bool
- case Compare(left, [cmp], [right]):
- l = self.type_check_exp(left, env); check_type_equal(l, int, left)
- r = self.type_check_exp(right, env); check_type_equal(r, int, right)
- return bool
- case IfExp(test, body, orelse):
- t = self.type_check_exp(test, env); check_type_equal(bool, t, test)
- b = self.type_check_exp(body, env)
- o = self.type_check_exp(orelse, env)
- check_type_equal(b, o, e)
- return b
- case _:
- return super().type_check_exp(e, env)
- def type_check_stmts(self, ss, env):
- if len(ss) == 0:
- return
- match ss[0]:
- case If(test, body, orelse):
- t = self.type_check_exp(test, env); check_type_equal(bool, t, test)
- b = self.type_check_stmts(body, env)
- o = self.type_check_stmts(orelse, env)
- check_type_equal(b, o, ss[0])
- return self.type_check_stmts(ss[1:], env)
- case _:
- return super().type_check_stmts(ss, env)
- \end{lstlisting}
- \fi}
- \caption{Type checker for the \LangIf{} language.}
- \label{fig:type-check-Lif}
- \end{figure}
- We shift our focus to Figure~\ref{fig:type-check-Lif}, the type
- checker for \LangIf{}.
- %
- The type of a Boolean constant is \BOOLTY{}.
- %
- \racket{The \code{operator-types} function adds dictionary entries for
- the other new operators.}
- %
- \python{Subtraction requires its arguments to be of type \INTTY{} and produces
- an \INTTY{}. Negation requires its argument to be a \BOOLTY{} and
- produces a \BOOLTY{}. Similarly for logical-and and logical-or. }
- %
- The equality operators requires the two arguments to have the same
- type.
- %
- \python{The other comparisons (less-than, etc.) require their
- arguments to be of type \INTTY{} and they produce a \BOOLTY{}.}
- %
- The condition of an \code{if} must
- be of \BOOLTY{} type and the two branches must have the same type.
- \begin{exercise}\normalfont
- Create 10 new test programs in \LangIf{}. Half of the programs should
- have a type error. For those programs, create an empty file with the
- same base name but with file extension \code{.tyerr}. For example, if
- the test
- \racket{\code{cond\_test\_14.rkt}}\python{\code{cond\_test\_14.py}}
- is expected to error, then create
- an empty file named \code{cond\_test\_14.tyerr}.
- %
- \racket{This indicates to \code{interp-tests} and
- \code{compiler-tests} that a type error is expected. }
- %
- \racket{This indicates to the \code{run-tests.py} scripts that a type
- error is expected.}
- %
- The other half of the test programs should not have type errors.
- %
- \racket{In the \code{run-tests.rkt} script, change the second argument
- of \code{interp-tests} and \code{compiler-tests} to
- \code{type-check-Lif}, which causes the type checker to run prior to
- the compiler passes. Temporarily change the \code{passes} to an
- empty list and run the script, thereby checking that the new test
- programs either type check or not as intended.}
- %
- Run the test script to check that these test programs type check as
- expected.
- \end{exercise}
- \clearpage
- \section{The \LangCIf{} Intermediate Language}
- \label{sec:Cif}
- {\if\edition\racketEd
- %
- Figure~\ref{fig:c1-concrete-syntax} defines the concrete syntax of the
- \LangCIf{} intermediate language and Figure~\ref{fig:c1-syntax}
- defines its abstract syntax. Compared to \LangCVar{}, the \LangCIf{}
- language adds logical and comparison operators to the \Exp{}
- non-terminal and the literals \TRUE{} and \FALSE{} to the \Arg{}
- non-terminal.
- Regarding control flow, \LangCIf{} adds \key{goto} and \code{if}
- statements to the \Tail{} non-terminal. The condition of an \code{if}
- statement is a comparison operation and the branches are \code{goto}
- statements, making it straightforward to compile \code{if} statements
- to x86.
- %
- \fi}
- %
- {\if\edition\pythonEd
- %
- The output of \key{explicate\_control} is a language similar to the
- $C$ language~\citep{Kernighan:1988nx} in that it has labels and
- \code{goto} statements, so we name it \LangCIf{}. The
- concrete syntax for \LangCIf{} is defined in
- Figure~\ref{fig:c1-concrete-syntax}
- and the abstract syntax is defined in Figure~\ref{fig:c1-syntax}.
- %
- The \LangCIf{} language supports the same operators as \LangIf{} but
- the arguments of operators are restricted to atomic expressions. The
- \LangCIf{} language does not include \code{if} expressions but it does
- include a restricted form of \code{if} statment. The condition must be
- a comparison and the two branches may only contain \code{goto}
- statements. These restrictions make it easier to translate \code{if}
- statements to x86.
- %
- \fi}
- %
- The \key{CProgram} construct contains
- %
- \racket{an alist}\python{a dictionary}
- %
- mapping labels to $\Tail$ expressions, which can be return statements,
- an assignment statement followed by a $\Tail$ expression, a
- \code{goto}, or a conditional \code{goto}.
- \begin{figure}[tbp]
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Atm &::=& \gray{ \Int \MID \Var } \MID \itm{bool} \\
- \itm{cmp} &::= & \code{eq?} \MID \code{<} \MID \code{<=} \MID \code{>} \MID \code{>=} \\
- \Exp &::=& \gray{ \Atm \MID \key{(read)} \MID \key{(-}~\Atm\key{)} \MID \key{(+}~\Atm~\Atm\key{)} } \\
- &\MID& \LP \key{not}~\Atm \RP \MID \LP \itm{cmp}~\Atm~\Atm\RP \\
- \Stmt &::=& \gray{ \Var~\key{=}~\Exp\key{;} } \\
- \Tail &::= & \gray{ \key{return}~\Exp\key{;} \MID \Stmt~\Tail }
- \MID \key{goto}~\itm{label}\key{;}\\
- &\MID& \key{if}~\LP \itm{cmp}~\Atm~\Atm \RP~ \key{goto}~\itm{label}\key{;} ~\key{else}~\key{goto}~\itm{label}\key{;} \\
- \LangCIfM{} & ::= & \gray{ (\itm{label}\key{:}~ \Tail)\ldots }
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The concrete syntax of the \LangCIf{} intermediate language.}
- \label{fig:c1-concrete-syntax}
- \end{figure}
- \begin{figure}[tp]
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- {\if\edition\racketEd
- \[
- \begin{array}{lcl}
- \Atm &::=& \gray{\INT{\Int} \MID \VAR{\Var}} \MID \BOOL{\itm{bool}} \\
- \itm{cmp} &::= & \code{eq?} \MID \code{<} \MID \code{<=} \MID \code{>} \MID \code{>=} \\
- \Exp &::= & \gray{ \Atm \MID \READ{} }\\
- &\MID& \gray{ \NEG{\Atm} \MID \ADD{\Atm}{\Atm} } \\
- &\MID& \UNIOP{\key{'not}}{\Atm}
- \MID \BINOP{\key{'}\itm{cmp}}{\Atm}{\Atm} \\
- \Stmt &::=& \gray{ \ASSIGN{\VAR{\Var}}{\Exp} } \\
- \Tail &::= & \gray{\RETURN{\Exp} \MID \SEQ{\Stmt}{\Tail} }
- \MID \GOTO{\itm{label}} \\
- &\MID& \IFSTMT{\BINOP{\itm{cmp}}{\Atm}{\Atm}}{\GOTO{\itm{label}}}{\GOTO{\itm{label}}} \\
- \LangCIfM{} & ::= & \gray{\CPROGRAM{\itm{info}}{\LP\LP\itm{label}\,\key{.}\,\Tail\RP\ldots\RP}}
- \end{array}
- \]
- \fi}
- {\if\edition\pythonEd
- \[
- \begin{array}{lcl}
- \Atm &::=& \INT{\Int} \MID \VAR{\Var} \MID \BOOL{\itm{bool}} \\
- \Exp &::= & \Atm \MID \READ{} \\
- &\MID& \BINOP{\Atm}{\itm{binop}}{\Atm}
- \MID \UNIOP{\itm{uniop}}{\Atm} \\
- &\MID& \CMP{\Atm}{\itm{cmp}}{\Atm}
- \MID \BOOLOP{\itm{boolop}}{\Atm}{\Atm} \\
- \Stmt &::=& \PRINT{\Exp} \MID \EXPR{\Exp} \\
- &\MID& \ASSIGN{\VAR{\Var}}{\Exp}
- \MID \RETURN{\Exp} \MID \GOTO{\itm{label}} \\
- &\MID& \IFSTMT{\CMP{\Atm}{\itm{cmp}}{\Atm}}{\LS\GOTO{\itm{label}}\RS}{\LS\GOTO{\itm{label}}\RS} \\
- \LangCIfM{} & ::= & \CPROGRAM{\itm{info}}{\LC\itm{label}\,\key{:}\,\Stmt^{*}, \ldots \RC}
- \end{array}
- \]
- \fi}
- \end{minipage}
- }
- \caption{The abstract syntax of \LangCIf{}\racket{, an extension of \LangCVar{}
- (Figure~\ref{fig:c0-syntax})}.}
- \label{fig:c1-syntax}
- \end{figure}
- \section{The \LangXIf{} Language}
- \label{sec:x86-if}
- \index{subject}{x86} To implement the new logical operations, the comparison
- operations, and the \key{if} expression, we need to delve further into
- the x86 language. Figures~\ref{fig:x86-1-concrete} and \ref{fig:x86-1}
- define the concrete and abstract syntax for the \LangXIf{} subset
- of x86, which includes instructions for logical operations,
- comparisons, and \racket{conditional} jumps.
- One challenge is that x86 does not provide an instruction that
- directly implements logical negation (\code{not} in \LangIf{} and
- \LangCIf{}). However, the \code{xorq} instruction can be used to
- encode \code{not}. The \key{xorq} instruction takes two arguments,
- performs a pairwise exclusive-or ($\mathrm{XOR}$) operation on each
- bit of its arguments, and writes the results into its second argument.
- Recall the truth table for exclusive-or:
- \begin{center}
- \begin{tabular}{l|cc}
- & 0 & 1 \\ \hline
- 0 & 0 & 1 \\
- 1 & 1 & 0
- \end{tabular}
- \end{center}
- For example, applying $\mathrm{XOR}$ to each bit of the binary numbers
- $0011$ and $0101$ yields $0110$. Notice that in the row of the table
- for the bit $1$, the result is the opposite of the second bit. Thus,
- the \code{not} operation can be implemented by \code{xorq} with $1$ as
- the first argument as follows, where $\Arg$ is the translation of
- $\Atm$.
- \[
- \CASSIGN{\Var}{\CUNIOP{\key{not}}{\Atm}}
- \qquad\Rightarrow\qquad
- \begin{array}{l}
- \key{movq}~ \Arg\key{,} \Var\\
- \key{xorq}~ \key{\$1,} \Var
- \end{array}
- \]
- \begin{figure}[tp]
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \[
- \begin{array}{lcl}
- \itm{bytereg} &::=& \key{ah} \MID \key{al} \MID \key{bh} \MID \key{bl}
- \MID \key{ch} \MID \key{cl} \MID \key{dh} \MID \key{dl} \\
- \Arg &::=& \gray{ \key{\$}\Int \MID \key{\%}\Reg \MID \Int\key{(}\key{\%}\Reg\key{)} } \MID \key{\%}\itm{bytereg}\\
- \itm{cc} & ::= & \key{e} \MID \key{l} \MID \key{le} \MID \key{g} \MID \key{ge} \\
- \Instr &::=& \gray{ \key{addq} \; \Arg\key{,} \Arg \MID
- \key{subq} \; \Arg\key{,} \Arg \MID
- \key{negq} \; \Arg \MID \key{movq} \; \Arg\key{,} \Arg \MID } \\
- && \gray{ \key{callq} \; \itm{label} \MID
- \key{pushq}\;\Arg \MID \key{popq}\;\Arg \MID \key{retq} \MID \racket{\key{jmp}\,\itm{label} \MID} } \python{\key{jmp}\,\itm{label} \MID} \\
- && \racket{\gray{ \itm{label}\key{:}\; \Instr }}\python{\itm{label}\key{:}\; \Instr}
- \MID \key{xorq}~\Arg\key{,}~\Arg
- \MID \key{cmpq}~\Arg\key{,}~\Arg \MID \\
- && \key{set}cc~\Arg
- \MID \key{movzbq}~\Arg\key{,}~\Arg
- \MID \key{j}cc~\itm{label}
- \\
- \LangXIfM{} &::= & \gray{ \key{.globl main} }\\
- & & \gray{ \key{main:} \; \Instr\ldots }
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The concrete syntax of \LangXIf{} (extends \LangXInt{} of Figure~\ref{fig:x86-int-concrete}).}
- \label{fig:x86-1-concrete}
- \end{figure}
- \begin{figure}[tp]
- \fbox{
- \begin{minipage}{0.98\textwidth}
- \small
- {\if\edition\racketEd
- \[
- \begin{array}{lcl}
- \itm{bytereg} &::=& \key{ah} \MID \key{al} \MID \key{bh} \MID \key{bl}
- \MID \key{ch} \MID \key{cl} \MID \key{dh} \MID \key{dl} \\
- \Arg &::=& \gray{\IMM{\Int} \MID \REG{\Reg} \MID \DEREF{\Reg}{\Int}}
- \MID \BYTEREG{\itm{bytereg}} \\
- \itm{cc} & ::= & \key{e} \MID \key{l} \MID \key{le} \MID \key{g} \MID \key{ge} \\
- \Instr &::=& \gray{ \BININSTR{\code{addq}}{\Arg}{\Arg}
- \MID \BININSTR{\code{subq}}{\Arg}{\Arg} } \\
- &\MID& \gray{ \BININSTR{\code{'movq}}{\Arg}{\Arg}
- \MID \UNIINSTR{\code{negq}}{\Arg} } \\
- &\MID& \gray{ \CALLQ{\itm{label}}{\itm{int}} \MID \RETQ{}
- \MID \PUSHQ{\Arg} \MID \POPQ{\Arg} \MID \JMP{\itm{label}} } \\
- &\MID& \BININSTR{\code{xorq}}{\Arg}{\Arg}
- \MID \BININSTR{\code{cmpq}}{\Arg}{\Arg}\\
- &\MID& \BININSTR{\code{set}}{\itm{cc}}{\Arg}
- \MID \BININSTR{\code{movzbq}}{\Arg}{\Arg}\\
- &\MID& \JMPIF{'\itm{cc}'}{\itm{label}} \\
- \Block &::= & \gray{\BLOCK{\itm{info}}{\LP\Instr\ldots\RP}} \\
- \LangXIfM{} &::= & \gray{\XPROGRAM{\itm{info}}{\LP\LP\itm{label} \,\key{.}\, \Block \RP\ldots\RP}}
- \end{array}
- \]
- \fi}
- %
- {\if\edition\pythonEd
- \[
- \begin{array}{lcl}
- \itm{bytereg} &::=& \key{ah} \MID \key{al} \MID \key{bh} \MID \key{bl}
- \MID \key{ch} \MID \key{cl} \MID \key{dh} \MID \key{dl} \\
- \Arg &::=& \gray{\IMM{\Int} \MID \REG{\Reg} \MID \DEREF{\Reg}{\Int}}
- \MID \BYTEREG{\itm{bytereg}} \\
- \itm{cc} & ::= & \key{e} \MID \key{l} \MID \key{le} \MID \key{g} \MID \key{ge} \\
- \Instr &::=& \gray{ \BININSTR{\code{addq}}{\Arg}{\Arg}
- \MID \BININSTR{\code{subq}}{\Arg}{\Arg} } \\
- &\MID& \gray{ \BININSTR{\code{movq}}{\Arg}{\Arg}
- \MID \UNIINSTR{\code{negq}}{\Arg} } \\
- &\MID& \gray{ \CALLQ{\itm{label}}{\itm{int}} \MID \RETQ{}
- \MID \PUSHQ{\Arg} \MID \POPQ{\Arg} \MID \racket{\JMP{\itm{label}}} } \python{\JMP{\itm{label}}}\\
- &\MID& \BININSTR{\code{xorq}}{\Arg}{\Arg}
- \MID \BININSTR{\code{cmpq}}{\Arg}{\Arg}\\
- &\MID& \BININSTR{\code{set}}{\itm{cc}}{\Arg}
- \MID \BININSTR{\code{movzbq}}{\Arg}{\Arg}\\
- &\MID& \JMPIF{\key{'}\itm{cc}\key{'}}{\itm{label}} \\
- \LangXIfM{} &::= & \XPROGRAM{\itm{info}}{\LC\itm{label} \,\key{:}\, \Instr^{*} \key{,} \ldots \RC }
- \end{array}
- \]
- \fi}
- \end{minipage}
- }
- \caption{The abstract syntax of \LangXIf{} (extends \LangXInt{} of Figure~\ref{fig:x86-int-ast}).}
- \label{fig:x86-1}
- \end{figure}
- Next we consider the x86 instructions that are relevant for compiling
- the comparison operations. The \key{cmpq} instruction compares its two
- arguments to determine whether one argument is less than, equal, or
- greater than the other argument. The \key{cmpq} instruction is unusual
- regarding the order of its arguments and where the result is
- placed. The argument order is backwards: if you want to test whether
- $x < y$, then write \code{cmpq} $y$\code{,} $x$. The result of
- \key{cmpq} is placed in the special EFLAGS register. This register
- cannot be accessed directly but it can be queried by a number of
- instructions, including the \key{set} instruction. The instruction
- $\key{set}cc~d$ puts a \key{1} or \key{0} into the destination $d$
- depending on whether the comparison comes out according to the
- condition code \itm{cc} (\key{e} for equal, \key{l} for less, \key{le}
- for less-or-equal, \key{g} for greater, \key{ge} for
- greater-or-equal). The \key{set} instruction has a quirk in
- that its destination argument must be single byte register, such as
- \code{al} (L for lower bits) or \code{ah} (H for higher bits), which
- are part of the \code{rax} register. Thankfully, the \key{movzbq}
- instruction can be used to move from a single byte register to a
- normal 64-bit register. The abstract syntax for the \code{set}
- instruction differs from the concrete syntax in that it separates the
- instruction name from the condition code.
- \python{The x86 instructions for jumping are relevant to the
- compilation of \key{if} expressions.}
- %
- \python{The instruction $\key{jmp}\,\itm{label}$ updates the program
- counter to the address of the instruction after the specified
- label.}
- %
- \racket{The x86 instruction for conditional jump is relevant to the
- compilation of \key{if} expressions.}
- %
- The instruction $\key{j}\itm{cc}~\itm{label}$ updates the program
- counter to point to the instruction after \itm{label} depending on
- whether the result in the EFLAGS register matches the condition code
- \itm{cc}, otherwise the jump instruction falls through to the next
- instruction. Like the abstract syntax for \code{set}, the abstract
- syntax for conditional jump separates the instruction name from the
- condition code. For example, \JMPIF{\key{'le'}}{\key{foo}} corresponds
- to \code{jle foo}. Because the conditional jump instruction relies on
- the EFLAGS register, it is common for it to be immediately preceded by
- a \key{cmpq} instruction to set the EFLAGS register.
- \section{Shrink the \LangIf{} Language}
- \label{sec:shrink-Lif}
- The \LangIf{} language includes several features that are easily
- expressible with other features. For example, \code{and} and \code{or}
- are expressible using \code{if} as follows.
- \begin{align*}
- \CAND{e_1}{e_2} & \quad \Rightarrow \quad \CIF{e_1}{e_2}{\FALSE{}}\\
- \COR{e_1}{e_2} & \quad \Rightarrow \quad \CIF{e_1}{\TRUE{}}{e_2}
- \end{align*}
- By performing these translations in the front-end of the compiler, the
- later passes of the compiler do not need to deal with these features,
- making the passes shorter.
- %% For example, subtraction is
- %% expressible using addition and negation.
- %% \[
- %% \key{(-}\; e_1 \; e_2\key{)} \quad \Rightarrow \quad \LP\key{+} \; e_1 \; \LP\key{-} \; e_2\RP\RP
- %% \]
- %% Several of the comparison operations are expressible using less-than
- %% and logical negation.
- %% \[
- %% \LP\key{<=}\; e_1 \; e_2\RP \quad \Rightarrow \quad
- %% \LP\key{let}~\LP\LS\key{tmp.1}~e_1\RS\RP~\LP\key{not}\;\LP\key{<}\;e_2\;\key{tmp.1})\RP\RP
- %% \]
- %% The \key{let} is needed in the above translation to ensure that
- %% expression $e_1$ is evaluated before $e_2$.
- On the other hand, sometimes translations reduce the efficiency of the
- generated code by increasing the number of instructions. For example,
- expressing subtraction in terms of negation
- \[
- \CBINOP{\key{-}}{e_1}{e_2} \quad \Rightarrow \quad
- \CBINOP{\key{+}}{e_1}{ \CUNIOP{\key{-}}{e_2} }
- \]
- produces code with two x86 instructions (\code{negq} and \code{addq})
- instead of just one (\code{subq}).
- %% However,
- %% these differences typically do not affect the number of accesses to
- %% memory, which is the primary factor that determines execution time on
- %% modern computer architectures.
- \begin{exercise}\normalfont
- %
- Implement the pass \code{shrink} to remove \key{and} and \key{or} from
- the language by translating them to \code{if} expressions in \LangIf{}.
- %
- Create four test programs that involve these operators.
- %
- {\if\edition\racketEd
- In the \code{run-tests.rkt} script, add the following entry for
- \code{shrink} to the list of passes (it should be the only pass at
- this point).
- \begin{lstlisting}
- (list "shrink" shrink interp_Lif type-check-Lif)
- \end{lstlisting}
- This instructs \code{interp-tests} to run the intepreter
- \code{interp\_Lif} and the type checker \code{type-check-Lif} on the
- output of \code{shrink}.
- \fi}
- %
- Run the script to test your compiler on all the test programs.
- \end{exercise}
- {\if\edition\racketEd
- \section{Uniquify Variables}
- \label{sec:uniquify-Lif}
- Add cases to \code{uniquify-exp} to handle Boolean constants and
- \code{if} expressions.
- \begin{exercise}\normalfont
- Update the \code{uniquify\_exp} for \LangIf{} and add the following
- entry to the list of \code{passes} in the \code{run-tests.rkt} script.
- \begin{lstlisting}
- (list "uniquify" uniquify interp_Lif type_check_Lif)
- \end{lstlisting}
- Run the script to test your compiler.
- \end{exercise}
- \fi}
- \section{Remove Complex Operands}
- \label{sec:remove-complex-opera-Lif}
- The output language of \code{remove\_complex\_operands} is \LangIfANF{}
- (Figure~\ref{fig:Lif-anf-syntax}), the administrative normal form of
- \LangIf{}. A Boolean constant is an atomic expressions but the
- \code{if} expression is not.
- All three sub-expressions of an
- \code{if} are allowed to be complex expressions but the operands of
- \code{not} and the comparisons must be atomic.
- %
- \python{We add a new language form, the \code{Let} expression, to aid
- in the translation of \code{if} expressions. The
- $\LET{x}{e_1}{e_2}$ form is like an assignment statement, but can be
- used as an expression. It assigns the result of $e_1$ to the
- variable $x$, an then evaluates $e_2$, which may reference $x$.}
- Add cases for Boolean constants, \python{comparisons,} and \code{if}
- expressions to the \code{rco\_exp} and \code{rco\_atom} functions
- according to whether the output needs to be \Exp{} or \Atm{} as
- specified in the grammar for \LangIfANF{}. Regarding \code{if}, it is
- particularly important to \textbf{not} replace its condition with a
- temporary variable because that would interfere with the generation of
- high-quality output in the \code{explicate\_control} pass.
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- {\if\edition\racketEd
- \[
- \begin{array}{rcl}
- \Atm &::=& \gray{ \INT{\Int} \MID \VAR{\Var} } \MID \BOOL{\itm{bool}}\\
- \Exp &::=& \gray{ \Atm \MID \READ{} } \\
- &\MID& \gray{ \NEG{\Atm} \MID \ADD{\Atm}{\Atm} } \\
- &\MID& \gray{ \LET{\Var}{\Exp}{\Exp} } \\
- &\MID& \UNIOP{\key{not}}{\Atm} \\
- &\MID& \BINOP{\itm{cmp}}{\Atm}{\Atm} \MID \IF{\Exp}{\Exp}{\Exp} \\
- R^{\mathsf{ANF}}_{\mathsf{if}} &::=& \PROGRAM{\code{()}}{\Exp}
- \end{array}
- \]
- \fi}
- {\if\edition\pythonEd
- \[
- \begin{array}{rcl}
- \Atm &::=& \INT{\Int} \MID \VAR{\Var} \MID \BOOL{\itm{bool}}\\
- \Exp &::=& \Atm \MID \READ{} \\
- &\MID& \BINOP{\itm{binop}}{\Atm}{\Atm} \MID \UNIOP{\key{uniop}}{\Atm} \\
- &\MID& \CMP{\Atm}{\itm{cmp}}{\Atm} \MID \IF{\Exp}{\Exp}{\Exp} \\
- &\MID& \LET{\Var}{\Exp}{\Exp}\\
- \Stmt{} &::=& \PRINT{\Atm} \MID \EXPR{\Exp} \\
- &\MID& \ASSIGN{\VAR{\Var}}{\Exp} \MID \IFSTMT{\Exp}{\Stmt^{*}}{\Stmt^{*}}\\
- P^{\mathsf{ANF}}_{\mathsf{if}} &::=& \PROGRAM{\code{()}}{\Stmt^{*}}
- \end{array}
- \]
- \fi}
- \end{minipage}
- }
- \caption{\LangIfANF{} is \LangIf{} in administrative normal form (ANF).}
- \label{fig:Lif-anf-syntax}
- \end{figure}
- \begin{exercise}\normalfont
- %
- Add cases for Boolean constants and \code{if} to the \code{rco\_atom}
- and \code{rco\_exp} functions in \code{compiler.rkt}.
- %
- Create three new \LangInt{} programs that exercise the interesting
- code in this pass.
- %
- {\if\edition\racketEd
- In the \code{run-tests.rkt} script, add the following entry to the
- list of \code{passes} and then run the script to test your compiler.
- \begin{lstlisting}
- (list "remove-complex" remove-complex-opera* interp-Lif type-check-Lif)
- \end{lstlisting}
- \fi}
- \end{exercise}
- \section{Explicate Control}
- \label{sec:explicate-control-Lif}
- \racket{Recall that the purpose of \code{explicate\_control} is to
- make the order of evaluation explicit in the syntax of the program.
- With the addition of \key{if} this get more interesting.}
- %
- The \code{explicate\_control} pass translates from \LangIf{} to \LangCIf{}.
- %
- The main challenge to overcome is that the condition of an \key{if}
- can be an arbitrary expression in \LangIf{} whereas in \LangCIf{} the
- condition must be a comparison.
- As a motivating example, consider the following program that has an
- \key{if} expression nested in the condition of another \key{if}.%
- \python{\footnote{Programmers rarely write nested \code{if}
- expressions, but it is not uncommon for the condition of an
- \code{if} statement to be a call of a function that also contains an
- \code{if} statement. When such a function is inlined, the result is
- a nested \code{if} that requires the techniques discussed in this
- section.}}
- % cond_test_41.rkt, if_lt_eq.py
- \begin{center}
- \begin{minipage}{0.96\textwidth}
- {\if\edition\racketEd
- \begin{lstlisting}
- (let ([x (read)])
- (let ([y (read)])
- (if (if (< x 1) (eq? x 0) (eq? x 2))
- (+ y 2)
- (+ y 10))))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- x = input_int()
- y = input_int()
- print(y + 2 if (x == 0 if x < 1 else x == 2) else y + 10)
- \end{lstlisting}
- \fi}
- \end{minipage}
- \end{center}
- %
- The naive way to compile \key{if} and the comparison operations would
- be to handle each of them in isolation, regardless of their context.
- Each comparison would be translated into a \key{cmpq} instruction
- followed by a couple instructions to move the result from the EFLAGS
- register into a general purpose register or stack location. Each
- \key{if} would be translated into a \key{cmpq} instruction followed by
- a conditional jump. The generated code for the inner \key{if} in the
- above example would be as follows.
- \begin{center}
- \begin{minipage}{0.96\textwidth}
- \begin{lstlisting}
- cmpq $1, x
- setl %al
- movzbq %al, tmp
- cmpq $1, tmp
- je then_branch_1
- jmp else_branch_1
- \end{lstlisting}
- \end{minipage}
- \end{center}
- However, if we take context into account we can do better and reduce
- the use of \key{cmpq} instructions for accessing the EFLAG register.
- Our goal will be to compile \key{if} expressions so that the relevant
- comparison instruction appears directly before the conditional jump.
- For example, we want to generate the following code for the inner
- \code{if}.
- \begin{center}
- \begin{minipage}{0.96\textwidth}
- \begin{lstlisting}
- cmpq $1, x
- je then_branch_1
- jmp else_branch_1
- \end{lstlisting}
- \end{minipage}
- \end{center}
- One way to achieve this is to reorganize the code at the level of
- \LangIf{}, pushing the outer \key{if} inside the inner one, yielding
- the following code.
- \begin{center}
- \begin{minipage}{0.96\textwidth}
- {\if\edition\racketEd
- \begin{lstlisting}
- (let ([x (read)])
- (let ([y (read)])
- (if (< x 1)
- (if (eq? x 0)
- (+ y 2)
- (+ y 10))
- (if (eq? x 2)
- (+ y 2)
- (+ y 10)))))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- \begin{lstlisting}
- x = input_int()
- y = intput_int()
- print(((y + 2) if x == 0 else (y + 10)) \
- if (x < 1) \
- else ((y + 2) if (x == 2) else (y + 10)))
- \end{lstlisting}
- \fi}
- \end{minipage}
- \end{center}
- Unfortunately, this approach duplicates the two branches from the
- outer \code{if} and a compiler must never duplicate code! After all,
- the two branches could have been very large expressions.
- We need a way to perform the above transformation but without
- duplicating code. That is, we need a way for different parts of a
- program to refer to the same piece of code.
- %
- Put another way, we need to move away from abstract syntax
- \emph{trees} and instead use \emph{graphs}.
- %
- At the level of x86 assembly this is straightforward because we can
- label the code for each branch and insert jumps in all the places that
- need to execute the branch.
- %
- Likewise, our language \LangCIf{} provides the ability to label a
- sequence of code and to jump to a label via \code{goto}.
- %
- %% In particular, we use a standard program representation called a
- %% \emph{control flow graph} (CFG), due to Frances Elizabeth
- %% \citet{Allen:1970uq}. \index{subject}{control-flow graph} Each vertex
- %% is a labeled sequence of code, called a \emph{basic block}, and each
- %% edge represents a jump to another block.
- %
- %% The nice thing about the output of \code{explicate\_control} is that
- %% there are no unnecessary comparisons and every comparison is part of a
- %% conditional jump.
- %% The down-side of this output is that it includes
- %% trivial blocks, such as the blocks labeled \code{block92} through
- %% \code{block95}, that only jump to another block. We discuss a solution
- %% to this problem in Section~\ref{sec:opt-jumps}.
- {\if\edition\racketEd
- %
- Recall that in Section~\ref{sec:explicate-control-Lvar} we implement
- \code{explicate\_control} for \LangVar{} using two mutually recursive
- functions, \code{explicate\_tail} and \code{explicate\_assign}. The
- former function translates expressions in tail position whereas the
- later function translates expressions on the right-hand-side of a
- \key{let}. With the addition of \key{if} expression in \LangIf{} we
- have a new kind of position to deal with: the predicate position of
- the \key{if}. We need another function, \code{explicate\_pred}, that
- decides how to compile an \key{if} by analyzing its predicate. So
- \code{explicate\_pred} takes an \LangIf{} expression and two \LangCIf{}
- tails for the then-branch and else-branch and outputs a tail. In the
- following paragraphs we discuss specific cases in the
- \code{explicate\_tail}, \code{explicate\_assign}, and
- \code{explicate\_pred} functions.
- %
- \fi}
- %
- {\if\edition\pythonEd
- %
- We recommend implementing \code{explicate\_control} using the
- following four auxiliary functions.
- \begin{description}
- \item[\code{explicate\_effect}] generates code for expressions as
- statements, so their result is ignored and only their side effects
- matter.
- \item[\code{explicate\_assign}] generates code for expressions
- on the right-hand side of an assignment.
- \item[\code{explicate\_pred}] generates code for an \code{if}
- expression or statement by analyzing the condition expression.
- \item[\code{explicate\_stmt}] generates code for statements.
- \end{description}
- These four functions should build the dictionary of basic blocks. The
- following auxiliary function can be used to create a new basic block
- from a list of statements. It returns a \code{goto} statement that
- jumps to the new basic block.
- \begin{center}
- \begin{minipage}{\textwidth}
- \begin{lstlisting}
- def create_block(stmts, basic_blocks):
- label = label_name(generate_name('block'))
- basic_blocks[label] = stmts
- return Goto(label)
- \end{lstlisting}
- \end{minipage}
- \end{center}
- Figure~\ref{fig:explicate-control-Lif} provides a skeleton for the
- \code{explicate\_control} pass.
- The \code{explicate\_effect} function has three parameters: 1) the
- expression to be compiled, 2) the already-compiled code for this
- expression's \emph{continuation}, that is, the list of statements that
- should execute after this expression, and 3) the dictionary of
- generated basic blocks. The \code{explicate\_effect} function returns
- a list of \LangCIf{} statements and it may add to the dictionary of
- basic blocks.
- %
- Let's consider a few of the cases for the expression to be compiled.
- If the expression to be compiled is a constant, then it can be
- discarded because it has no side effects. If it's a \CREAD{}, then it
- has a side-effect and should be preserved. So the exprssion should be
- translated into a statement using the \code{Expr} AST class. If the
- expression to be compiled is an \code{if} expression, we translate the
- two branches using \code{explicate\_effect} and then translate the
- condition expression using \code{explicate\_pred}, which generates
- code for the entire \code{if}.
- The \code{explicate\_assign} function has four parameters: 1) the
- right-hand-side of the assignment, 2) the left-hand-side of the
- assignment (the variable), 3) the continuation, and 4) the dictionary
- of basic blocks. The \code{explicate\_assign} function returns a list
- of \LangCIf{} statements and it may add to the dictionary of basic
- blocks.
- When the right-hand-side is an \code{if} expression, there is some
- work to do. In particular, the two branches should be translated using
- \code{explicate\_assign} and the condition expression should be
- translated using \code{explicate\_pred}. Otherwise we can simply
- generate an assignment statement, with the given left and right-hand
- sides, concatenated with its continuation.
- \begin{figure}[tbp]
- \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
- def explicate_effect(e, cont, basic_blocks):
- match e:
- case IfExp(test, body, orelse):
- ...
- case Call(func, args):
- ...
- case Let(var, rhs, body):
- ...
- case _:
- ...
- def explicate_assign(rhs, lhs, cont, basic_blocks):
- match rhs:
- case IfExp(test, body, orelse):
- ...
- case Let(var, rhs, body):
- ...
- case _:
- return [Assign([lhs], rhs)] + cont
- def explicate_pred(cnd, thn, els, basic_blocks):
- match cnd:
- case Compare(left, [op], [right]):
- goto_thn = create_block(thn, basic_blocks)
- goto_els = create_block(els, basic_blocks)
- return [If(cnd, [goto_thn], [goto_els])]
- case Constant(True):
- return thn;
- case Constant(False):
- return els;
- case UnaryOp(Not(), operand):
- ...
- case IfExp(test, body, orelse):
- ...
- case Let(var, rhs, body):
- ...
- case _:
- return [If(Compare(cnd, [Eq()], [Constant(False)]),
- [create_block(els, basic_blocks)],
- [create_block(thn, basic_blocks)])]
- def explicate_stmt(s, cont, basic_blocks):
- match s:
- case Assign([lhs], rhs):
- return explicate_assign(rhs, lhs, cont, basic_blocks)
- case Expr(value):
- return explicate_effect(value, cont, basic_blocks)
- case If(test, body, orelse):
- ...
- def explicate_control(p):
- match p:
- case Module(body):
- new_body = [Return(Constant(0))]
- basic_blocks = {}
- for s in reversed(body):
- new_body = explicate_stmt(s, new_body, basic_blocks)
- basic_blocks[label_name('start')] = new_body
- return CProgram(basic_blocks)
- \end{lstlisting}
- \caption{Skeleton for the \code{explicate\_control} pass.}
- \label{fig:explicate-control-Lif}
- \end{figure}
- \fi}
- {\if\edition\racketEd
- %
- The \code{explicate\_tail} and \code{explicate\_assign} functions need
- additional cases for Boolean constants and \key{if}. The cases for
- \code{if} should recursively compile the two branches using either
- \code{explicate\_tail} or \code{explicate\_assign}, respectively. The
- cases should then invoke \code{explicate\_pred} on the condition
- expression, passing in the generated code for the two branches. For
- example, consider the following program with an \code{if} in tail
- position.
- \begin{lstlisting}
- (let ([x (read)])
- (if (eq? x 0) 42 777))
- \end{lstlisting}
- The two branches are recursively compiled to \code{return 42;} and
- \code{return 777;}. We then delegate to \code{explicate\_pred},
- passing the condition \code{(eq? x 0)} and the two return statements, which is
- used as the result for \code{explicate\_tail}.
- Next let us consider a program with an \code{if} on the right-hand
- side of a \code{let}.
- \begin{lstlisting}
- (let ([y (read)])
- (let ([x (if (eq? y 0) 40 777)])
- (+ x 2)))
- \end{lstlisting}
- Note that the body of the inner \code{let} will have already been
- compiled to \code{return (+ x 2);} and passed as the \code{cont}
- parameter of \code{explicate\_assign}. We'll need to use \code{cont}
- to recursively process both branches of the \code{if}, so we generate
- the following block using an auxiliary function named \code{create\_block}.
- \begin{lstlisting}
- block_6:
- return (+ x 2)
- \end{lstlisting}
- and use \code{goto block\_6;} as the \code{cont} argument for
- compiling the branches. So the two branches compile to
- \begin{lstlisting}
- x = 40;
- goto block_6;
- \end{lstlisting}
- and
- \begin{lstlisting}
- x = 777;
- goto block_6;
- \end{lstlisting}
- We then delegate to \code{explicate\_pred}, passing the condition \code{(eq? y
- 0)} and the above code for the branches.
- \fi}
- {\if\edition\racketEd
- \begin{figure}[tbp]
- \begin{lstlisting}
- (define (explicate_pred cnd thn els)
- (match cnd
- [(Var x) ___]
- [(Let x rhs body) ___]
- [(Prim 'not (list e)) ___]
- [(Prim op es) #:when (or (eq? op 'eq?) (eq? op '<))
- (IfStmt (Prim op arg*) (create_block thn)
- (create_block els))]
- [(Bool b) (if b thn els)]
- [(If cnd^ thn^ els^) ___]
- [else (error "explicate_pred unhandled case" cnd)]))
- \end{lstlisting}
- \caption{Skeleton for the \key{explicate\_pred} auxiliary function.}
- \label{fig:explicate-pred}
- \end{figure}
- \fi}
- \racket{The skeleton for the \code{explicate\_pred} function is given
- in Figure~\ref{fig:explicate-pred}. It takes three parameters:
- 1) \code{cnd}, the condition expression of the \code{if},
- 2) \code{thn}, the code generated by explicate for the ``then'' branch,
- and 3) \code{els}, the code generated by
- explicate for the ``else'' branch. The \code{explicate\_pred}
- function should match on \code{cnd} with a case for
- every kind of expression that can have type \code{Boolean}.}
- %
- \python{The \code{explicate\_pred} function has four parameters: 1)
- the condition expession, 2) the generated statements for the
- ``then'' branch, 3) the generated statements for the ``else''
- branch, and 4) the dictionary of basic blocks. The
- \code{explicate\_pred} function returns a list of \LangCIf{}
- statements and it may add to the dictionary of basic blocks.}
- Consider the case for comparison operators. We translate the
- comparison to an \code{if} statement whose branches are \code{goto}
- statements created by applying \code{create\_block} to the code
- generated for the \code{thn} and \code{els} branches. Let us
- illustrate this translation with an example. Returning
- to the program with an \code{if} expression in tail position,
- we invoke \code{explicate\_pred} on its condition \code{(eq? x 0)}
- which happens to be a comparison operator.
- \begin{lstlisting}
- (let ([x (read)])
- (if (eq? x 0) 42 777))
- \end{lstlisting}
- The two branches \code{42} and \code{777} were already compiled to \code{return}
- statements, from which we now create the following blocks.
- \begin{center}
- \begin{minipage}{\textwidth}
- \begin{lstlisting}
- block_1:
- return 42;
- block_2:
- return 777;
- \end{lstlisting}
- \end{minipage}
- \end{center}
- %
- So \code{explicate\_pred} compiles the comparison \code{(eq? x 0)}
- to the following \code{if} statement.
- %
- \begin{center}
- \begin{minipage}{\textwidth}
- \begin{lstlisting}
- if (eq? x 0)
- goto block_1;
- else
- goto block_2;
- \end{lstlisting}
- \end{minipage}
- \end{center}
- Next consider the case for Boolean constants. We perform a kind of
- partial evaluation\index{subject}{partial evaluation} and output
- either the \code{thn} or \code{els} branch depending on whether the
- constant is \TRUE{} or \FALSE{}. Let us illustrate this with the
- following program.
- \begin{center}
- \begin{minipage}{\textwidth}
- \begin{lstlisting}
- (if #t 42 777)
- \end{lstlisting}
- \end{minipage}
- \end{center}
- %
- Again, the two branches \code{42} and \code{777} were compiled to
- \code{return} statements, so \code{explicate\_pred} compiles the
- constant \code{\#t} to the code for the ``then'' branch.
- \begin{center}
- \begin{minipage}{\textwidth}
- \begin{lstlisting}
- return 42;
- \end{lstlisting}
- \end{minipage}
- \end{center}
- %
- This case demonstrates that we sometimes discard the \code{thn} or
- \code{els} blocks that are input to \code{explicate\_pred}.
- The case for \key{if} expressions in \code{explicate\_pred} is
- particularly illuminating because it deals with the challenges we
- discussed above regarding nested \key{if} expressions
- (Figure~\ref{fig:explicate-control-s1-38}). The
- \racket{\lstinline{thn^}}\python{\code{body}} and
- \racket{\lstinline{els^}}\python{\code{orlese}} branches of the
- \key{if} inherit their context from the current one, that is,
- predicate context. So you should recursively apply
- \code{explicate\_pred} to the
- \racket{\lstinline{thn^}}\python{\code{body}} and
- \racket{\lstinline{els^}}\python{\code{orelse}} branches. For both of
- those recursive calls, pass \code{thn} and \code{els} as the extra
- parameters. Thus, \code{thn} and \code{els} may get used twice, once
- inside each recursive call. As discussed above, to avoid duplicating
- code, we need to add them to the dictionary of basic blocks so that we
- can instead refer to them by name and execute them with a \key{goto}.
- {\if\edition\pythonEd
- %
- The last of the auxiliary functions is \code{explicate\_stmt}. It has
- three parameters: 1) the statement to be compiled, 2) the code for its
- continuation, and 3) the dictionary of basic blocks. The
- \code{explicate\_stmt} returns a list of statements and it may add to
- the dictionary of basic blocks. The cases for assignment and an
- expression-statement are given in full in the skeleton code: they
- simply dispatch to \code{explicate\_assign} and
- \code{explicate\_effect}, respectively. The case for \code{if}
- statements is not given, and is similar to the case for \code{if}
- expressions.
- The \code{explicate\_control} function itself is given in
- Figure~\ref{fig:explicate-control-Lif}. It applies
- \code{explicate\_stmt} to each statement in the program, from back to
- front. Thus, the result so-far, stored in \code{new\_body}, can be
- used as the continuation parameter in the next call to
- \code{explicate\_stmt}. The \code{new\_body} is initialized to a
- \code{Return} statement. Once complete, we add the \code{new\_body} to
- the dictionary of basic blocks, labeling it as the ``start'' block.
- %
- \fi}
- %% Getting back to the case for \code{if} in \code{explicate\_pred}, we
- %% make the recursive calls to \code{explicate\_pred} on the ``then'' and
- %% ``else'' branches with the arguments \code{(create_block} $B_1$\code{)}
- %% and \code{(create_block} $B_2$\code{)}. Let $B_3$ and $B_4$ be the
- %% results from the two recursive calls. We complete the case for
- %% \code{if} by recursively apply \code{explicate\_pred} to the condition
- %% of the \code{if} with the promised blocks $B_3$ and $B_4$ to obtain
- %% the result $B_5$.
- %% \[
- %% (\key{if}\; \itm{cnd}\; \itm{thn}\; \itm{els})
- %% \quad\Rightarrow\quad
- %% B_5
- %% \]
- %% In the case for \code{if} in \code{explicate\_tail}, the two branches
- %% inherit the current context, so they are in tail position. Thus, the
- %% recursive calls on the ``then'' and ``else'' branch should be calls to
- %% \code{explicate\_tail}.
- %% %
- %% We need to pass $B_0$ as the accumulator argument for both of these
- %% recursive calls, but we need to be careful not to duplicate $B_0$.
- %% Thus, we first apply \code{create_block} to $B_0$ so that it gets added
- %% to the control-flow graph and obtain a promised goto $G_0$.
- %% %
- %% Let $B_1$ be the result of \code{explicate\_tail} on the ``then''
- %% branch and $G_0$ and let $B_2$ be the result of \code{explicate\_tail}
- %% on the ``else'' branch and $G_0$. Let $B_3$ be the result of applying
- %% \code{explicate\_pred} to the condition of the \key{if}, $B_1$, and
- %% $B_2$. Then the \key{if} as a whole translates to promise $B_3$.
- %% \[
- %% (\key{if}\; \itm{cnd}\; \itm{thn}\; \itm{els}) \quad\Rightarrow\quad B_3
- %% \]
- %% In the above discussion, we use the metavariables $B_1$, $B_2$, and
- %% $B_3$ to refer to blocks for the purposes of our discussion, but they
- %% should not be confused with the labels for the blocks that appear in
- %% the generated code. We initially construct unlabeled blocks; we only
- %% attach labels to blocks when we add them to the control-flow graph, as
- %% we see in the next case.
- %% Next consider the case for \key{if} in the \code{explicate\_assign}
- %% function. The context of the \key{if} is an assignment to some
- %% variable $x$ and then the control continues to some promised block
- %% $B_1$. The code that we generate for both the ``then'' and ``else''
- %% branches needs to continue to $B_1$, so to avoid duplicating $B_1$ we
- %% apply \code{create_block} to it and obtain a promised goto $G_1$. The
- %% branches of the \key{if} inherit the current context, so they are in
- %% assignment positions. Let $B_2$ be the result of applying
- %% \code{explicate\_assign} to the ``then'' branch, variable $x$, and
- %% $G_1$. Let $B_3$ be the result of applying \code{explicate\_assign} to
- %% the ``else'' branch, variable $x$, and $G_1$. Finally, let $B_4$ be
- %% the result of applying \code{explicate\_pred} to the predicate
- %% $\itm{cnd}$ and the promises $B_2$ and $B_3$. The \key{if} as a whole
- %% translates to the promise $B_4$.
- %% \[
- %% (\key{if}\; \itm{cnd}\; \itm{thn}\; \itm{els}) \quad\Rightarrow\quad B_4
- %% \]
- %% This completes the description of \code{explicate\_control} for \LangIf{}.
- Figure~\ref{fig:explicate-control-s1-38} shows the output of the
- \code{remove\_complex\_operands} pass and then the
- \code{explicate\_control} pass on the example program. We walk through
- the output program.
- %
- Following the order of evaluation in the output of
- \code{remove\_complex\_operands}, we first have two calls to \CREAD{}
- and then the comparison \racket{\code{(< x 1)}}\python{\code{x < 1}}
- in the predicate of the inner \key{if}. In the output of
- \code{explicate\_control}, in the
- block labeled \code{start}, are two assignment statements followed by a
- \code{if} statement that branches to \code{block\_8} or
- \code{block\_9}. The blocks associated with those labels contain the
- translations of the code
- \racket{\code{(eq? x 0)}}\python{\code{x == 0}}
- and
- \racket{\code{(eq? x 2)}}\python{\code{x == 2}},
- respectively. In particular, we start \code{block\_8} with the
- comparison
- \racket{\code{(eq? x 0)}}\python{\code{x == 0}}
- and then branch to \code{block\_4} or \code{block\_5}.
- Here was see that our algorithm sometimes inserts unnecessary blocks:
- \code{block\_4} is just a \code{goto} to \code{block\_2}
- and \code{block\_5} is just a \code{goto} to \code{block\_3}.
- It would be better to skip blocks \code{block\_4} and \code{block\_5}
- and go directly to \code{block\_2} and \code{block\_3},
- which we investigate in Section~\ref{sec:opt-jumps}.
- Getting back to the example, \code{block\_2} and \code{block\_3},
- corresponds to the two branches of the outer \key{if}, i.e.,
- \racket{\code{(+ y 2)}}\python{\code{y + 2}} and
- \racket{\code{(+ y 10)}}\python{\code{y + 10}}.
- %
- The story for \code{block\_9} is similar to that of \code{block\_8}.
- %
- \python{The \code{block\_1} corresponds to the \code{print} statment
- at the end of the program.}
- \begin{figure}[tbp]
- {\if\edition\racketEd
- \begin{tabular}{lll}
- \begin{minipage}{0.4\textwidth}
- % cond_test_41.rkt
- \begin{lstlisting}
- (let ([x (read)])
- (let ([y (read)])
- (if (if (< x 1)
- (eq? x 0)
- (eq? x 2))
- (+ y 2)
- (+ y 10))))
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow$
- &
- \begin{minipage}{0.55\textwidth}
- \begin{lstlisting}
- start:
- x = (read);
- y = (read);
- if (< x 1)
- goto block_8;
- else
- goto block_9;
- block_8:
- if (eq? x 0)
- goto block_4;
- else
- goto block_5;
- block_9:
- if (eq? x 2)
- goto block_6;
- else
- goto block_7;
- block_4:
- goto block_2;
- block_5:
- goto block_3;
- block_6:
- goto block_2;
- block_7:
- goto block_3;
- block_2:
- return (+ y 2);
- block_3:
- return (+ y 10);
- \end{lstlisting}
- \end{minipage}
- \end{tabular}
- \fi}
- {\if\edition\pythonEd
- \begin{tabular}{lll}
- \begin{minipage}{0.4\textwidth}
- % cond_test_41.rkt
- \begin{lstlisting}
- x = input_int()
- y = input_int()
- print(y + 2 \
- if (x == 0 \
- if x < 1 \
- else x == 2) \
- else y + 10)
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow$
- &
- \begin{minipage}{0.55\textwidth}
- \begin{lstlisting}
- start:
- x = input_int()
- y = input_int()
- if x < 1:
- goto block_8
- else:
- goto block_9
- block_8:
- if x == 0:
- goto block_4
- else:
- goto block_5
- block_9:
- if x == 2:
- goto block_6
- else:
- goto block_7
- block_4:
- goto block_2
- block_5:
- goto block_3
- block_6:
- goto block_2
- block_7:
- goto block_3
- block_2:
- tmp_0 = y + 2
- goto block_1
- block_3:
- tmp_0 = y + 10
- goto block_1
- block_1:
- print(tmp_0)
- return 0
- \end{lstlisting}
- \end{minipage}
- \end{tabular}
- \fi}
- \caption{Translation from \LangIf{} to \LangCIf{}
- via the \code{explicate\_control}.}
- \label{fig:explicate-control-s1-38}
- \end{figure}
- {\if\edition\racketEd
- The way in which the \code{shrink} pass transforms logical operations
- such as \code{and} and \code{or} can impact the quality of code
- generated by \code{explicate\_control}. For example, consider the
- following program.
- % cond_test_21.rkt, and_eq_input.py
- \begin{lstlisting}
- (if (and (eq? (read) 0) (eq? (read) 1))
- 0
- 42)
- \end{lstlisting}
- The \code{and} operation should transform into something that the
- \code{explicate\_pred} function can still analyze and descend through to
- reach the underlying \code{eq?} conditions. Ideally, your
- \code{explicate\_control} pass should generate code similar to the
- following for the above program.
- \begin{center}
- \begin{lstlisting}
- start:
- tmp1 = (read);
- if (eq? tmp1 0) goto block40;
- else goto block39;
- block40:
- tmp2 = (read);
- if (eq? tmp2 1) goto block38;
- else goto block39;
- block38:
- return 0;
- block39:
- return 42;
- \end{lstlisting}
- \end{center}
- \fi}
- \begin{exercise}\normalfont
- \racket{
- Implement the pass \code{explicate\_control} by adding the cases for
- Boolean constants and \key{if} to the \code{explicate\_tail} and
- \code{explicate\_assign} functions. Implement the auxiliary function
- \code{explicate\_pred} for predicate contexts.}
- \python{Implement \code{explicate\_control} pass with its
- four auxiliary functions.}
- %
- Create test cases that exercise all of the new cases in the code for
- this pass.
- %
- {\if\edition\racketEd
- Add the following entry to the list of \code{passes} in
- \code{run-tests.rkt} and then run this script to test your compiler.
- \begin{lstlisting}
- (list "explicate_control" explicate_control interp-Cif type-check-Cif)
- \end{lstlisting}
- \fi}
- \end{exercise}
- \clearpage
- \section{Select Instructions}
- \label{sec:select-Lif}
- \index{subject}{instruction selection}
- The \code{select\_instructions} pass translates \LangCIf{} to
- \LangXIfVar{}.
- %
- \racket{Recall that we implement this pass using three auxiliary
- functions, one for each of the non-terminals $\Atm$, $\Stmt$, and
- $\Tail$.}
- %
- \racket{For $\Atm$, we have new cases for the Booleans.}
- %
- \python{We begin with the Boolean constants.}
- We take the usual approach of encoding them as integers.
- \[
- \TRUE{} \quad\Rightarrow\quad \key{1}
- \qquad\qquad
- \FALSE{} \quad\Rightarrow\quad \key{0}
- \]
- For translating statements, we discuss a couple cases. The \code{not}
- operation can be implemented in terms of \code{xorq} as we discussed
- at the beginning of this section. Given an assignment, if the
- left-hand side variable is the same as the argument of \code{not},
- then just the \code{xorq} instruction suffices.
- \[
- \CASSIGN{\Var}{ \CUNIOP{\key{not}}{\Var} }
- \quad\Rightarrow\quad
- \key{xorq}~\key{\$}1\key{,}~\Var
- \]
- Otherwise, a \key{movq} is needed to adapt to the update-in-place
- semantics of x86. In the following translation, let $\Arg$ be the
- result of translating $\Atm$ to x86.
- \[
- \CASSIGN{\Var}{ \CUNIOP{\key{not}}{\Atm} }
- \quad\Rightarrow\quad
- \begin{array}{l}
- \key{movq}~\Arg\key{,}~\Var\\
- \key{xorq}~\key{\$}1\key{,}~\Var
- \end{array}
- \]
- Next consider the cases for equality. Translating this operation to
- x86 is slightly involved due to the unusual nature of the \key{cmpq}
- instruction discussed above. We recommend translating an assignment
- with an equality on the right-hand side into a sequence of three
- instructions. \\
- \begin{tabular}{lll}
- \begin{minipage}{0.4\textwidth}
- \begin{lstlisting}
- |$\CASSIGN{\Var}{ \LP\CEQ{\Atm_1}{\Atm_2} \RP }$|
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow$
- &
- \begin{minipage}{0.4\textwidth}
- \begin{lstlisting}
- cmpq |$\Arg_2$|, |$\Arg_1$|
- sete %al
- movzbq %al, |$\Var$|
- \end{lstlisting}
- \end{minipage}
- \end{tabular} \\
- The translations for the other comparison operators are similar to the
- above but use different suffixes for the \code{set} instruction.
- \racket{Regarding the $\Tail$ non-terminal, we have two new cases:
- \key{goto} and \key{if} statements. Both are straightforward to
- translate to x86.}
- %
- A \key{goto} statement becomes a jump instruction.
- \[
- \key{goto}\; \ell\racket{\key{;}} \quad \Rightarrow \quad \key{jmp}\;\ell
- \]
- %
- An \key{if} statement becomes a compare instruction followed by a
- conditional jump (for the ``then'' branch) and the fall-through is to
- a regular jump (for the ``else'' branch).\\
- \begin{tabular}{lll}
- \begin{minipage}{0.4\textwidth}
- \begin{lstlisting}
- if |$\CEQ{\Atm_1}{\Atm_2}$||$\python{\key{:}}$|
- goto |$\ell_1$||$\racket{\key{;}}$|
- else|$\python{\key{:}}$|
- goto |$\ell_2$||$\racket{\key{;}}$|
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow$
- &
- \begin{minipage}{0.4\textwidth}
- \begin{lstlisting}
- cmpq |$\Arg_2$|, |$\Arg_1$|
- je |$\ell_1$|
- jmp |$\ell_2$|
- \end{lstlisting}
- \end{minipage}
- \end{tabular} \\
- Again, the translations for the other comparison operators are similar to the
- above but use different suffixes for the conditional jump instruction.
- \python{Regarding the \key{return} statement, we recommend treating it
- as an assignment to the \key{rax} register followed by a jump to the
- conclusion of the \code{main} function.}
- \begin{exercise}\normalfont
- Expand your \code{select\_instructions} pass to handle the new
- features of the \LangIf{} language.
- %
- {\if\edition\racketEd
- Add the following entry to the list of \code{passes} in
- \code{run-tests.rkt}
- \begin{lstlisting}
- (list "select_instructions" select_instructions interp-pseudo-x86-1)
- \end{lstlisting}
- \fi}
- %
- Run the script to test your compiler on all the test programs.
- \end{exercise}
- \section{Register Allocation}
- \label{sec:register-allocation-Lif}
- \index{subject}{register allocation}
- The changes required for \LangIf{} affect liveness analysis, building the
- interference graph, and assigning homes, but the graph coloring
- algorithm itself does not change.
- \subsection{Liveness Analysis}
- \label{sec:liveness-analysis-Lif}
- \index{subject}{liveness analysis}
- Recall that for \LangVar{} we implemented liveness analysis for a
- single basic block (Section~\ref{sec:liveness-analysis-Lvar}). With
- the addition of \key{if} expressions to \LangIf{},
- \code{explicate\_control} produces many basic blocks.
- %% We recommend that you create a new auxiliary function named
- %% \code{uncover\_live\_CFG} that applies liveness analysis to a
- %% control-flow graph.
- The first question is: what order should we process the basic blocks?
- Recall that to perform liveness analysis on a basic block we need to
- know the live-after set for the last instruction in the block. If a
- basic block has no successors (i.e. contains no jumps to other
- blocks), then it has an empty live-after set and we can immediately
- apply liveness analysis to it. If a basic block has some successors,
- then we need to complete liveness analysis on those blocks
- first. These ordering contraints are the reverse of a
- \emph{topological order}\index{subject}{topological order} on a graph
- representation of the program. In particular, the \emph{control flow
- graph} (CFG)\index{subject}{control-flow graph}~\citep{Allen:1970uq}
- of a program has a node for each basic block and an edge for each jump
- from one block to another. It is straightforward to generate a CFG
- from the dictionary of basic blocks. One then transposes the CFG and
- applies the topological sort algorithm.
- %
- %
- \racket{We recommend using the \code{tsort} and \code{transpose}
- functions of the Racket \code{graph} package to accomplish this.}
- %
- \python{We provide implementations of \code{topological\_sort} and
- \code{transpose} in the file \code{graph.py} of the support code.}
- %
- As an aside, a topological ordering is only guaranteed to exist if the
- graph does not contain any cycles. This is the case for the
- control-flow graphs that we generate from \LangIf{} programs.
- However, in Chapter~\ref{ch:Rwhile} we add loops to create \LangLoop{}
- and learn how to handle cycles in the control-flow graph.
- \racket{You'll need to construct a directed graph to represent the
- control-flow graph. Do not use the \code{directed-graph} of the
- \code{graph} package because that only allows at most one edge
- between each pair of vertices, but a control-flow graph may have
- multiple edges between a pair of vertices. The \code{multigraph.rkt}
- file in the support code implements a graph representation that
- allows multiple edges between a pair of vertices.}
- {\if\edition\racketEd
- The next question is how to analyze jump instructions. Recall that in
- Section~\ref{sec:liveness-analysis-Lvar} we maintain an alist named
- \code{label->live} that maps each label to the set of live locations
- at the beginning of its block. We use \code{label->live} to determine
- the live-before set for each $\JMP{\itm{label}}$ instruction. Now
- that we have many basic blocks, \code{label->live} needs to be updated
- as we process the blocks. In particular, after performing liveness
- analysis on a block, we take the live-before set of its first
- instruction and associate that with the block's label in the
- \code{label->live}.
- \fi}
- %
- {\if\edition\pythonEd
- %
- The next question is how to analyze jump instructions. The locations
- that are live before a \code{jmp} should be the locations in
- $L_{\mathtt{before}}$ at the target of the jump. So we recommend
- maintaining a dictionary named \code{live\_before\_block} that maps each
- label to the $L_{\mathtt{before}}$ for the first instruction in its
- block. After performing liveness analysis on each block, we take the
- live-before set of its first instruction and associate that with the
- block's label in the \code{live\_before\_block} dictionary.
- %
- \fi}
- In \LangXIfVar{} we also have the conditional jump
- $\JMPIF{\itm{cc}}{\itm{label}}$ to deal with. Liveness analysis for
- this instruction is particularly interesting because, during
- compilation, we do not know which way a conditional jump will go. So
- we do not know whether to use the live-before set for the following
- instruction or the live-before set for the block associated with the
- $\itm{label}$. However, there is no harm to the correctness of the
- generated code if we classify more locations as live than the ones
- that are truly live during one particular execution of the
- instruction. Thus, we can take the union of the live-before sets from
- the following instruction and from the mapping for $\itm{label}$ in
- \racket{\code{label->live}}\python{\code{live\_before\_block}}.
- The auxiliary functions for computing the variables in an
- instruction's argument and for computing the variables read-from ($R$)
- or written-to ($W$) by an instruction need to be updated to handle the
- new kinds of arguments and instructions in \LangXIfVar{}.
- \begin{exercise}\normalfont
- {\if\edition\racketEd
- %
- Update the \code{uncover\_live} pass to apply liveness analysis to
- every basic block in the program.
- %
- Add the following entry to the list of \code{passes} in the
- \code{run-tests.rkt} script.
- \begin{lstlisting}
- (list "uncover_live" uncover_live interp-pseudo-x86-1)
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- %
- Update the \code{uncover\_live} function to perform liveness analysis,
- in reverse topological order, on all of the basic blocks in the
- program.
- %
- \fi}
- % Check that the live-after sets that you generate for
- % example X matches the following... -Jeremy
- \end{exercise}
- \subsection{Build the Interference Graph}
- \label{sec:build-interference-Lif}
- Many of the new instructions in \LangXIfVar{} can be handled in the
- same way as the instructions in \LangXVar{}. Thus, if your code was
- already quite general, it will not need to be changed to handle the
- new instructions. If you code is not general enough, we recommend that
- you change your code to be more general. For example, you can factor
- out the computing of the the read and write sets for each kind of
- instruction into auxiliary functions.
- Note that the \key{movzbq} instruction requires some special care,
- similar to the \key{movq} instruction. See rule number 1 in
- Section~\ref{sec:build-interference}.
- \begin{exercise}\normalfont
- Update the \code{build\_interference} pass for \LangXIfVar{}.
- {\if\edition\racketEd
- Add the following entries to the list of \code{passes} in the
- \code{run-tests.rkt} script.
- \begin{lstlisting}
- (list "build_interference" build_interference interp-pseudo-x86-1)
- (list "allocate_registers" allocate_registers interp-x86-1)
- \end{lstlisting}
- \fi}
- % Check that the interference graph that you generate for
- % example X matches the following graph G... -Jeremy
- \end{exercise}
- \section{Patch Instructions}
- The new instructions \key{cmpq} and \key{movzbq} have some special
- restrictions that need to be handled in the \code{patch\_instructions}
- pass.
- %
- The second argument of the \key{cmpq} instruction must not be an
- immediate value (such as an integer). So if you are comparing two
- immediates, we recommend inserting a \key{movq} instruction to put the
- second argument in \key{rax}. As usual, \key{cmpq} may have at most
- one memory reference.
- %
- The second argument of the \key{movzbq} must be a register.
- \begin{exercise}\normalfont
- %
- Update \code{patch\_instructions} pass for \LangXIfVar{}.
- %
- {\if\edition\racketEd
- Add the following entry to the list of \code{passes} in
- \code{run-tests.rkt} and then run this script to test your compiler.
- \begin{lstlisting}
- (list "patch_instructions" patch_instructions interp-x86-1)
- \end{lstlisting}
- \fi}
- \end{exercise}
- {\if\edition\pythonEd
-
- \section{Print x86}
- \label{sec:print-x86-cond}
- The generation of the \code{main} function with its prelude and
- conclusion must change to accomodate how the program now consists of
- one or more basic blocks. After the prelude in \code{main}, jump to
- the \code{start} block. Place the conclusion in a basic block labelled
- with \code{conclusion}.
- \fi}
- Figure~\ref{fig:if-example-x86} shows a simple example program in
- \LangIf{} translated to x86, showing the results of
- \code{explicate\_control}, \code{select\_instructions}, and the final
- x86 assembly.
- \begin{figure}[tbp]
- {\if\edition\racketEd
- \begin{tabular}{lll}
- \begin{minipage}{0.4\textwidth}
- % cond_test_20.rkt, eq_input.py
- \begin{lstlisting}
- (if (eq? (read) 1) 42 0)
- \end{lstlisting}
- $\Downarrow$
- \begin{lstlisting}
- start:
- tmp7951 = (read);
- if (eq? tmp7951 1)
- goto block7952;
- else
- goto block7953;
- block7952:
- return 42;
- block7953:
- return 0;
- \end{lstlisting}
- $\Downarrow$
- \begin{lstlisting}
- start:
- callq read_int
- movq %rax, tmp7951
- cmpq $1, tmp7951
- je block7952
- jmp block7953
- block7953:
- movq $0, %rax
- jmp conclusion
- block7952:
- movq $42, %rax
- jmp conclusion
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow\qquad$
- \begin{minipage}{0.4\textwidth}
- \begin{lstlisting}
- start:
- callq read_int
- movq %rax, %rcx
- cmpq $1, %rcx
- je block7952
- jmp block7953
- block7953:
- movq $0, %rax
- jmp conclusion
- block7952:
- movq $42, %rax
- jmp conclusion
- .globl main
- main:
- pushq %rbp
- movq %rsp, %rbp
- pushq %r13
- pushq %r12
- pushq %rbx
- pushq %r14
- subq $0, %rsp
- jmp start
- conclusion:
- addq $0, %rsp
- popq %r14
- popq %rbx
- popq %r12
- popq %r13
- popq %rbp
- retq
- \end{lstlisting}
- \end{minipage}
- \end{tabular}
- \fi}
- {\if\edition\pythonEd
- \begin{tabular}{lll}
- \begin{minipage}{0.4\textwidth}
- % cond_test_20.rkt, eq_input.py
- \begin{lstlisting}
- print(42 if input_int() == 1 else 0)
- \end{lstlisting}
- $\Downarrow$
- \begin{lstlisting}
- start:
- tmp_0 = input_int()
- if tmp_0 == 1:
- goto block_3
- else:
- goto block_4
- block_3:
- tmp_1 = 42
- goto block_2
- block_4:
- tmp_1 = 0
- goto block_2
- block_2:
- print(tmp_1)
- return 0
- \end{lstlisting}
- $\Downarrow$
- \begin{lstlisting}
- start:
- callq read_int
- movq %rax, tmp_0
- cmpq 1, tmp_0
- je block_3
- jmp block_4
- block_3:
- movq 42, tmp_1
- jmp block_2
- block_4:
- movq 0, tmp_1
- jmp block_2
- block_2:
- movq tmp_1, %rdi
- callq print_int
- movq 0, %rax
- jmp conclusion
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow\qquad$
- \begin{minipage}{0.4\textwidth}
- \begin{lstlisting}
- .globl main
- main:
- pushq %rbp
- movq %rsp, %rbp
- subq $0, %rsp
- jmp start
- start:
- callq read_int
- movq %rax, %rcx
- cmpq $1, %rcx
- je block_3
- jmp block_4
- block_3:
- movq $42, %rcx
- jmp block_2
- block_4:
- movq $0, %rcx
- jmp block_2
- block_2:
- movq %rcx, %rdi
- callq print_int
- movq $0, %rax
- jmp conclusion
- conclusion:
- addq $0, %rsp
- popq %rbp
- retq
- \end{lstlisting}
- \end{minipage}
- \end{tabular}
- \fi}
- \caption{Example compilation of an \key{if} expression to x86, showing
- the results of \code{explicate\_control},
- \code{select\_instructions}, and the final x86 assembly code. }
- \label{fig:if-example-x86}
- \end{figure}
- \begin{figure}[tbp]
- {\if\edition\racketEd
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (Lif) at (0,2) {\large \LangIf{}};
- \node (Lif-2) at (3,2) {\large \LangIf{}};
- \node (Lif-3) at (6,2) {\large \LangIf{}};
- \node (Lif-4) at (9,2) {\large \LangIf{}};
- \node (Lif-5) at (12,2) {\large \LangIf{}};
- \node (C1-1) at (3,0) {\large \LangCIf{}};
- \node (x86-2) at (3,-2) {\large \LangXIfVar{}};
- \node (x86-2-1) at (3,-4) {\large \LangXIfVar{}};
- \node (x86-2-2) at (6,-4) {\large \LangXIfVar{}};
- \node (x86-3) at (6,-2) {\large \LangXIfVar{}};
- \node (x86-4) at (9,-2) {\large \LangXIf{}};
- \node (x86-5) at (9,-4) {\large \LangXIf{}};
- \path[->,bend left=15] (Lif) edge [above] node {\ttfamily\footnotesize type\_check} (Lif-2);
- \path[->,bend left=15] (Lif-2) edge [above] node {\ttfamily\footnotesize shrink} (Lif-3);
- \path[->,bend left=15] (Lif-3) edge [above] node {\ttfamily\footnotesize uniquify} (Lif-4);
- \path[->,bend left=15] (Lif-4) edge [above] node {\ttfamily\footnotesize remove\_complex.} (Lif-5);
- \path[->,bend left=15] (Lif-5) edge [left] node {\ttfamily\footnotesize explicate\_control} (C1-1);
- \path[->,bend right=15] (C1-1) edge [left] node {\ttfamily\footnotesize select\_instructions} (x86-2);
- \path[->,bend left=15] (x86-2) edge [right] node {\ttfamily\footnotesize uncover\_live} (x86-2-1);
- \path[->,bend right=15] (x86-2-1) edge [below] node {\ttfamily\footnotesize build\_inter.} (x86-2-2);
- \path[->,bend right=15] (x86-2-2) edge [right] node {\ttfamily\footnotesize allocate\_reg.} (x86-3);
- \path[->,bend left=15] (x86-3) edge [above] node {\ttfamily\footnotesize patch\_instr.} (x86-4);
- \path[->,bend left=15] (x86-4) edge [right] node {\ttfamily\footnotesize print\_x86 } (x86-5);
- \end{tikzpicture}
- \fi}
- {\if\edition\pythonEd
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (Lif-1) at (0,2) {\large \LangIf{}};
- \node (Lif-2) at (3,2) {\large \LangIf{}};
- \node (Lif-3) at (6,2) {\large \LangIf{}};
- \node (C-1) at (3,0) {\large \LangCIf{}};
- \node (x86-1) at (3,-2) {\large \LangXIfVar{}};
- \node (x86-2) at (6,-2) {\large \LangXIfVar{}};
- \node (x86-3) at (9,-2) {\large \LangXIf{}};
- \node (x86-4) at (12,-2) {\large \LangXIf{}};
- \path[->,bend left=15] (Lif-1) edge [above] node {\ttfamily\footnotesize shrink} (Lif-2);
- \path[->,bend left=15] (Lif-2) edge [above] node {\ttfamily\footnotesize remove\_complex.} (Lif-3);
- \path[->,bend left=15] (Lif-3) edge [right] node {\ttfamily\footnotesize explicate\_control} (C-1);
- \path[->,bend right=15] (C-1) edge [left] node {\ttfamily\footnotesize select\_instr.} (x86-1);
- \path[->,bend right=15] (x86-1) edge [below] node {\ttfamily\footnotesize assign\_homes} (x86-2);
- \path[->,bend left=15] (x86-2) edge [above] node {\ttfamily\footnotesize patch\_instr.} (x86-3);
- \path[->,bend right=15] (x86-3) edge [below] node {\ttfamily\footnotesize print\_x86 } (x86-4);
- \end{tikzpicture}
- \fi}
- \caption{Diagram of the passes for \LangIf{}, a language with conditionals.}
- \label{fig:Lif-passes}
- \end{figure}
- Figure~\ref{fig:Lif-passes} lists all the passes needed for the
- compilation of \LangIf{}.
- \section{Challenge: Optimize Blocks and Remove Jumps}
- \label{sec:opt-jumps}
- We discuss two optional challenges that involve optimizing the
- control-flow of the program.
- \subsection{Optimize Blocks}
- The algorithm for \code{explicate\_control} that we discussed in
- Section~\ref{sec:explicate-control-Lif} sometimes generates too many
- blocks. It does so in two different ways.
- %
- First, recall how in Figure~\ref{fig:explicate-control-s1-38},
- \code{block\_4} consists of just a jump to \code{block\_2}. We created
- a new basic block from a single \code{goto} statement, whereas we
- could have simply returned the \code{goto} statement. We can solve
- this problem by modifying the \code{create\_block} function to
- recognize this situation.
- Second, \code{explicate\_control} creates a basic block whenever a
- continuation \emph{might} get used more than once (wheneven a
- continuation is passed into two or more recursive calls). However,
- just because a continuation might get used more than once, doesn't
- mean it will. In fact, some continuation parameters may not be used
- at all because we sometimes ignore them. For example, consider the
- case for the constant \TRUE{} in \code{explicate\_pred}, where we
- discard the \code{els} branch. So the question is how can we decide
- whether to create a basic block?
- The solution to this conundrum is to use \emph{lazy
- evaluation}\index{subject}{lazy evaluation}~\citep{Friedman:1976aa}
- to delay creating a basic block until the point in time where we know
- it will be used.
- %
- {\if\edition\racketEd
- %
- Racket provides support for
- lazy evaluation with the
- \href{https://docs.racket-lang.org/reference/Delayed_Evaluation.html}{\code{racket/promise}}
- package. The expression \key{(delay} $e_1 \ldots e_n$\key{)}
- \index{subject}{delay} creates a
- \emph{promise}\index{subject}{promise} in which the evaluation of the
- expressions is postponed. When \key{(force}
- $p$\key{)}\index{subject}{force} is applied to a promise $p$ for the
- first time, the expressions $e_1 \ldots e_n$ are evaluated and the
- result of $e_n$ is cached in the promise and returned. If \code{force}
- is applied again to the same promise, then the cached result is
- returned. If \code{force} is applied to an argument that is not a
- promise, \code{force} simply returns the argument.
- %
- \fi}
- %
- {\if\edition\pythonEd
- %
- While Python does not provide direct support for lazy evaluation, it
- is easy to mimic. We can \emph{delay} the evaluation of a computation
- by wrapping it inside a function with no parameters. We can
- \emph{force} its evaluation by calling the function. However, in some
- cases of \code{explicate\_pred}, etc., we will return a list of
- statements and in other cases we will return a function that computes
- a list of statements. We use the term \emph{promise} to refer to a
- value that may or may not be delayed. To uniformly deal with
- promises, we define the following \code{force} function that checks
- whether its input is delayed (i.e. whether it is a function) and then
- either 1) calls the function, or 2) returns the input.
- \begin{lstlisting}
- def force(promise):
- if isinstance(promise, types.FunctionType):
- return promise()
- else:
- return promise
- \end{lstlisting}
- %
- \fi}
- We use promises for the input and output of the functions
- \code{explicate\_pred}, \code{explicate\_assign},
- %
- \racket{ and \code{explicate\_tail}}\python{ \code{explicate\_effect}, and \code{explicate\_stmt}}.
- %
- So instead of taking and returning lists of statments, they take and
- return promises. Furthermore, when we come to a situation in which a
- continuation might be used more than once, as in the case for
- \code{if} in \code{explicate\_pred}, we create a delayed computation
- that creates a basic block for each continuation (if there is not
- already one) and then returns a \code{goto} statement to that basic
- block.
- %
- {\if\edition\racketEd
- %
- The following auxiliary function named \code{create\_block} accomplishes
- this task. It begins with \code{delay} to create a promise. When
- forced, this promise will force the original promise. If that returns
- a \code{goto} (because the block was already added to the control-flow
- graph), then we return the \code{goto}. Otherwise we add the block to
- the control-flow graph with another auxiliary function named
- \code{add-node}. That function returns the label for the new block,
- which we use to create a \code{goto}.
- \begin{lstlisting}
- (define (create_block block)
- (delay
- (define b (force block))
- (match b
- [(Goto label) (Goto label)]
- [else (Goto (add-node b))])))
- \end{lstlisting}
- \fi}
- {\if\edition\pythonEd
- %
- Here's the new version of the \code{create\_block} auxiliary function
- that works on promises and that checks whether the block consists of a
- solitary \code{goto} statement.\\
- \begin{minipage}{\textwidth}
- \begin{lstlisting}
- def create_block(promise, basic_blocks):
- stmts = force(promise)
- match stmts:
- case [Goto(l)]:
- return Goto(l)
- case _:
- label = label_name(generate_name('block'))
- basic_blocks[label] = stmts
- return Goto(label)
- \end{lstlisting}
- \end{minipage}
- \fi}
- Figure~\ref{fig:explicate-control-challenge} shows the output of
- \code{explicate\_control} on the example of the nested \code{if}
- expressions with the two improvements discussed above. As you can
- see, the number of basic blocks has been reduced from 10 blocks (see
- Figure~\ref{fig:explicate-control-s1-38}) down to 6 blocks.
- \begin{figure}[tbp]
- {\if\edition\racketEd
- \begin{tabular}{lll}
- \begin{minipage}{0.4\textwidth}
- % cond_test_41.rkt
- \begin{lstlisting}
- (let ([x (read)])
- (let ([y (read)])
- (if (if (< x 1)
- (eq? x 0)
- (eq? x 2))
- (+ y 2)
- (+ y 10))))
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow$
- &
- \begin{minipage}{0.55\textwidth}
- \begin{lstlisting}
- start:
- x = (read);
- y = (read);
- if (< x 1) goto block40;
- else goto block41;
- block40:
- if (eq? x 0) goto block38;
- else goto block39;
- block41:
- if (eq? x 2) goto block38;
- else goto block39;
- block38:
- return (+ y 2);
- block39:
- return (+ y 10);
- \end{lstlisting}
- \end{minipage}
- \end{tabular}
- \fi}
- {\if\edition\pythonEd
- \begin{tabular}{lll}
- \begin{minipage}{0.4\textwidth}
- % cond_test_41.rkt
- \begin{lstlisting}
- x = input_int()
- y = input_int()
- print(y + 2 \
- if (x == 0 \
- if x < 1 \
- else x == 2) \
- else y + 10)
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow$
- &
- \begin{minipage}{0.55\textwidth}
- \begin{lstlisting}
- start:
- x = input_int()
- y = input_int()
- if x < 1:
- goto block_4
- else:
- goto block_5
- block_4:
- if x == 0:
- goto block_2
- else:
- goto block_3
- block_5:
- if x == 2:
- goto block_2
- else:
- goto block_3
- block_2:
- tmp_0 = y + 2
- goto block_1
- block_3:
- tmp_0 = y + 10
- goto block_1
- block_1:
- print(tmp_0)
- return 0
- \end{lstlisting}
- \end{minipage}
- \end{tabular}
- \fi}
- \caption{Translation from \LangIf{} to \LangCIf{}
- via the improved \code{explicate\_control}.}
- \label{fig:explicate-control-challenge}
- \end{figure}
- %% Recall that in the example output of \code{explicate\_control} in
- %% Figure~\ref{fig:explicate-control-s1-38}, \code{block57} through
- %% \code{block60} are trivial blocks, they do nothing but jump to another
- %% block. The first goal of this challenge assignment is to remove those
- %% blocks. Figure~\ref{fig:optimize-jumps} repeats the result of
- %% \code{explicate\_control} on the left and shows the result of bypassing
- %% the trivial blocks on the right. Let us focus on \code{block61}. The
- %% \code{then} branch jumps to \code{block57}, which in turn jumps to
- %% \code{block55}. The optimized code on the right of
- %% Figure~\ref{fig:optimize-jumps} bypasses \code{block57}, with the
- %% \code{then} branch jumping directly to \code{block55}. The story is
- %% similar for the \code{else} branch, as well as for the two branches in
- %% \code{block62}. After the jumps in \code{block61} and \code{block62}
- %% have been optimized in this way, there are no longer any jumps to
- %% blocks \code{block57} through \code{block60}, so they can be removed.
- %% \begin{figure}[tbp]
- %% \begin{tabular}{lll}
- %% \begin{minipage}{0.4\textwidth}
- %% \begin{lstlisting}
- %% block62:
- %% tmp54 = (read);
- %% if (eq? tmp54 2) then
- %% goto block59;
- %% else
- %% goto block60;
- %% block61:
- %% tmp53 = (read);
- %% if (eq? tmp53 0) then
- %% goto block57;
- %% else
- %% goto block58;
- %% block60:
- %% goto block56;
- %% block59:
- %% goto block55;
- %% block58:
- %% goto block56;
- %% block57:
- %% goto block55;
- %% block56:
- %% return (+ 700 77);
- %% block55:
- %% return (+ 10 32);
- %% start:
- %% tmp52 = (read);
- %% if (eq? tmp52 1) then
- %% goto block61;
- %% else
- %% goto block62;
- %% \end{lstlisting}
- %% \end{minipage}
- %% &
- %% $\Rightarrow$
- %% &
- %% \begin{minipage}{0.55\textwidth}
- %% \begin{lstlisting}
- %% block62:
- %% tmp54 = (read);
- %% if (eq? tmp54 2) then
- %% goto block55;
- %% else
- %% goto block56;
- %% block61:
- %% tmp53 = (read);
- %% if (eq? tmp53 0) then
- %% goto block55;
- %% else
- %% goto block56;
- %% block56:
- %% return (+ 700 77);
- %% block55:
- %% return (+ 10 32);
- %% start:
- %% tmp52 = (read);
- %% if (eq? tmp52 1) then
- %% goto block61;
- %% else
- %% goto block62;
- %% \end{lstlisting}
- %% \end{minipage}
- %% \end{tabular}
- %% \caption{Optimize jumps by removing trivial blocks.}
- %% \label{fig:optimize-jumps}
- %% \end{figure}
- %% The name of this pass is \code{optimize-jumps}. We recommend
- %% implementing this pass in two phases. The first phrase builds a hash
- %% table that maps labels to possibly improved labels. The second phase
- %% changes the target of each \code{goto} to use the improved label. If
- %% the label is for a trivial block, then the hash table should map the
- %% label to the first non-trivial block that can be reached from this
- %% label by jumping through trivial blocks. If the label is for a
- %% non-trivial block, then the hash table should map the label to itself;
- %% we do not want to change jumps to non-trivial blocks.
- %% The first phase can be accomplished by constructing an empty hash
- %% table, call it \code{short-cut}, and then iterating over the control
- %% flow graph. Each time you encouter a block that is just a \code{goto},
- %% then update the hash table, mapping the block's source to the target
- %% of the \code{goto}. Also, the hash table may already have mapped some
- %% labels to the block's source, to you must iterate through the hash
- %% table and update all of those so that they instead map to the target
- %% of the \code{goto}.
- %% For the second phase, we recommend iterating through the $\Tail$ of
- %% each block in the program, updating the target of every \code{goto}
- %% according to the mapping in \code{short-cut}.
- \begin{exercise}\normalfont
- Implement the improvements to the \code{explicate\_control} pass.
- Check that it removes trivial blocks in a few example programs. Then
- check that your compiler still passes all of your tests.
- \end{exercise}
- \subsection{Remove Jumps}
- There is an opportunity for removing jumps that is apparent in the
- example of Figure~\ref{fig:if-example-x86}. The \code{start} block
- ends with a jump to \code{block\_4} and there are no other jumps to
- \code{block\_4} in the rest of the program. In this situation we can
- avoid the runtime overhead of this jump by merging \code{block\_4}
- into the preceding block, in this case the \code{start} block.
- Figure~\ref{fig:remove-jumps} shows the output of
- \code{select\_instructions} on the left and the result of this
- optimization on the right.
- \begin{figure}[tbp]
- {\if\edition\racketEd
- \begin{tabular}{lll}
- \begin{minipage}{0.5\textwidth}
- % cond_test_20.rkt
- \begin{lstlisting}
- start:
- callq read_int
- movq %rax, tmp7951
- cmpq $1, tmp7951
- je block7952
- jmp block7953
- block7953:
- movq $0, %rax
- jmp conclusion
- block7952:
- movq $42, %rax
- jmp conclusion
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow\qquad$
- \begin{minipage}{0.4\textwidth}
- \begin{lstlisting}
- start:
- callq read_int
- movq %rax, tmp7951
- cmpq $1, tmp7951
- je block7952
- movq $0, %rax
- jmp conclusion
- block7952:
- movq $42, %rax
- jmp conclusion
- \end{lstlisting}
- \end{minipage}
- \end{tabular}
- \fi}
- {\if\edition\pythonEd
- \begin{tabular}{lll}
- \begin{minipage}{0.5\textwidth}
- % cond_test_20.rkt
- \begin{lstlisting}
- start:
- callq read_int
- movq %rax, tmp_0
- cmpq 1, tmp_0
- je block_3
- jmp block_4
- block_3:
- movq 42, tmp_1
- jmp block_2
- block_4:
- movq 0, tmp_1
- jmp block_2
- block_2:
- movq tmp_1, %rdi
- callq print_int
- movq 0, %rax
- jmp conclusion
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow\qquad$
- \begin{minipage}{0.4\textwidth}
- \begin{lstlisting}
- start:
- callq read_int
- movq %rax, tmp_0
- cmpq 1, tmp_0
- je block_3
- movq 0, tmp_1
- jmp block_2
- block_3:
- movq 42, tmp_1
- jmp block_2
- block_2:
- movq tmp_1, %rdi
- callq print_int
- movq 0, %rax
- jmp conclusion
- \end{lstlisting}
- \end{minipage}
- \end{tabular}
- \fi}
- \caption{Merging basic blocks by removing unnecessary jumps.}
- \label{fig:remove-jumps}
- \end{figure}
- \begin{exercise}\normalfont
- %
- Implement a pass named \code{remove\_jumps} that merges basic blocks
- into their preceding basic block, when there is only one preceding
- block. The pass should translate from \LangXIfVar{} to \LangXIfVar{}.
- %
- {\if\edition\racketEd
- In the \code{run-tests.rkt} script, add the following entry to the
- list of \code{passes} between \code{allocate\_registers}
- and \code{patch\_instructions}.
- \begin{lstlisting}
- (list "remove-jumps" remove-jumps interp-pseudo-x86-1)
- \end{lstlisting}
- \fi}
- %
- Run the script to test your compiler.
- %
- Check that \code{remove\_jumps} accomplishes the goal of merging basic
- blocks on several test programs.
- \end{exercise}
- \section{Further Reading}
- \label{sec:cond-further-reading}
- The algorithm for the \code{explicate\_control} pass comes from the
- course notes of \citet{Dybvig:2010aa}. The use of lazy evaluation in
- Section~\ref{sec:opt-jumps} to optimize basic blocks is new. There
- are algorithms similar to \code{explicate\_control} in the literature,
- such as the case-of-case transformation of \citet{PeytonJones:1998}.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- \chapter{Loops and Dataflow Analysis}
- \label{ch:Rwhile}
- % TODO: define R'_8
- % TODO: multi-graph
- \if\edition\racketEd
- In this chapter we study two features that are the hallmarks of
- imperative programming languages: loops and assignments to local
- variables. The following example demonstrates these new features by
- computing the sum of the first five positive integers.
- % similar to loop_test_1.rkt
- \begin{lstlisting}
- (let ([sum 0])
- (let ([i 5])
- (begin
- (while (> i 0)
- (begin
- (set! sum (+ sum i))
- (set! i (- i 1))))
- sum)))
- \end{lstlisting}
- The \code{while} loop consists of a condition and a body.
- %
- The \code{set!} consists of a variable and a right-hand-side expression.
- %
- The primary purpose of both the \code{while} loop and \code{set!} is
- to cause side effects, so it is convenient to also include in a
- language feature for sequencing side effects: the \code{begin}
- expression. It consists of one or more subexpressions that are
- evaluated left-to-right.
- \section{The \LangLoop{} Language}
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Exp &::=& \gray{ \Int \MID \CREAD{} \MID \CNEG{\Exp}
- \MID \CADD{\Exp}{\Exp} \MID \CSUB{\Exp}{\Exp} } \\
- &\MID& \gray{ \Var \MID \CLET{\Var}{\Exp}{\Exp} }\\
- &\MID& \gray{\key{\#t} \MID \key{\#f}
- \MID (\key{and}\;\Exp\;\Exp)
- \MID (\key{or}\;\Exp\;\Exp)
- \MID (\key{not}\;\Exp) } \\
- &\MID& \gray{ (\key{eq?}\;\Exp\;\Exp) \MID \CIF{\Exp}{\Exp}{\Exp} } \\
- &\MID& \gray{ (\key{vector}\;\Exp\ldots) \MID
- (\key{vector-ref}\;\Exp\;\Int)} \\
- &\MID& \gray{(\key{vector-set!}\;\Exp\;\Int\;\Exp)\MID (\key{void})
- \MID (\Exp \; \Exp\ldots) } \\
- &\MID& \gray{ \LP \key{procedure-arity}~\Exp\RP
- \MID \CLAMBDA{\LP\LS\Var \key{:} \Type\RS\ldots\RP}{\Type}{\Exp} } \\
- &\MID& \CSETBANG{\Var}{\Exp}
- \MID \CBEGIN{\Exp\ldots}{\Exp}
- \MID \CWHILE{\Exp}{\Exp} \\
- \Def &::=& \gray{ \CDEF{\Var}{\LS\Var \key{:} \Type\RS\ldots}{\Type}{\Exp} } \\
- \LangLoopM{} &::=& \gray{\Def\ldots \; \Exp}
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The concrete syntax of \LangLoop{}, extending \LangAny{} (Figure~\ref{fig:Rany-concrete-syntax}).}
- \label{fig:Rwhile-concrete-syntax}
- \end{figure}
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Exp &::=& \gray{ \INT{\Int} \VAR{\Var} \MID \LET{\Var}{\Exp}{\Exp} } \\
- &\MID& \gray{ \PRIM{\itm{op}}{\Exp\ldots} }\\
- &\MID& \gray{ \BOOL{\itm{bool}}
- \MID \IF{\Exp}{\Exp}{\Exp} } \\
- &\MID& \gray{ \VOID{} \MID \LP\key{HasType}~\Exp~\Type \RP
- \MID \APPLY{\Exp}{\Exp\ldots} }\\
- &\MID& \gray{ \LAMBDA{\LP\LS\Var\code{:}\Type\RS\ldots\RP}{\Type}{\Exp} }\\
- &\MID& \SETBANG{\Var}{\Exp} \MID \BEGIN{\LP\Exp\ldots\RP}{\Exp}
- \MID \WHILE{\Exp}{\Exp} \\
- \Def &::=& \gray{ \FUNDEF{\Var}{\LP\LS\Var \code{:} \Type\RS\ldots\RP}{\Type}{\code{'()}}{\Exp} }\\
- \LangLoopM{} &::=& \gray{ \PROGRAMDEFSEXP{\code{'()}}{\LP\Def\ldots\RP}{\Exp} }
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The abstract syntax of \LangLoop{}, extending \LangAny{} (Figure~\ref{fig:Rany-syntax}).}
- \label{fig:Rwhile-syntax}
- \end{figure}
- The concrete syntax of \LangLoop{} is defined in
- Figure~\ref{fig:Rwhile-concrete-syntax} and its abstract syntax is defined
- in Figure~\ref{fig:Rwhile-syntax}.
- %
- The definitional interpreter for \LangLoop{} is shown in
- Figure~\ref{fig:interp-Rwhile}. We add three new cases for \code{SetBang},
- \code{WhileLoop}, and \code{Begin} and we make changes to the cases
- for \code{Var}, \code{Let}, and \code{Apply} regarding variables. To
- support assignment to variables and to make their lifetimes indefinite
- (see the second example in Section~\ref{sec:assignment-scoping}), we
- box the value that is bound to each variable (in \code{Let}) and
- function parameter (in \code{Apply}). The case for \code{Var} unboxes
- the value.
- %
- Now to discuss the new cases. For \code{SetBang}, we lookup the
- variable in the environment to obtain a boxed value and then we change
- it using \code{set-box!} to the result of evaluating the right-hand
- side. The result value of a \code{SetBang} is \code{void}.
- %
- For the \code{WhileLoop}, we repeatedly 1) evaluate the condition, and
- if the result is true, 2) evaluate the body.
- The result value of a \code{while} loop is also \code{void}.
- %
- Finally, the $\BEGIN{\itm{es}}{\itm{body}}$ expression evaluates the
- subexpressions \itm{es} for their effects and then evaluates
- and returns the result from \itm{body}.
- \begin{figure}[tbp]
- \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
- (define interp-Rwhile_class
- (class interp-Rany_class
- (super-new)
- (define/override ((interp-exp env) e)
- (define recur (interp-exp env))
- (match e
- [(SetBang x rhs)
- (set-box! (lookup x env) (recur rhs))]
- [(WhileLoop cnd body)
- (define (loop)
- (cond [(recur cnd) (recur body) (loop)]
- [else (void)]))
- (loop)]
- [(Begin es body)
- (for ([e es]) (recur e))
- (recur body)]
- [else ((super interp-exp env) e)]))
- ))
- (define (interp-Rwhile p)
- (send (new interp-Rwhile_class) interp-program p))
- \end{lstlisting}
- \caption{Interpreter for \LangLoop{}.}
- \label{fig:interp-Rwhile}
- \end{figure}
- The type checker for \LangLoop{} is define in
- Figure~\ref{fig:type-check-Rwhile}. For \code{SetBang}, the type of the
- variable and the right-hand-side must agree. The result type is
- \code{Void}. For the \code{WhileLoop}, the condition must be a
- \code{Boolean}. The result type is also \code{Void}. For
- \code{Begin}, the result type is the type of its last subexpression.
- \begin{figure}[tbp]
- \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
- (define type-check-Rwhile_class
- (class type-check-Rany_class
- (super-new)
- (inherit check-type-equal?)
- (define/override (type-check-exp env)
- (lambda (e)
- (define recur (type-check-exp env))
- (match e
- [(SetBang x rhs)
- (define-values (rhs^ rhsT) (recur rhs))
- (define varT (dict-ref env x))
- (check-type-equal? rhsT varT e)
- (values (SetBang x rhs^) 'Void)]
- [(WhileLoop cnd body)
- (define-values (cnd^ Tc) (recur cnd))
- (check-type-equal? Tc 'Boolean e)
- (define-values (body^ Tbody) ((type-check-exp env) body))
- (values (WhileLoop cnd^ body^) 'Void)]
- [(Begin es body)
- (define-values (es^ ts)
- (for/lists (l1 l2) ([e es]) (recur e)))
- (define-values (body^ Tbody) (recur body))
- (values (Begin es^ body^) Tbody)]
- [else ((super type-check-exp env) e)])))
- ))
- (define (type-check-Rwhile p)
- (send (new type-check-Rwhile_class) type-check-program p))
- \end{lstlisting}
- \caption{Type checking \key{SetBang}, \key{WhileLoop},
- and \code{Begin} in \LangLoop{}.}
- \label{fig:type-check-Rwhile}
- \end{figure}
-
- At first glance, the translation of these language features to x86
- seems straightforward because the \LangCFun{} intermediate language
- already supports all of the ingredients that we need: assignment,
- \code{goto}, conditional branching, and sequencing. However, there are
- complications that arise which we discuss in the next section. After
- that we introduce the changes necessary to the existing passes.
- \section{Cyclic Control Flow and Dataflow Analysis}
- \label{sec:dataflow-analysis}
- Up until this point the control-flow graphs generated in
- \code{explicate\_control} were guaranteed to be acyclic. However, each
- \code{while} loop introduces a cycle in the control-flow graph.
- But does that matter?
- %
- Indeed it does. Recall that for register allocation, the compiler
- performs liveness analysis to determine which variables can share the
- same register. In Section~\ref{sec:liveness-analysis-Lif} we analyze
- the control-flow graph in reverse topological order, but topological
- order is only well-defined for acyclic graphs.
- Let us return to the example of computing the sum of the first five
- positive integers. Here is the program after instruction selection but
- before register allocation.
- \begin{center}
- \begin{minipage}{0.45\textwidth}
- \begin{lstlisting}
- (define (main) : Integer
- mainstart:
- movq $0, sum1
- movq $5, i2
- jmp block5
- block5:
- movq i2, tmp3
- cmpq tmp3, $0
- jl block7
- jmp block8
- \end{lstlisting}
- \end{minipage}
- \begin{minipage}{0.45\textwidth}
- \begin{lstlisting}
-
- block7:
- addq i2, sum1
- movq $1, tmp4
- negq tmp4
- addq tmp4, i2
- jmp block5
- block8:
- movq $27, %rax
- addq sum1, %rax
- jmp mainconclusion
- )
- \end{lstlisting}
- \end{minipage}
- \end{center}
- Recall that liveness analysis works backwards, starting at the end
- of each function. For this example we could start with \code{block8}
- because we know what is live at the beginning of the conclusion,
- just \code{rax} and \code{rsp}. So the live-before set
- for \code{block8} is $\{\ttm{rsp},\ttm{sum1}\}$.
- %
- Next we might try to analyze \code{block5} or \code{block7}, but
- \code{block5} jumps to \code{block7} and vice versa, so it seems that
- we are stuck.
- The way out of this impasse comes from the realization that one can
- perform liveness analysis starting with an empty live-after set to
- compute an under-approximation of the live-before set. By
- \emph{under-approximation}, we mean that the set only contains
- variables that are really live, but it may be missing some. Next, the
- under-approximations for each block can be improved by 1) updating the
- live-after set for each block using the approximate live-before sets
- from the other blocks and 2) perform liveness analysis again on each
- block. In fact, by iterating this process, the under-approximations
- eventually become the correct solutions!
- %
- This approach of iteratively analyzing a control-flow graph is
- applicable to many static analysis problems and goes by the name
- \emph{dataflow analysis}\index{subject}{dataflow analysis}. It was invented by
- \citet{Kildall:1973vn} in his Ph.D. thesis at the University of
- Washington.
- Let us apply this approach to the above example. We use the empty set
- for the initial live-before set for each block. Let $m_0$ be the
- following mapping from label names to sets of locations (variables and
- registers).
- \begin{center}
- \begin{lstlisting}
- mainstart: {}
- block5: {}
- block7: {}
- block8: {}
- \end{lstlisting}
- \end{center}
- Using the above live-before approximations, we determine the
- live-after for each block and then apply liveness analysis to each
- block. This produces our next approximation $m_1$ of the live-before
- sets.
- \begin{center}
- \begin{lstlisting}
- mainstart: {}
- block5: {i2}
- block7: {i2, sum1}
- block8: {rsp, sum1}
- \end{lstlisting}
- \end{center}
- For the second round, the live-after for \code{mainstart} is the
- current live-before for \code{block5}, which is \code{\{i2\}}. So the
- liveness analysis for \code{mainstart} computes the empty set. The
- live-after for \code{block5} is the union of the live-before sets for
- \code{block7} and \code{block8}, which is \code{\{i2 , rsp, sum1\}}.
- So the liveness analysis for \code{block5} computes \code{\{i2 , rsp,
- sum1\}}. The live-after for \code{block7} is the live-before for
- \code{block5} (from the previous iteration), which is \code{\{i2\}}.
- So the liveness analysis for \code{block7} remains \code{\{i2,
- sum1\}}. Together these yield the following approximation $m_2$ of
- the live-before sets.
- \begin{center}
- \begin{lstlisting}
- mainstart: {}
- block5: {i2, rsp, sum1}
- block7: {i2, sum1}
- block8: {rsp, sum1}
- \end{lstlisting}
- \end{center}
- In the preceding iteration, only \code{block5} changed, so we can
- limit our attention to \code{mainstart} and \code{block7}, the two
- blocks that jump to \code{block5}. As a result, the live-before sets
- for \code{mainstart} and \code{block7} are updated to include
- \code{rsp}, yielding the following approximation $m_3$.
- \begin{center}
- \begin{lstlisting}
- mainstart: {rsp}
- block5: {i2, rsp, sum1}
- block7: {i2, rsp, sum1}
- block8: {rsp, sum1}
- \end{lstlisting}
- \end{center}
- Because \code{block7} changed, we analyze \code{block5} once more, but
- its live-before set remains \code{\{ i2, rsp, sum1 \}}. At this point
- our approximations have converged, so $m_3$ is the solution.
- This iteration process is guaranteed to converge to a solution by the
- Kleene Fixed-Point Theorem, a general theorem about functions on
- lattices~\citep{Kleene:1952aa}. Roughly speaking, a \emph{lattice} is
- any collection that comes with a partial ordering $\sqsubseteq$ on its
- elements, a least element $\bot$ (pronounced bottom), and a join
- operator $\sqcup$.\index{subject}{lattice}\index{subject}{bottom}\index{subject}{partial
- ordering}\index{subject}{join}\footnote{Technically speaking, we will be
- working with join semi-lattices.} When two elements are ordered $m_i
- \sqsubseteq m_j$, it means that $m_j$ contains at least as much
- information as $m_i$, so we can think of $m_j$ as a better-or-equal
- approximation than $m_i$. The bottom element $\bot$ represents the
- complete lack of information, i.e., the worst approximation. The join
- operator takes two lattice elements and combines their information,
- i.e., it produces the least upper bound of the two.\index{subject}{least upper
- bound}
- A dataflow analysis typically involves two lattices: one lattice to
- represent abstract states and another lattice that aggregates the
- abstract states of all the blocks in the control-flow graph. For
- liveness analysis, an abstract state is a set of locations. We form
- the lattice $L$ by taking its elements to be sets of locations, the
- ordering to be set inclusion ($\subseteq$), the bottom to be the empty
- set, and the join operator to be set union.
- %
- We form a second lattice $M$ by taking its elements to be mappings
- from the block labels to sets of locations (elements of $L$). We
- order the mappings point-wise, using the ordering of $L$. So given any
- two mappings $m_i$ and $m_j$, $m_i \sqsubseteq_M m_j$ when $m_i(\ell)
- \subseteq m_j(\ell)$ for every block label $\ell$ in the program. The
- bottom element of $M$ is the mapping $\bot_M$ that sends every label
- to the empty set, i.e., $\bot_M(\ell) = \emptyset$.
- We can think of one iteration of liveness analysis as being a function
- $f$ on the lattice $M$. It takes a mapping as input and computes a new
- mapping.
- \[
- f(m_i) = m_{i+1}
- \]
- Next let us think for a moment about what a final solution $m_s$
- should look like. If we perform liveness analysis using the solution
- $m_s$ as input, we should get $m_s$ again as the output. That is, the
- solution should be a \emph{fixed point} of the function $f$.\index{subject}{fixed point}
- \[
- f(m_s) = m_s
- \]
- Furthermore, the solution should only include locations that are
- forced to be there by performing liveness analysis on the program, so
- the solution should be the \emph{least} fixed point.\index{subject}{least fixed point}
- The Kleene Fixed-Point Theorem states that if a function $f$ is
- monotone (better inputs produce better outputs), then the least fixed
- point of $f$ is the least upper bound of the \emph{ascending Kleene
- chain} obtained by starting at $\bot$ and iterating $f$ as
- follows.\index{subject}{Kleene Fixed-Point Theorem}
- \[
- \bot \sqsubseteq f(\bot) \sqsubseteq f(f(\bot)) \sqsubseteq \cdots
- \sqsubseteq f^n(\bot) \sqsubseteq \cdots
- \]
- When a lattice contains only finitely-long ascending chains, then
- every Kleene chain tops out at some fixed point after a number of
- iterations of $f$. So that fixed point is also a least upper
- bound of the chain.
- \[
- \bot \sqsubseteq f(\bot) \sqsubseteq f(f(\bot)) \sqsubseteq \cdots
- \sqsubseteq f^k(\bot) = f^{k+1}(\bot) = m_s
- \]
- The liveness analysis is indeed a monotone function and the lattice
- $M$ only has finitely-long ascending chains because there are only a
- finite number of variables and blocks in the program. Thus we are
- guaranteed that iteratively applying liveness analysis to all blocks
- in the program will eventually produce the least fixed point solution.
- Next let us consider dataflow analysis in general and discuss the
- generic work list algorithm (Figure~\ref{fig:generic-dataflow}).
- %
- The algorithm has four parameters: the control-flow graph \code{G}, a
- function \code{transfer} that applies the analysis to one block, the
- \code{bottom} and \code{join} operator for the lattice of abstract
- states. The algorithm begins by creating the bottom mapping,
- represented by a hash table. It then pushes all of the nodes in the
- control-flow graph onto the work list (a queue). The algorithm repeats
- the \code{while} loop as long as there are items in the work list. In
- each iteration, a node is popped from the work list and processed. The
- \code{input} for the node is computed by taking the join of the
- abstract states of all the predecessor nodes. The \code{transfer}
- function is then applied to obtain the \code{output} abstract
- state. If the output differs from the previous state for this block,
- the mapping for this block is updated and its successor nodes are
- pushed onto the work list.
- \begin{figure}[tb]
- \begin{lstlisting}
- (define (analyze-dataflow G transfer bottom join)
- (define mapping (make-hash))
- (for ([v (in-vertices G)])
- (dict-set! mapping v bottom))
- (define worklist (make-queue))
- (for ([v (in-vertices G)])
- (enqueue! worklist v))
- (define trans-G (transpose G))
- (while (not (queue-empty? worklist))
- (define node (dequeue! worklist))
- (define input (for/fold ([state bottom])
- ([pred (in-neighbors trans-G node)])
- (join state (dict-ref mapping pred))))
- (define output (transfer node input))
- (cond [(not (equal? output (dict-ref mapping node)))
- (dict-set! mapping node output)
- (for ([v (in-neighbors G node)])
- (enqueue! worklist v))]))
- mapping)
- \end{lstlisting}
- \caption{Generic work list algorithm for dataflow analysis}
- \label{fig:generic-dataflow}
- \end{figure}
- Having discussed the complications that arise from adding support for
- assignment and loops, we turn to discussing the significant changes to
- existing passes.
- \section{Remove Complex Operands}
- \label{sec:rco-loop}
- The three new language forms, \code{while}, \code{set!}, and
- \code{begin} are all complex expressions and their subexpressions are
- allowed to be complex. Figure~\ref{fig:Rfun-anf-syntax} defines the
- output language \LangFunANF{} of this pass.
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{rcl}
- \Atm &::=& \gray{ \INT{\Int} \MID \VAR{\Var} \MID \BOOL{\itm{bool}}
- \MID \VOID{} } \\
- \Exp &::=& \ldots \MID \gray{ \LET{\Var}{\Exp}{\Exp} } \\
- &\MID& \WHILE{\Exp}{\Exp} \MID \SETBANG{\Var}{\Exp}
- \MID \BEGIN{\LP\Exp\ldots\RP}{\Exp} \\
- \Def &::=& \gray{ \FUNDEF{\Var}{([\Var \code{:} \Type]\ldots)}{\Type}{\code{'()}}{\Exp} }\\
- R^{\dagger}_8 &::=& \gray{ \PROGRAMDEFS{\code{'()}}{\Def} }
- \end{array}
- \]
- \end{minipage}
- }
- \caption{\LangLoopANF{} is \LangLoop{} in administrative normal form (ANF).}
- \label{fig:Rwhile-anf-syntax}
- \end{figure}
- As usual, when a complex expression appears in a grammar position that
- needs to be atomic, such as the argument of a primitive operator, we
- must introduce a temporary variable and bind it to the complex
- expression. This approach applies, unchanged, to handle the new
- language forms. For example, in the following code there are two
- \code{begin} expressions appearing as arguments to \code{+}. The
- output of \code{rco\_exp} is shown below, in which the \code{begin}
- expressions have been bound to temporary variables. Recall that
- \code{let} expressions in \LangLoopANF{} are allowed to have
- arbitrary expressions in their right-hand-side expression, so it is
- fine to place \code{begin} there.
- \begin{lstlisting}
- (let ([x0 10])
- (let ([y1 0])
- (+ (+ (begin (set! y1 (read)) x0)
- (begin (set! x0 (read)) y1))
- x0)))
- |$\Rightarrow$|
- (let ([x0 10])
- (let ([y1 0])
- (let ([tmp2 (begin (set! y1 (read)) x0)])
- (let ([tmp3 (begin (set! x0 (read)) y1)])
- (let ([tmp4 (+ tmp2 tmp3)])
- (+ tmp4 x0))))))
- \end{lstlisting}
- \section{Explicate Control and \LangCLoop{}}
- \label{sec:explicate-loop}
- Recall that in the \code{explicate\_control} pass we define one helper
- function for each kind of position in the program. For the \LangVar{}
- language of integers and variables we needed kinds of positions:
- assignment and tail. The \code{if} expressions of \LangIf{} introduced
- predicate positions. For \LangLoop{}, the \code{begin} expression introduces
- yet another kind of position: effect position. Except for the last
- subexpression, the subexpressions inside a \code{begin} are evaluated
- only for their effect. Their result values are discarded. We can
- generate better code by taking this fact into account.
- The output language of \code{explicate\_control} is \LangCLoop{}
- (Figure~\ref{fig:c7-syntax}), which is nearly identical to
- \LangCLam{}. The only syntactic difference is that \code{Call},
- \code{vector-set!}, and \code{read} may also appear as statements.
- The most significant difference between \LangCLam{} and \LangCLoop{}
- is that the control-flow graphs of the later may contain cycles.
- \begin{figure}[tp]
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Stmt &::=& \gray{ \ASSIGN{\VAR{\Var}}{\Exp}
- \MID \LP\key{Collect} \,\itm{int}\RP } \\
- &\MID& \CALL{\Atm}{\LP\Atm\ldots\RP} \MID \READ{}\\
- &\MID& \LP\key{Prim}~\key{'vector-set!}\,\LP\key{list}\,\Atm\,\INT{\Int}\,\Atm\RP\RP \\
- \Def &::=& \DEF{\itm{label}}{\LP\LS\Var\key{:}\Type\RS\ldots\RP}{\Type}{\itm{info}}{\LP\LP\itm{label}\,\key{.}\,\Tail\RP\ldots\RP}\\
- \LangCLoopM{} & ::= & \PROGRAMDEFS{\itm{info}}{\LP\Def\ldots\RP}
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The abstract syntax of \LangCLoop{}, extending \LangCLam{} (Figure~\ref{fig:c4-syntax}).}
- \label{fig:c7-syntax}
- \end{figure}
- The new auxiliary function \code{explicate\_effect} takes an expression
- (in an effect position) and a promise of a continuation block. The
- function returns a promise for a $\Tail$ that includes the generated
- code for the input expression followed by the continuation block. If
- the expression is obviously pure, that is, never causes side effects,
- then the expression can be removed, so the result is just the
- continuation block.
- %
- The $\WHILE{\itm{cnd}}{\itm{body}}$ expression is the most interesting
- case. First, you will need a fresh label $\itm{loop}$ for the top of
- the loop. Recursively process the \itm{body} (in effect position)
- with the a \code{goto} to $\itm{loop}$ as the continuation, producing
- \itm{body'}. Next, process the \itm{cnd} (in predicate position) with
- \itm{body'} as the then-branch and the continuation block as the
- else-branch. The result should be added to the control-flow graph with
- the label \itm{loop}. The result for the whole \code{while} loop is a
- \code{goto} to the \itm{loop} label. Note that the loop should only be
- added to the control-flow graph if the loop is indeed used, which can
- be accomplished using \code{delay}.
- The auxiliary functions for tail, assignment, and predicate positions
- need to be updated. The three new language forms, \code{while},
- \code{set!}, and \code{begin}, can appear in assignment and tail
- positions. Only \code{begin} may appear in predicate positions; the
- other two have result type \code{Void}.
- \section{Select Instructions}
- \label{sec:select-instructions-loop}
- Only three small additions are needed in the
- \code{select\_instructions} pass to handle the changes to \LangCLoop{}. That
- is, \code{Call}, \code{read}, and \code{vector-set!} may now appear as
- stand-alone statements instead of only appearing on the right-hand
- side of an assignment statement. The code generation is nearly
- identical; just leave off the instruction for moving the result into
- the left-hand side.
- \section{Register Allocation}
- \label{sec:register-allocation-loop}
- As discussed in Section~\ref{sec:dataflow-analysis}, the presence of
- loops in \LangLoop{} means that the control-flow graphs may contain cycles,
- which complicates the liveness analysis needed for register
- allocation.
- \subsection{Liveness Analysis}
- \label{sec:liveness-analysis-r8}
- We recommend using the generic \code{analyze-dataflow} function that
- was presented at the end of Section~\ref{sec:dataflow-analysis} to
- perform liveness analysis, replacing the code in
- \code{uncover\_live} that processed the basic blocks in topological
- order (Section~\ref{sec:liveness-analysis-Lif}).
- The \code{analyze-dataflow} function has four parameters.
- \begin{enumerate}
- \item The first parameter \code{G} should be a directed graph from the
- \code{racket/graph} package (see the sidebar in
- Section~\ref{sec:build-interference}) that represents the
- control-flow graph.
- \item The second parameter \code{transfer} is a function that applies
- liveness analysis to a basic block. It takes two parameters: the
- label for the block to analyze and the live-after set for that
- block. The transfer function should return the live-before set for
- the block. Also, as a side-effect, it should update the block's
- $\itm{info}$ with the liveness information for each instruction. To
- implement the \code{transfer} function, you should be able to reuse
- the code you already have for analyzing basic blocks.
- \item The third and fourth parameters of \code{analyze-dataflow} are
- \code{bottom} and \code{join} for the lattice of abstract states,
- i.e. sets of locations. The bottom of the lattice is the empty set
- \code{(set)} and the join operator is \code{set-union}.
- \end{enumerate}
- \begin{figure}[p]
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (Rfun) at (0,2) {\large \LangLoop{}};
- \node (Rfun-2) at (3,2) {\large \LangLoop{}};
- %\node (Rfun-3) at (6,2) {\large \LangLoop{}};
- %\node (Rfun-4) at (9,2) {\large \LangLoopFunRef{}};
- %\node (F1-1) at (12,0) {\large \LangLoopFunRef{}};
- %\node (F1-2) at (9,0) {\large \LangLoopFunRef{}};
- %\node (F1-3) at (6,0) {\large \LangLoopFunRef{}};
- \node (F1-4) at (6,2) {\large \LangLoop{}};
- \node (F1-5) at (9,2) {\large \LangLoop{}};
- \node (C3-2) at (3,0) {\large \LangCLoop{}};
- \node (x86-2) at (3,-2) {\large \LangXIfVar{}};
- \node (x86-2-1) at (3,-4) {\large \LangXIfVar{}};
- \node (x86-2-2) at (6,-4) {\large \LangXIfVar{}};
- \node (x86-3) at (6,-2) {\large \LangXIfVar{}};
- \node (x86-4) at (9,-2) {\large \LangXIf{}};
- \node (x86-5) at (9,-4) {\large \LangXIf{}};
- %% \path[->,bend left=15] (Rfun) edge [above] node
- %% {\ttfamily\footnotesize type-check} (Rfun-2);
- \path[->,bend left=15] (Rfun) edge [above] node
- {\ttfamily\footnotesize shrink} (Rfun-2);
- \path[->,bend left=15] (Rfun-2) edge [above] node
- {\ttfamily\footnotesize uniquify} (F1-4);
- %% \path[->,bend left=15] (Rfun-3) edge [above] node
- %% {\ttfamily\footnotesize reveal\_functions} (Rfun-4);
- %% \path[->,bend left=15] (Rfun-4) edge [right] node
- %% {\ttfamily\footnotesize convert\_assignments} (F1-1);
- %% \path[->,bend left=15] (Rfun-4) edge [right] node
- %% {\ttfamily\footnotesize convert\_to\_clos.} (F1-2);
- %% \path[->,bend right=15] (F1-2) edge [above] node
- %% {\ttfamily\footnotesize limit\_fun.} (F1-3);
- %% \path[->,bend right=15] (F1-3) edge [above] node
- %% {\ttfamily\footnotesize expose-alloc.} (F1-4);
- \path[->,bend left=15] (F1-4) edge [above] node
- {\ttfamily\footnotesize remove\_complex.} (F1-5);
- \path[->,bend left=15] (F1-5) edge [right] node
- {\ttfamily\footnotesize explicate\_control} (C3-2);
- \path[->,bend left=15] (C3-2) edge [left] node
- {\ttfamily\footnotesize select\_instr.} (x86-2);
- \path[->,bend right=15] (x86-2) edge [left] node
- {\ttfamily\footnotesize uncover\_live} (x86-2-1);
- \path[->,bend right=15] (x86-2-1) edge [below] node
- {\ttfamily\footnotesize build\_inter.} (x86-2-2);
- \path[->,bend right=15] (x86-2-2) edge [left] node
- {\ttfamily\footnotesize allocate\_reg.} (x86-3);
- \path[->,bend left=15] (x86-3) edge [above] node
- {\ttfamily\footnotesize patch\_instr.} (x86-4);
- \path[->,bend left=15] (x86-4) edge [right] node {\ttfamily\footnotesize print-x86} (x86-5);
- \end{tikzpicture}
- \caption{Diagram of the passes for \LangLoop{} (loops and assignment).}
- \label{fig:Rwhile-passes}
- \end{figure}
- Figure~\ref{fig:Rwhile-passes} provides an overview of all the passes needed
- for the compilation of \LangLoop{}.
- % Further Reading: dataflow analysis
- \fi
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- \chapter{Tuples and Garbage Collection}
- \label{ch:Rvec}
- \index{subject}{tuple}
- \index{subject}{vector}
- \if\edition\racketEd
- %% \margincomment{\scriptsize To do: Flesh out this chapter, e.g., make sure
- %% all the IR grammars are spelled out! \\ --Jeremy}
- %% \margincomment{\scriptsize Be more explicit about how to deal with
- %% the root stack. \\ --Jeremy}
- In this chapter we study the implementation of mutable tuples, called
- vectors in Racket. This language feature is the first to use the
- computer's \emph{heap}\index{subject}{heap} because the lifetime of a
- Racket tuple is indefinite, that is, a tuple lives forever from the
- programmer's viewpoint. Of course, from an implementer's viewpoint, it
- is important to reclaim the space associated with a tuple when it is
- no longer needed, which is why we also study \emph{garbage
- collection} \index{garbage collection} techniques in this chapter.
- Section~\ref{sec:r3} introduces the \LangVec{} language including its
- interpreter and type checker. The \LangVec{} language extends the \LangIf{}
- language of Chapter~\ref{ch:Lif} with vectors and Racket's
- \code{void} value. The reason for including the later is that the
- \code{vector-set!} operation returns a value of type
- \code{Void}\footnote{Racket's \code{Void} type corresponds to what is
- called the \code{Unit} type in the programming languages
- literature. Racket's \code{Void} type is inhabited by a single value
- \code{void} which corresponds to \code{unit} or \code{()} in the
- literature~\citep{Pierce:2002hj}.}.
- Section~\ref{sec:GC} describes a garbage collection algorithm based on
- copying live objects back and forth between two halves of the
- heap. The garbage collector requires coordination with the compiler so
- that it can see all of the \emph{root} pointers, that is, pointers in
- registers or on the procedure call stack.
- Sections~\ref{sec:expose-allocation} through \ref{sec:print-x86-gc}
- discuss all the necessary changes and additions to the compiler
- passes, including a new compiler pass named \code{expose-allocation}.
- \section{The \LangVec{} Language}
- \label{sec:r3}
- Figure~\ref{fig:Rvec-concrete-syntax} defines the concrete syntax for
- \LangVec{} and Figure~\ref{fig:Rvec-syntax} defines the abstract syntax. The
- \LangVec{} language includes three new forms: \code{vector} for creating a
- tuple, \code{vector-ref} for reading an element of a tuple, and
- \code{vector-set!} for writing to an element of a tuple. The program
- in Figure~\ref{fig:vector-eg} shows the usage of tuples in Racket. We
- create a 3-tuple \code{t} and a 1-tuple that is stored at index $2$ of
- the 3-tuple, demonstrating that tuples are first-class values. The
- element at index $1$ of \code{t} is \code{\#t}, so the ``then'' branch
- of the \key{if} is taken. The element at index $0$ of \code{t} is
- \code{40}, to which we add \code{2}, the element at index $0$ of the
- 1-tuple. So the result of the program is \code{42}.
- \begin{figure}[tbp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \[
- \begin{array}{lcl}
- \Type &::=& \gray{\key{Integer} \MID \key{Boolean}}
- \MID \LP\key{Vector}\;\Type\ldots\RP \MID \key{Void}\\
- \Exp &::=& \gray{ \Int \MID \CREAD{} \MID \CNEG{\Exp} \MID \CADD{\Exp}{\Exp} \MID \CSUB{\Exp}{\Exp} } \\
- &\MID& \gray{ \Var \MID \CLET{\Var}{\Exp}{\Exp} }\\
- &\MID& \gray{ \key{\#t} \MID \key{\#f}
- \MID \LP\key{and}\;\Exp\;\Exp\RP
- \MID \LP\key{or}\;\Exp\;\Exp\RP
- \MID \LP\key{not}\;\Exp\RP } \\
- &\MID& \gray{ \LP\itm{cmp}\;\Exp\;\Exp\RP
- \MID \CIF{\Exp}{\Exp}{\Exp} } \\
- &\MID& \LP\key{vector}\;\Exp\ldots\RP
- \MID \LP\key{vector-length}\;\Exp\RP \\
- &\MID& \LP\key{vector-ref}\;\Exp\;\Int\RP
- \MID \LP\key{vector-set!}\;\Exp\;\Int\;\Exp\RP \\
- &\MID& \LP\key{void}\RP \MID \LP\key{has-type}~\Exp~\Type\RP\\
- \LangVecM{} &::=& \Exp
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The concrete syntax of \LangVec{}, extending \LangIf{}
- (Figure~\ref{fig:Lif-concrete-syntax}).}
- \label{fig:Rvec-concrete-syntax}
- \end{figure}
- \begin{figure}[tbp]
- \begin{lstlisting}
- (let ([t (vector 40 #t (vector 2))])
- (if (vector-ref t 1)
- (+ (vector-ref t 0)
- (vector-ref (vector-ref t 2) 0))
- 44))
- \end{lstlisting}
- \caption{Example program that creates tuples and reads from them.}
- \label{fig:vector-eg}
- \end{figure}
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \[
- \begin{array}{lcl}
- \itm{op} &::=& \ldots \MID \code{vector} \MID \code{vector-length} \\
- \Exp &::=& \gray{ \INT{\Int} \MID \VAR{\Var} \MID \LET{\Var}{\Exp}{\Exp} } \\
- &\MID& \gray{ \PRIM{\itm{op}}{\Exp\ldots}
- \MID \BOOL{\itm{bool}}
- \MID \IF{\Exp}{\Exp}{\Exp} } \\
- &\MID& \VECREF{\Exp}{\INT{\Int}}\\
- &\MID& \VECSET{\Exp}{\INT{\Int}}{\Exp} \\
- &\MID& \VOID{} \MID \LP\key{HasType}~\Exp~\Type \RP \\
- \LangVecM{} &::=& \PROGRAM{\key{'()}}{\Exp}
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The abstract syntax of \LangVec{}.}
- \label{fig:Rvec-syntax}
- \end{figure}
- \index{subject}{allocate}
- \index{subject}{heap allocate}
- Tuples are our first encounter with heap-allocated data, which raises
- several interesting issues. First, variable binding performs a
- shallow-copy when dealing with tuples, which means that different
- variables can refer to the same tuple, that is, different variables
- can be \emph{aliases} for the same entity. Consider the following
- example in which both \code{t1} and \code{t2} refer to the same tuple.
- Thus, the mutation through \code{t2} is visible when referencing the
- tuple from \code{t1}, so the result of this program is \code{42}.
- \index{subject}{alias}\index{subject}{mutation}
- \begin{center}
- \begin{minipage}{0.96\textwidth}
- \begin{lstlisting}
- (let ([t1 (vector 3 7)])
- (let ([t2 t1])
- (let ([_ (vector-set! t2 0 42)])
- (vector-ref t1 0))))
- \end{lstlisting}
- \end{minipage}
- \end{center}
- The next issue concerns the lifetime of tuples. Of course, they are
- created by the \code{vector} form, but when does their lifetime end?
- Notice that \LangVec{} does not include an operation for deleting
- tuples. Furthermore, the lifetime of a tuple is not tied to any notion
- of static scoping. For example, the following program returns
- \code{42} even though the variable \code{w} goes out of scope prior to
- the \code{vector-ref} that reads from the vector it was bound to.
- \begin{center}
- \begin{minipage}{0.96\textwidth}
- \begin{lstlisting}
- (let ([v (vector (vector 44))])
- (let ([x (let ([w (vector 42)])
- (let ([_ (vector-set! v 0 w)])
- 0))])
- (+ x (vector-ref (vector-ref v 0) 0))))
- \end{lstlisting}
- \end{minipage}
- \end{center}
- From the perspective of programmer-observable behavior, tuples live
- forever. Of course, if they really lived forever, then many programs
- would run out of memory.\footnote{The \LangVec{} language does not have
- looping or recursive functions, so it is nigh impossible to write a
- program in \LangVec{} that will run out of memory. However, we add
- recursive functions in the next Chapter!} A Racket implementation
- must therefore perform automatic garbage collection.
- Figure~\ref{fig:interp-Rvec} shows the definitional interpreter for the
- \LangVec{} language. We define the \code{vector}, \code{vector-length},
- \code{vector-ref}, and \code{vector-set!} operations for \LangVec{} in
- terms of the corresponding operations in Racket. One subtle point is
- that the \code{vector-set!} operation returns the \code{\#<void>}
- value. The \code{\#<void>} value can be passed around just like other
- values inside an \LangVec{} program and a \code{\#<void>} value can be
- compared for equality with another \code{\#<void>} value. However,
- there are no other operations specific to the the \code{\#<void>}
- value in \LangVec{}. In contrast, Racket defines the \code{void?} predicate
- that returns \code{\#t} when applied to \code{\#<void>} and \code{\#f}
- otherwise.
- \begin{figure}[tbp]
- \begin{lstlisting}
- (define interp-Rvec_class
- (class interp-Lif_class
- (super-new)
- (define/override (interp-op op)
- (match op
- ['eq? (lambda (v1 v2)
- (cond [(or (and (fixnum? v1) (fixnum? v2))
- (and (boolean? v1) (boolean? v2))
- (and (vector? v1) (vector? v2))
- (and (void? v1) (void? v2)))
- (eq? v1 v2)]))]
- ['vector vector]
- ['vector-length vector-length]
- ['vector-ref vector-ref]
- ['vector-set! vector-set!]
- [else (super interp-op op)]
- ))
- (define/override ((interp-exp env) e)
- (define recur (interp-exp env))
- (match e
- [(HasType e t) (recur e)]
- [(Void) (void)]
- [else ((super interp-exp env) e)]
- ))
- ))
- (define (interp-Rvec p)
- (send (new interp-Rvec_class) interp-program p))
- \end{lstlisting}
- \caption{Interpreter for the \LangVec{} language.}
- \label{fig:interp-Rvec}
- \end{figure}
- Figure~\ref{fig:type-check-Rvec} shows the type checker for \LangVec{}, which
- deserves some explanation. When allocating a vector, we need to know
- which elements of the vector are pointers (i.e. are also vectors). We
- can obtain this information during type checking. The type checker in
- Figure~\ref{fig:type-check-Rvec} not only computes the type of an
- expression, it also wraps every \key{vector} creation with the form
- $(\key{HasType}~e~T)$, where $T$ is the vector's type.
- %
- To create the s-expression for the \code{Vector} type in
- Figure~\ref{fig:type-check-Rvec}, we use the
- \href{https://docs.racket-lang.org/reference/quasiquote.html}{unquote-splicing
- operator} \code{,@} to insert the list \code{t*} without its usual
- start and end parentheses. \index{subject}{unquote-slicing}
- \begin{figure}[tp]
- \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
- (define type-check-Rvec_class
- (class type-check-Lif_class
- (super-new)
- (inherit check-type-equal?)
- (define/override (type-check-exp env)
- (lambda (e)
- (define recur (type-check-exp env))
- (match e
- [(Void) (values (Void) 'Void)]
- [(Prim 'vector es)
- (define-values (e* t*) (for/lists (e* t*) ([e es]) (recur e)))
- (define t `(Vector ,@t*))
- (values (HasType (Prim 'vector e*) t) t)]
- [(Prim 'vector-ref (list e1 (Int i)))
- (define-values (e1^ t) (recur e1))
- (match t
- [`(Vector ,ts ...)
- (unless (and (0 . <= . i) (i . < . (length ts)))
- (error 'type-check "index ~a out of bounds\nin ~v" i e))
- (values (Prim 'vector-ref (list e1^ (Int i))) (list-ref ts i))]
- [else (error 'type-check "expect Vector, not ~a\nin ~v" t e)])]
- [(Prim 'vector-set! (list e1 (Int i) arg) )
- (define-values (e-vec t-vec) (recur e1))
- (define-values (e-arg^ t-arg) (recur arg))
- (match t-vec
- [`(Vector ,ts ...)
- (unless (and (0 . <= . i) (i . < . (length ts)))
- (error 'type-check "index ~a out of bounds\nin ~v" i e))
- (check-type-equal? (list-ref ts i) t-arg e)
- (values (Prim 'vector-set! (list e-vec (Int i) e-arg^)) 'Void)]
- [else (error 'type-check "expect Vector, not ~a\nin ~v" t-vec e)])]
- [(Prim 'vector-length (list e))
- (define-values (e^ t) (recur e))
- (match t
- [`(Vector ,ts ...)
- (values (Prim 'vector-length (list e^)) 'Integer)]
- [else (error 'type-check "expect Vector, not ~a\nin ~v" t e)])]
- [(Prim 'eq? (list arg1 arg2))
- (define-values (e1 t1) (recur arg1))
- (define-values (e2 t2) (recur arg2))
- (match* (t1 t2)
- [(`(Vector ,ts1 ...) `(Vector ,ts2 ...)) (void)]
- [(other wise) (check-type-equal? t1 t2 e)])
- (values (Prim 'eq? (list e1 e2)) 'Boolean)]
- [(HasType (Prim 'vector es) t)
- ((type-check-exp env) (Prim 'vector es))]
- [(HasType e1 t)
- (define-values (e1^ t^) (recur e1))
- (check-type-equal? t t^ e)
- (values (HasType e1^ t) t)]
- [else ((super type-check-exp env) e)]
- )))
- ))
- (define (type-check-Rvec p)
- (send (new type-check-Rvec_class) type-check-program p))
- \end{lstlisting}
- \caption{Type checker for the \LangVec{} language.}
- \label{fig:type-check-Rvec}
- \end{figure}
- \section{Garbage Collection}
- \label{sec:GC}
- Here we study a relatively simple algorithm for garbage collection
- that is the basis of state-of-the-art garbage
- collectors~\citep{Lieberman:1983aa,Ungar:1984aa,Jones:1996aa,Detlefs:2004aa,Dybvig:2006aa,Tene:2011kx}. In
- particular, we describe a two-space copying
- collector~\citep{Wilson:1992fk} that uses Cheney's algorithm to
- perform the
- copy~\citep{Cheney:1970aa}.
- \index{subject}{copying collector}
- \index{subject}{two-space copying collector}
- Figure~\ref{fig:copying-collector} gives a
- coarse-grained depiction of what happens in a two-space collector,
- showing two time steps, prior to garbage collection (on the top) and
- after garbage collection (on the bottom). In a two-space collector,
- the heap is divided into two parts named the FromSpace and the
- ToSpace. Initially, all allocations go to the FromSpace until there is
- not enough room for the next allocation request. At that point, the
- garbage collector goes to work to make more room.
- \index{subject}{ToSpace}
- \index{subject}{FromSpace}
- The garbage collector must be careful not to reclaim tuples that will
- be used by the program in the future. Of course, it is impossible in
- general to predict what a program will do, but we can over approximate
- the will-be-used tuples by preserving all tuples that could be
- accessed by \emph{any} program given the current computer state. A
- program could access any tuple whose address is in a register or on
- the procedure call stack. These addresses are called the \emph{root
- set}\index{subject}{root set}. In addition, a program could access any tuple that is
- transitively reachable from the root set. Thus, it is safe for the
- garbage collector to reclaim the tuples that are not reachable in this
- way.
- So the goal of the garbage collector is twofold:
- \begin{enumerate}
- \item preserve all tuple that are reachable from the root set via a
- path of pointers, that is, the \emph{live} tuples, and
- \item reclaim the memory of everything else, that is, the
- \emph{garbage}.
- \end{enumerate}
- A copying collector accomplishes this by copying all of the live
- objects from the FromSpace into the ToSpace and then performs a sleight
- of hand, treating the ToSpace as the new FromSpace and the old
- FromSpace as the new ToSpace. In the example of
- Figure~\ref{fig:copying-collector}, there are three pointers in the
- root set, one in a register and two on the stack. All of the live
- objects have been copied to the ToSpace (the right-hand side of
- Figure~\ref{fig:copying-collector}) in a way that preserves the
- pointer relationships. For example, the pointer in the register still
- points to a 2-tuple whose first element is a 3-tuple and whose second
- element is a 2-tuple. There are four tuples that are not reachable
- from the root set and therefore do not get copied into the ToSpace.
- The exact situation in Figure~\ref{fig:copying-collector} cannot be
- created by a well-typed program in \LangVec{} because it contains a
- cycle. However, creating cycles will be possible once we get to \LangAny{}.
- We design the garbage collector to deal with cycles to begin with so
- we will not need to revisit this issue.
- \begin{figure}[tbp]
- \centering
- \includegraphics[width=\textwidth]{figs/copy-collect-1} \\[5ex]
- \includegraphics[width=\textwidth]{figs/copy-collect-2}
- \caption{A copying collector in action.}
- \label{fig:copying-collector}
- \end{figure}
- There are many alternatives to copying collectors (and their bigger
- siblings, the generational collectors) when its comes to garbage
- collection, such as mark-and-sweep~\citep{McCarthy:1960dz} and
- reference counting~\citep{Collins:1960aa}. The strengths of copying
- collectors are that allocation is fast (just a comparison and pointer
- increment), there is no fragmentation, cyclic garbage is collected,
- and the time complexity of collection only depends on the amount of
- live data, and not on the amount of garbage~\citep{Wilson:1992fk}. The
- main disadvantages of a two-space copying collector is that it uses a
- lot of space and takes a long time to perform the copy, though these
- problems are ameliorated in generational collectors. Racket and
- Scheme programs tend to allocate many small objects and generate a lot
- of garbage, so copying and generational collectors are a good fit.
- Garbage collection is an active research topic, especially concurrent
- garbage collection~\citep{Tene:2011kx}. Researchers are continuously
- developing new techniques and revisiting old
- trade-offs~\citep{Blackburn:2004aa,Jones:2011aa,Shahriyar:2013aa,Cutler:2015aa,Shidal:2015aa,Osterlund:2016aa,Jacek:2019aa,Gamari:2020aa}. Researchers
- meet every year at the International Symposium on Memory Management to
- present these findings.
- \subsection{Graph Copying via Cheney's Algorithm}
- \label{sec:cheney}
- \index{subject}{Cheney's algorithm}
- Let us take a closer look at the copying of the live objects. The
- allocated objects and pointers can be viewed as a graph and we need to
- copy the part of the graph that is reachable from the root set. To
- make sure we copy all of the reachable vertices in the graph, we need
- an exhaustive graph traversal algorithm, such as depth-first search or
- breadth-first search~\citep{Moore:1959aa,Cormen:2001uq}. Recall that
- such algorithms take into account the possibility of cycles by marking
- which vertices have already been visited, so as to ensure termination
- of the algorithm. These search algorithms also use a data structure
- such as a stack or queue as a to-do list to keep track of the vertices
- that need to be visited. We use breadth-first search and a trick
- due to \citet{Cheney:1970aa} for simultaneously representing the queue
- and copying tuples into the ToSpace.
- Figure~\ref{fig:cheney} shows several snapshots of the ToSpace as the
- copy progresses. The queue is represented by a chunk of contiguous
- memory at the beginning of the ToSpace, using two pointers to track
- the front and the back of the queue. The algorithm starts by copying
- all tuples that are immediately reachable from the root set into the
- ToSpace to form the initial queue. When we copy a tuple, we mark the
- old tuple to indicate that it has been visited. We discuss how this
- marking is accomplish in Section~\ref{sec:data-rep-gc}. Note that any
- pointers inside the copied tuples in the queue still point back to the
- FromSpace. Once the initial queue has been created, the algorithm
- enters a loop in which it repeatedly processes the tuple at the front
- of the queue and pops it off the queue. To process a tuple, the
- algorithm copies all the tuple that are directly reachable from it to
- the ToSpace, placing them at the back of the queue. The algorithm then
- updates the pointers in the popped tuple so they point to the newly
- copied tuples.
- \begin{figure}[tbp]
- \centering \includegraphics[width=0.9\textwidth]{figs/cheney}
- \caption{Depiction of the Cheney algorithm copying the live tuples.}
- \label{fig:cheney}
- \end{figure}
- Getting back to Figure~\ref{fig:cheney}, in the first step we copy the
- tuple whose second element is $42$ to the back of the queue. The other
- pointer goes to a tuple that has already been copied, so we do not
- need to copy it again, but we do need to update the pointer to the new
- location. This can be accomplished by storing a \emph{forwarding
- pointer} to the new location in the old tuple, back when we initially
- copied the tuple into the ToSpace. This completes one step of the
- algorithm. The algorithm continues in this way until the front of the
- queue is empty, that is, until the front catches up with the back.
- \subsection{Data Representation}
- \label{sec:data-rep-gc}
- The garbage collector places some requirements on the data
- representations used by our compiler. First, the garbage collector
- needs to distinguish between pointers and other kinds of data. There
- are several ways to accomplish this.
- \begin{enumerate}
- \item Attached a tag to each object that identifies what type of
- object it is~\citep{McCarthy:1960dz}.
- \item Store different types of objects in different
- regions~\citep{Steele:1977ab}.
- \item Use type information from the program to either generate
- type-specific code for collecting or to generate tables that can
- guide the
- collector~\citep{Appel:1989aa,Goldberg:1991aa,Diwan:1992aa}.
- \end{enumerate}
- Dynamically typed languages, such as Lisp, need to tag objects
- anyways, so option 1 is a natural choice for those languages.
- However, \LangVec{} is a statically typed language, so it would be
- unfortunate to require tags on every object, especially small and
- pervasive objects like integers and Booleans. Option 3 is the
- best-performing choice for statically typed languages, but comes with
- a relatively high implementation complexity. To keep this chapter
- within a 2-week time budget, we recommend a combination of options 1
- and 2, using separate strategies for the stack and the heap.
- Regarding the stack, we recommend using a separate stack for pointers,
- which we call a \emph{root stack}\index{subject}{root stack} (a.k.a. ``shadow
- stack'')~\citep{Siebert:2001aa,Henderson:2002aa,Baker:2009aa}. That
- is, when a local variable needs to be spilled and is of type
- \code{(Vector $\Type_1 \ldots \Type_n$)}, then we put it on the root
- stack instead of the normal procedure call stack. Furthermore, we
- always spill vector-typed variables if they are live during a call to
- the collector, thereby ensuring that no pointers are in registers
- during a collection. Figure~\ref{fig:shadow-stack} reproduces the
- example from Figure~\ref{fig:copying-collector} and contrasts it with
- the data layout using a root stack. The root stack contains the two
- pointers from the regular stack and also the pointer in the second
- register.
- \begin{figure}[tbp]
- \centering \includegraphics[width=0.60\textwidth]{figs/root-stack}
- \caption{Maintaining a root stack to facilitate garbage collection.}
- \label{fig:shadow-stack}
- \end{figure}
- The problem of distinguishing between pointers and other kinds of data
- also arises inside of each tuple on the heap. We solve this problem by
- attaching a tag, an extra 64-bits, to each
- tuple. Figure~\ref{fig:tuple-rep} zooms in on the tags for two of the
- tuples in the example from Figure~\ref{fig:copying-collector}. Note
- that we have drawn the bits in a big-endian way, from right-to-left,
- with bit location 0 (the least significant bit) on the far right,
- which corresponds to the direction of the x86 shifting instructions
- \key{salq} (shift left) and \key{sarq} (shift right). Part of each tag
- is dedicated to specifying which elements of the tuple are pointers,
- the part labeled ``pointer mask''. Within the pointer mask, a 1 bit
- indicates there is a pointer and a 0 bit indicates some other kind of
- data. The pointer mask starts at bit location 7. We have limited
- tuples to a maximum size of 50 elements, so we just need 50 bits for
- the pointer mask. The tag also contains two other pieces of
- information. The length of the tuple (number of elements) is stored in
- bits location 1 through 6. Finally, the bit at location 0 indicates
- whether the tuple has yet to be copied to the ToSpace. If the bit has
- value 1, then this tuple has not yet been copied. If the bit has
- value 0 then the entire tag is a forwarding pointer. (The lower 3 bits
- of a pointer are always zero anyways because our tuples are 8-byte
- aligned.)
- \begin{figure}[tbp]
- \centering \includegraphics[width=0.8\textwidth]{figs/tuple-rep}
- \caption{Representation of tuples in the heap.}
- \label{fig:tuple-rep}
- \end{figure}
- \subsection{Implementation of the Garbage Collector}
- \label{sec:organize-gz}
- \index{subject}{prelude}
- An implementation of the copying collector is provided in the
- \code{runtime.c} file. Figure~\ref{fig:gc-header} defines the
- interface to the garbage collector that is used by the compiler. The
- \code{initialize} function creates the FromSpace, ToSpace, and root
- stack and should be called in the prelude of the \code{main}
- function. The arguments of \code{initialize} are the root stack size
- and the heap size. Both need to be multiples of $64$ and $16384$ is a
- good choice for both. The \code{initialize} function puts the address
- of the beginning of the FromSpace into the global variable
- \code{free\_ptr}. The global variable \code{fromspace\_end} points to
- the address that is 1-past the last element of the FromSpace. (We use
- half-open intervals to represent chunks of
- memory~\citep{Dijkstra:1982aa}.) The \code{rootstack\_begin} variable
- points to the first element of the root stack.
- As long as there is room left in the FromSpace, your generated code
- can allocate tuples simply by moving the \code{free\_ptr} forward.
- %
- The amount of room left in FromSpace is the difference between the
- \code{fromspace\_end} and the \code{free\_ptr}. The \code{collect}
- function should be called when there is not enough room left in the
- FromSpace for the next allocation. The \code{collect} function takes
- a pointer to the current top of the root stack (one past the last item
- that was pushed) and the number of bytes that need to be
- allocated. The \code{collect} function performs the copying collection
- and leaves the heap in a state such that the next allocation will
- succeed.
- \begin{figure}[tbp]
- \begin{lstlisting}
- void initialize(uint64_t rootstack_size, uint64_t heap_size);
- void collect(int64_t** rootstack_ptr, uint64_t bytes_requested);
- int64_t* free_ptr;
- int64_t* fromspace_begin;
- int64_t* fromspace_end;
- int64_t** rootstack_begin;
- \end{lstlisting}
- \caption{The compiler's interface to the garbage collector.}
- \label{fig:gc-header}
- \end{figure}
- %% \begin{exercise}
- %% In the file \code{runtime.c} you will find the implementation of
- %% \code{initialize} and a partial implementation of \code{collect}.
- %% The \code{collect} function calls another function, \code{cheney},
- %% to perform the actual copy, and that function is left to the reader
- %% to implement. The following is the prototype for \code{cheney}.
- %% \begin{lstlisting}
- %% static void cheney(int64_t** rootstack_ptr);
- %% \end{lstlisting}
- %% The parameter \code{rootstack\_ptr} is a pointer to the top of the
- %% rootstack (which is an array of pointers). The \code{cheney} function
- %% also communicates with \code{collect} through the global
- %% variables \code{fromspace\_begin} and \code{fromspace\_end}
- %% mentioned in Figure~\ref{fig:gc-header} as well as the pointers for
- %% the ToSpace:
- %% \begin{lstlisting}
- %% static int64_t* tospace_begin;
- %% static int64_t* tospace_end;
- %% \end{lstlisting}
- %% The job of the \code{cheney} function is to copy all the live
- %% objects (reachable from the root stack) into the ToSpace, update
- %% \code{free\_ptr} to point to the next unused spot in the ToSpace,
- %% update the root stack so that it points to the objects in the
- %% ToSpace, and finally to swap the global pointers for the FromSpace
- %% and ToSpace.
- %% \end{exercise}
- %% \section{Compiler Passes}
- %% \label{sec:code-generation-gc}
- The introduction of garbage collection has a non-trivial impact on our
- compiler passes. We introduce a new compiler pass named
- \code{expose-allocation}. We make
- significant changes to \code{select\_instructions},
- \code{build\_interference}, \code{allocate\_registers}, and
- \code{print\_x86} and make minor changes in several more passes. The
- following program will serve as our running example. It creates two
- tuples, one nested inside the other. Both tuples have length one. The
- program accesses the element in the inner tuple tuple via two vector
- references.
- % tests/s2_17.rkt
- \begin{lstlisting}
- (vector-ref (vector-ref (vector (vector 42)) 0) 0)
- \end{lstlisting}
- \section{Shrink}
- \label{sec:shrink-Rvec}
- Recall that the \code{shrink} pass translates the primitives operators
- into a smaller set of primitives. Because this pass comes after type
- checking, but before the passes that require the type information in
- the \code{HasType} AST nodes, the \code{shrink} pass must be modified
- to wrap \code{HasType} around each AST node that it generates.
- \section{Expose Allocation}
- \label{sec:expose-allocation}
- The pass \code{expose-allocation} lowers the \code{vector} creation
- form into a conditional call to the collector followed by the
- allocation. We choose to place the \code{expose-allocation} pass
- before \code{remove\_complex\_operands} because the code generated by
- \code{expose-allocation} contains complex operands. We also place
- \code{expose-allocation} before \code{explicate\_control} because
- \code{expose-allocation} introduces new variables using \code{let},
- but \code{let} is gone after \code{explicate\_control}.
- The output of \code{expose-allocation} is a language \LangAlloc{} that
- extends \LangVec{} with the three new forms that we use in the translation
- of the \code{vector} form.
- \[
- \begin{array}{lcl}
- \Exp &::=& \cdots
- \MID (\key{collect} \,\itm{int})
- \MID (\key{allocate} \,\itm{int}\,\itm{type})
- \MID (\key{global-value} \,\itm{name})
- \end{array}
- \]
- The $(\key{collect}\,n)$ form runs the garbage collector, requesting
- $n$ bytes. It will become a call to the \code{collect} function in
- \code{runtime.c} in \code{select\_instructions}. The
- $(\key{allocate}\,n\,T)$ form creates an tuple of $n$ elements.
- \index{subject}{allocate}
- The $T$ parameter is the type of the tuple: \code{(Vector $\Type_1 \ldots
- \Type_n$)} where $\Type_i$ is the type of the $i$th element in the
- tuple. The $(\key{global-value}\,\itm{name})$ form reads the value of
- a global variable, such as \code{free\_ptr}.
- In the following, we show the transformation for the \code{vector}
- form into 1) a sequence of let-bindings for the initializing
- expressions, 2) a conditional call to \code{collect}, 3) a call to
- \code{allocate}, and 4) the initialization of the vector. In the
- following, \itm{len} refers to the length of the vector and
- \itm{bytes} is how many total bytes need to be allocated for the
- vector, which is 8 for the tag plus \itm{len} times 8.
- \begin{lstlisting}
- (has-type (vector |$e_0 \ldots e_{n-1}$|) |\itm{type}|)
- |$\Longrightarrow$|
- (let ([|$x_0$| |$e_0$|]) ... (let ([|$x_{n-1}$| |$e_{n-1}$|])
- (let ([_ (if (< (+ (global-value free_ptr) |\itm{bytes}|)
- (global-value fromspace_end))
- (void)
- (collect |\itm{bytes}|))])
- (let ([|$v$| (allocate |\itm{len}| |\itm{type}|)])
- (let ([_ (vector-set! |$v$| |$0$| |$x_0$|)]) ...
- (let ([_ (vector-set! |$v$| |$n-1$| |$x_{n-1}$|)])
- |$v$|) ... )))) ...)
- \end{lstlisting}
- In the above, we suppressed all of the \code{has-type} forms in the
- output for the sake of readability. The placement of the initializing
- expressions $e_0,\ldots,e_{n-1}$ prior to the \code{allocate} and the
- sequence of \code{vector-set!} is important, as those expressions may
- trigger garbage collection and we cannot have an allocated but
- uninitialized tuple on the heap during a collection.
- Figure~\ref{fig:expose-alloc-output} shows the output of the
- \code{expose-allocation} pass on our running example.
- \begin{figure}[tbp]
- % tests/s2_17.rkt
- \begin{lstlisting}
- (vector-ref
- (vector-ref
- (let ([vecinit7976
- (let ([vecinit7972 42])
- (let ([collectret7974
- (if (< (+ (global-value free_ptr) 16)
- (global-value fromspace_end))
- (void)
- (collect 16)
- )])
- (let ([alloc7971 (allocate 1 (Vector Integer))])
- (let ([initret7973 (vector-set! alloc7971 0 vecinit7972)])
- alloc7971)
- )
- )
- )
- ])
- (let ([collectret7978
- (if (< (+ (global-value free_ptr) 16)
- (global-value fromspace_end))
- (void)
- (collect 16)
- )])
- (let ([alloc7975 (allocate 1 (Vector (Vector Integer)))])
- (let ([initret7977 (vector-set! alloc7975 0 vecinit7976)])
- alloc7975)
- )
- )
- )
- 0)
- 0)
- \end{lstlisting}
- \caption{Output of the \code{expose-allocation} pass, minus
- all of the \code{has-type} forms.}
- \label{fig:expose-alloc-output}
- \end{figure}
- \section{Remove Complex Operands}
- \label{sec:remove-complex-opera-Rvec}
- The new forms \code{collect}, \code{allocate}, and \code{global-value}
- should all be treated as complex operands.
- %% A new case for
- %% \code{HasType} is needed and the case for \code{Prim} needs to be
- %% handled carefully to prevent the \code{Prim} node from being separated
- %% from its enclosing \code{HasType}.
- Figure~\ref{fig:Rvec-anf-syntax}
- shows the grammar for the output language \LangVecANF{} of this
- pass, which is \LangVec{} in administrative normal form.
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{rcl}
- \Atm &::=& \gray{ \INT{\Int} \MID \VAR{\Var} \MID \BOOL{\itm{bool}} }
- \MID \VOID{} \\
- \Exp &::=& \gray{ \Atm \MID \READ{} } \\
- &\MID& \gray{ \NEG{\Atm} \MID \ADD{\Atm}{\Atm} } \\
- &\MID& \gray{ \LET{\Var}{\Exp}{\Exp} } \\
- &\MID& \gray{ \UNIOP{\key{'not}}{\Atm} } \\
- &\MID& \gray{ \BINOP{\itm{cmp}}{\Atm}{\Atm} \MID \IF{\Exp}{\Exp}{\Exp} }\\
- &\MID& \LP\key{Collect}~\Int\RP \MID \LP\key{Allocate}~\Int~\Type\RP
- \MID \LP\key{GlobalValue}~\Var\RP\\
- % &\MID& \LP\key{HasType}~\Exp~\Type\RP \\
- \LangVecANFM{} &::=& \gray{ \PROGRAM{\code{'()}}{\Exp} }
- \end{array}
- \]
- \end{minipage}
- }
- \caption{\LangVecANF{} is \LangVec{} in administrative normal form (ANF).}
- \label{fig:Rvec-anf-syntax}
- \end{figure}
- \section{Explicate Control and the \LangCVec{} language}
- \label{sec:explicate-control-r3}
- \begin{figure}[tp]
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Atm &::=& \gray{ \INT{\Int} \MID \VAR{\Var} \MID \BOOL{\itm{bool}} }\\
- \itm{cmp} &::= & \gray{ \key{eq?} \MID \key{<} } \\
- \Exp &::= & \gray{ \Atm \MID \READ{} } \\
- &\MID& \gray{ \NEG{\Atm} \MID \ADD{\Atm}{\Atm} }\\
- &\MID& \gray{ \UNIOP{\key{not}}{\Atm} \MID \BINOP{\itm{cmp}}{\Atm}{\Atm} } \\
- &\MID& \LP\key{Allocate} \,\itm{int}\,\itm{type}\RP \\
- &\MID& \BINOP{\key{'vector-ref}}{\Atm}{\INT{\Int}} \\
- &\MID& \LP\key{Prim}~\key{'vector-set!}\,\LP\Atm\,\INT{\Int}\,\Atm\RP\RP\\
- &\MID& \LP\key{GlobalValue} \,\Var\RP \MID \LP\key{Void}\RP\\
- \Stmt &::=& \gray{ \ASSIGN{\VAR{\Var}}{\Exp} }
- \MID \LP\key{Collect} \,\itm{int}\RP \\
- \Tail &::= & \gray{ \RETURN{\Exp} \MID \SEQ{\Stmt}{\Tail}
- \MID \GOTO{\itm{label}} } \\
- &\MID& \gray{ \IFSTMT{\BINOP{\itm{cmp}}{\Atm}{\Atm}}{\GOTO{\itm{label}}}{\GOTO{\itm{label}}} }\\
- \LangCVecM{} & ::= & \gray{ \CPROGRAM{\itm{info}}{\LP\LP\itm{label}\,\key{.}\,\Tail\RP\ldots\RP} }
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The abstract syntax of \LangCVec{}, extending \LangCIf{}
- (Figure~\ref{fig:c1-syntax}).}
- \label{fig:c2-syntax}
- \end{figure}
- The output of \code{explicate\_control} is a program in the
- intermediate language \LangCVec{}, whose abstract syntax is defined in
- Figure~\ref{fig:c2-syntax}. (The concrete syntax is defined in
- Figure~\ref{fig:c2-concrete-syntax} of the Appendix.) The new forms
- of \LangCVec{} include the \key{allocate}, \key{vector-ref}, and
- \key{vector-set!}, and \key{global-value} expressions and the
- \code{collect} statement. The \code{explicate\_control} pass can treat
- these new forms much like the other expression forms that we've
- already encoutered.
- \section{Select Instructions and the \LangXGlobal{} Language}
- \label{sec:select-instructions-gc}
- \index{subject}{instruction selection}
- %% void (rep as zero)
- %% allocate
- %% collect (callq collect)
- %% vector-ref
- %% vector-set!
- %% global (postpone)
- In this pass we generate x86 code for most of the new operations that
- were needed to compile tuples, including \code{Allocate},
- \code{Collect}, \code{vector-ref}, \code{vector-set!}, and
- \code{void}. We compile \code{GlobalValue} to \code{Global} because
- the later has a different concrete syntax (see
- Figures~\ref{fig:x86-2-concrete} and \ref{fig:x86-2}).
- \index{subject}{x86}
- The \code{vector-ref} and \code{vector-set!} forms translate into
- \code{movq} instructions. (The plus one in the offset is to get past
- the tag at the beginning of the tuple representation.)
- \begin{lstlisting}
- |$\itm{lhs}$| = (vector-ref |$\itm{vec}$| |$n$|);
- |$\Longrightarrow$|
- movq |$\itm{vec}'$|, %r11
- movq |$8(n+1)$|(%r11), |$\itm{lhs'}$|
- |$\itm{lhs}$| = (vector-set! |$\itm{vec}$| |$n$| |$\itm{arg}$|);
- |$\Longrightarrow$|
- movq |$\itm{vec}'$|, %r11
- movq |$\itm{arg}'$|, |$8(n+1)$|(%r11)
- movq $0, |$\itm{lhs'}$|
- \end{lstlisting}
- The $\itm{lhs}'$, $\itm{vec}'$, and $\itm{arg}'$ are obtained by
- translating $\itm{vec}$ and $\itm{arg}$ to x86. The move of $\itm{vec}'$ to
- register \code{r11} ensures that offset expression
- \code{$-8(n+1)$(\%r11)} contains a register operand. This requires
- removing \code{r11} from consideration by the register allocating.
- Why not use \code{rax} instead of \code{r11}? Suppose we instead used
- \code{rax}. Then the generated code for \code{vector-set!} would be
- \begin{lstlisting}
- movq |$\itm{vec}'$|, %rax
- movq |$\itm{arg}'$|, |$8(n+1)$|(%rax)
- movq $0, |$\itm{lhs}'$|
- \end{lstlisting}
- Next, suppose that $\itm{arg}'$ ends up as a stack location, so
- \code{patch\_instructions} would insert a move through \code{rax}
- as follows.
- \begin{lstlisting}
- movq |$\itm{vec}'$|, %rax
- movq |$\itm{arg}'$|, %rax
- movq %rax, |$8(n+1)$|(%rax)
- movq $0, |$\itm{lhs}'$|
- \end{lstlisting}
- But the above sequence of instructions does not work because we're
- trying to use \code{rax} for two different values ($\itm{vec}'$ and
- $\itm{arg}'$) at the same time!
- We compile the \code{allocate} form to operations on the
- \code{free\_ptr}, as shown below. The address in the \code{free\_ptr}
- is the next free address in the FromSpace, so we copy it into
- \code{r11} and then move it forward by enough space for the tuple
- being allocated, which is $8(\itm{len}+1)$ bytes because each element
- is 8 bytes (64 bits) and we use 8 bytes for the tag. We then
- initialize the \itm{tag} and finally copy the address in \code{r11} to
- the left-hand-side. Refer to Figure~\ref{fig:tuple-rep} to see how the
- tag is organized. We recommend using the Racket operations
- \code{bitwise-ior} and \code{arithmetic-shift} to compute the tag
- during compilation. The type annotation in the \code{vector} form is
- used to determine the pointer mask region of the tag.
- \begin{lstlisting}
- |$\itm{lhs}$| = (allocate |$\itm{len}$| (Vector |$\itm{type} \ldots$|));
- |$\Longrightarrow$|
- movq free_ptr(%rip), %r11
- addq |$8(\itm{len}+1)$|, free_ptr(%rip)
- movq $|$\itm{tag}$|, 0(%r11)
- movq %r11, |$\itm{lhs}'$|
- \end{lstlisting}
- The \code{collect} form is compiled to a call to the \code{collect}
- function in the runtime. The arguments to \code{collect} are 1) the
- top of the root stack and 2) the number of bytes that need to be
- allocated. We use another dedicated register, \code{r15}, to
- store the pointer to the top of the root stack. So \code{r15} is not
- available for use by the register allocator.
- \begin{lstlisting}
- (collect |$\itm{bytes}$|)
- |$\Longrightarrow$|
- movq %r15, %rdi
- movq $|\itm{bytes}|, %rsi
- callq collect
- \end{lstlisting}
- \begin{figure}[tp]
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \[
- \begin{array}{lcl}
- \Arg &::=& \gray{ \key{\$}\Int \MID \key{\%}\Reg \MID \Int\key{(}\key{\%}\Reg\key{)} \MID \key{\%}\itm{bytereg} } \MID \Var \key{(\%rip)} \\
- \LangXGlobalM{} &::= & \gray{ \key{.globl main} }\\
- & & \gray{ \key{main:} \; \Instr\ldots }
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The concrete syntax of \LangXGlobal{} (extends \LangXIf{} of Figure~\ref{fig:x86-1-concrete}).}
- \label{fig:x86-2-concrete}
- \end{figure}
- \begin{figure}[tp]
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Arg &::=& \gray{ \INT{\Int} \MID \REG{\Reg} \MID \DEREF{\Reg}{\Int}
- \MID \BYTEREG{\Reg}} \\
- &\MID& (\key{Global}~\Var) \\
- \LangXGlobalM{} &::= & \gray{ \XPROGRAM{\itm{info}}{\LP\LP\itm{label} \,\key{.}\, \Block \RP\ldots\RP} }
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The abstract syntax of \LangXGlobal{} (extends \LangXIf{} of Figure~\ref{fig:x86-1}).}
- \label{fig:x86-2}
- \end{figure}
- The concrete and abstract syntax of the \LangXGlobal{} language is
- defined in Figures~\ref{fig:x86-2-concrete} and \ref{fig:x86-2}. It
- differs from \LangXIf{} just in the addition of the form for global
- variables.
- %
- Figure~\ref{fig:select-instr-output-gc} shows the output of the
- \code{select\_instructions} pass on the running example.
- \begin{figure}[tbp]
- \centering
- % tests/s2_17.rkt
- \begin{minipage}[t]{0.5\textwidth}
- \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
- block35:
- movq free_ptr(%rip), alloc9024
- addq $16, free_ptr(%rip)
- movq alloc9024, %r11
- movq $131, 0(%r11)
- movq alloc9024, %r11
- movq vecinit9025, 8(%r11)
- movq $0, initret9026
- movq alloc9024, %r11
- movq 8(%r11), tmp9034
- movq tmp9034, %r11
- movq 8(%r11), %rax
- jmp conclusion
- block36:
- movq $0, collectret9027
- jmp block35
- block38:
- movq free_ptr(%rip), alloc9020
- addq $16, free_ptr(%rip)
- movq alloc9020, %r11
- movq $3, 0(%r11)
- movq alloc9020, %r11
- movq vecinit9021, 8(%r11)
- movq $0, initret9022
- movq alloc9020, vecinit9025
- movq free_ptr(%rip), tmp9031
- movq tmp9031, tmp9032
- addq $16, tmp9032
- movq fromspace_end(%rip), tmp9033
- cmpq tmp9033, tmp9032
- jl block36
- jmp block37
- block37:
- movq %r15, %rdi
- movq $16, %rsi
- callq 'collect
- jmp block35
- block39:
- movq $0, collectret9023
- jmp block38
- \end{lstlisting}
- \end{minipage}
- \begin{minipage}[t]{0.45\textwidth}
- \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
- start:
- movq $42, vecinit9021
- movq free_ptr(%rip), tmp9028
- movq tmp9028, tmp9029
- addq $16, tmp9029
- movq fromspace_end(%rip), tmp9030
- cmpq tmp9030, tmp9029
- jl block39
- jmp block40
- block40:
- movq %r15, %rdi
- movq $16, %rsi
- callq 'collect
- jmp block38
- \end{lstlisting}
- \end{minipage}
- \caption{Output of the \code{select\_instructions} pass.}
- \label{fig:select-instr-output-gc}
- \end{figure}
- \clearpage
- \section{Register Allocation}
- \label{sec:reg-alloc-gc}
- \index{subject}{register allocation}
- As discussed earlier in this chapter, the garbage collector needs to
- access all the pointers in the root set, that is, all variables that
- are vectors. It will be the responsibility of the register allocator
- to make sure that:
- \begin{enumerate}
- \item the root stack is used for spilling vector-typed variables, and
- \item if a vector-typed variable is live during a call to the
- collector, it must be spilled to ensure it is visible to the
- collector.
- \end{enumerate}
- The later responsibility can be handled during construction of the
- interference graph, by adding interference edges between the call-live
- vector-typed variables and all the callee-saved registers. (They
- already interfere with the caller-saved registers.) The type
- information for variables is in the \code{Program} form, so we
- recommend adding another parameter to the \code{build\_interference}
- function to communicate this alist.
- The spilling of vector-typed variables to the root stack can be
- handled after graph coloring, when choosing how to assign the colors
- (integers) to registers and stack locations. The \code{Program} output
- of this pass changes to also record the number of spills to the root
- stack.
- % build-interference
- %
- % callq
- % extra parameter for var->type assoc. list
- % update 'program' and 'if'
- % allocate-registers
- % allocate spilled vectors to the rootstack
- % don't change color-graph
- \section{Generate Prelude and Conclusion}
- \label{sec:print-x86-gc}
- \label{sec:prelude-conclusion-x86-gc}
- \index{subject}{prelude}\index{subject}{conclusion}
- Figure~\ref{fig:print-x86-output-gc} shows the output of the
- \code{prelude\_and\_conclusion} pass on the running example. In the
- prelude and conclusion of the \code{main} function, we treat the root
- stack very much like the regular stack in that we move the root stack
- pointer (\code{r15}) to make room for the spills to the root stack,
- except that the root stack grows up instead of down. For the running
- example, there was just one spill so we increment \code{r15} by 8
- bytes. In the conclusion we decrement \code{r15} by 8 bytes.
- One issue that deserves special care is that there may be a call to
- \code{collect} prior to the initializing assignments for all the
- variables in the root stack. We do not want the garbage collector to
- accidentally think that some uninitialized variable is a pointer that
- needs to be followed. Thus, we zero-out all locations on the root
- stack in the prelude of \code{main}. In
- Figure~\ref{fig:print-x86-output-gc}, the instruction
- %
- \lstinline{movq $0, (%r15)}
- %
- accomplishes this task. The garbage collector tests each root to see
- if it is null prior to dereferencing it.
- \begin{figure}[htbp]
- \begin{minipage}[t]{0.5\textwidth}
- \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
- block35:
- movq free_ptr(%rip), %rcx
- addq $16, free_ptr(%rip)
- movq %rcx, %r11
- movq $131, 0(%r11)
- movq %rcx, %r11
- movq -8(%r15), %rax
- movq %rax, 8(%r11)
- movq $0, %rdx
- movq %rcx, %r11
- movq 8(%r11), %rcx
- movq %rcx, %r11
- movq 8(%r11), %rax
- jmp conclusion
- block36:
- movq $0, %rcx
- jmp block35
- block38:
- movq free_ptr(%rip), %rcx
- addq $16, free_ptr(%rip)
- movq %rcx, %r11
- movq $3, 0(%r11)
- movq %rcx, %r11
- movq %rbx, 8(%r11)
- movq $0, %rdx
- movq %rcx, -8(%r15)
- movq free_ptr(%rip), %rcx
- addq $16, %rcx
- movq fromspace_end(%rip), %rdx
- cmpq %rdx, %rcx
- jl block36
- movq %r15, %rdi
- movq $16, %rsi
- callq collect
- jmp block35
- block39:
- movq $0, %rcx
- jmp block38
- \end{lstlisting}
- \end{minipage}
- \begin{minipage}[t]{0.45\textwidth}
- \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
- start:
- movq $42, %rbx
- movq free_ptr(%rip), %rdx
- addq $16, %rdx
- movq fromspace_end(%rip), %rcx
- cmpq %rcx, %rdx
- jl block39
- movq %r15, %rdi
- movq $16, %rsi
- callq collect
- jmp block38
-
- .globl main
- main:
- pushq %rbp
- movq %rsp, %rbp
- pushq %r13
- pushq %r12
- pushq %rbx
- pushq %r14
- subq $0, %rsp
- movq $16384, %rdi
- movq $16384, %rsi
- callq initialize
- movq rootstack_begin(%rip), %r15
- movq $0, (%r15)
- addq $8, %r15
- jmp start
- conclusion:
- subq $8, %r15
- addq $0, %rsp
- popq %r14
- popq %rbx
- popq %r12
- popq %r13
- popq %rbp
- retq
- \end{lstlisting}
- \end{minipage}
- \caption{Output of the \code{print\_x86} pass.}
- \label{fig:print-x86-output-gc}
- \end{figure}
- \begin{figure}[p]
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (Rvec) at (0,2) {\large \LangVec{}};
- \node (Rvec-2) at (3,2) {\large \LangVec{}};
- \node (Rvec-3) at (6,2) {\large \LangVec{}};
- \node (Rvec-4) at (9,2) {\large \LangVec{}};
- \node (Rvec-5) at (12,2) {\large \LangAlloc{}};
- \node (C2-4) at (3,0) {\large \LangCVec{}};
- \node (x86-2) at (3,-2) {\large \LangXGlobalVar{}};
- \node (x86-2-1) at (3,-4) {\large \LangXGlobalVar{}};
- \node (x86-2-2) at (6,-4) {\large \LangXGlobalVar{}};
- \node (x86-3) at (6,-2) {\large \LangXGlobalVar{}};
- \node (x86-4) at (9,-2) {\large \LangXGlobal{}};
- \node (x86-5) at (9,-4) {\large \LangXGlobal{}};
- %\path[->,bend left=15] (Rvec) edge [above] node {\ttfamily\footnotesize type-check} (Rvec-2);
- \path[->,bend left=15] (Rvec) edge [above] node {\ttfamily\footnotesize shrink} (Rvec-2);
- \path[->,bend left=15] (Rvec-2) edge [above] node {\ttfamily\footnotesize uniquify} (Rvec-3);
- \path[->,bend left=15] (Rvec-3) edge [above] node {\ttfamily\footnotesize expose\_alloc.} (Rvec-4);
- \path[->,bend left=15] (Rvec-4) edge [above] node {\ttfamily\footnotesize remove\_complex.} (Rvec-5);
- \path[->,bend left=20] (Rvec-5) edge [left] node {\ttfamily\footnotesize explicate\_control} (C2-4);
- \path[->,bend left=15] (C2-4) edge [right] node {\ttfamily\footnotesize select\_instr.} (x86-2);
- \path[->,bend right=15] (x86-2) edge [left] node {\ttfamily\footnotesize uncover\_live} (x86-2-1);
- \path[->,bend right=15] (x86-2-1) edge [below] node {\ttfamily\footnotesize build\_inter.} (x86-2-2);
- \path[->,bend right=15] (x86-2-2) edge [right] node {\ttfamily\footnotesize allocate\_reg.} (x86-3);
- \path[->,bend left=15] (x86-3) edge [above] node {\ttfamily\footnotesize patch\_instr.} (x86-4);
- \path[->,bend left=15] (x86-4) edge [right] node {\ttfamily\footnotesize print\_x86} (x86-5);
- \end{tikzpicture}
- \caption{Diagram of the passes for \LangVec{}, a language with tuples.}
- \label{fig:Rvec-passes}
- \end{figure}
- Figure~\ref{fig:Rvec-passes} gives an overview of all the passes needed
- for the compilation of \LangVec{}.
- \section{Challenge: Simple Structures}
- \label{sec:simple-structures}
- \index{subject}{struct}
- \index{subject}{structure}
- Figure~\ref{fig:r3s-concrete-syntax} defines the concrete syntax for
- \LangStruct{}, which extends \LangVec{} with support for simple structures.
- Recall that a \code{struct} in Typed Racket is a user-defined data
- type that contains named fields and that is heap allocated, similar to
- a vector. The following is an example of a structure definition, in
- this case the definition of a \code{point} type.
- \begin{lstlisting}
- (struct point ([x : Integer] [y : Integer]) #:mutable)
- \end{lstlisting}
- \begin{figure}[tbp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \[
- \begin{array}{lcl}
- \Type &::=& \gray{\key{Integer} \MID \key{Boolean}
- \MID (\key{Vector}\;\Type \ldots) \MID \key{Void} } \MID \Var \\
- \itm{cmp} &::= & \gray{ \key{eq?} \MID \key{<} \MID \key{<=} \MID \key{>} \MID \key{>=} } \\
- \Exp &::=& \gray{ \Int \MID (\key{read}) \MID (\key{-}\;\Exp) \MID (\key{+} \; \Exp\;\Exp) \MID (\key{-}\;\Exp\;\Exp) } \\
- &\MID& \gray{ \Var \MID (\key{let}~([\Var~\Exp])~\Exp) }\\
- &\MID& \gray{ \key{\#t} \MID \key{\#f}
- \MID (\key{and}\;\Exp\;\Exp)
- \MID (\key{or}\;\Exp\;\Exp)
- \MID (\key{not}\;\Exp) } \\
- &\MID& \gray{ (\itm{cmp}\;\Exp\;\Exp)
- \MID (\key{if}~\Exp~\Exp~\Exp) } \\
- &\MID& \gray{ (\key{vector}\;\Exp \ldots)
- \MID (\key{vector-ref}\;\Exp\;\Int) } \\
- &\MID& \gray{ (\key{vector-set!}\;\Exp\;\Int\;\Exp) }\\
- &\MID& \gray{ (\key{void}) } \MID (\Var\;\Exp \ldots)\\
- \Def &::=& (\key{struct}\; \Var \; ([\Var \,\key{:}\, \Type] \ldots)\; \code{\#:mutable})\\
- \LangStruct{} &::=& \Def \ldots \; \Exp
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The concrete syntax of \LangStruct{}, extending \LangVec{}
- (Figure~\ref{fig:Rvec-concrete-syntax}).}
- \label{fig:r3s-concrete-syntax}
- \end{figure}
- An instance of a structure is created using function call syntax, with
- the name of the structure in the function position:
- \begin{lstlisting}
- (point 7 12)
- \end{lstlisting}
- Function-call syntax is also used to read the value in a field of a
- structure. The function name is formed by the structure name, a dash,
- and the field name. The following example uses \code{point-x} and
- \code{point-y} to access the \code{x} and \code{y} fields of two point
- instances.
- \begin{center}
- \begin{lstlisting}
- (let ([pt1 (point 7 12)])
- (let ([pt2 (point 4 3)])
- (+ (- (point-x pt1) (point-x pt2))
- (- (point-y pt1) (point-y pt2)))))
- \end{lstlisting}
- \end{center}
- Similarly, to write to a field of a structure, use its set function,
- whose name starts with \code{set-}, followed by the structure name,
- then a dash, then the field name, and concluded with an exclamation
- mark. The following example uses \code{set-point-x!} to change the
- \code{x} field from \code{7} to \code{42}.
- \begin{center}
- \begin{lstlisting}
- (let ([pt (point 7 12)])
- (let ([_ (set-point-x! pt 42)])
- (point-x pt)))
- \end{lstlisting}
- \end{center}
- \begin{exercise}\normalfont
- Extend your compiler with support for simple structures, compiling
- \LangStruct{} to x86 assembly code. Create five new test cases that use
- structures and test your compiler.
- \end{exercise}
- \section{Challenge: Arrays}
- \label{sec:arrays}
- In Chapter~\ref{ch:Rvec} we studied tuples, that is, sequences of
- elements whose length is determined at compile-time and where each
- element of a tuple may have a different type (they are
- heterogeous). This challenge is also about sequences, but this time
- the length is determined at run-time and all the elements have the same
- type (they are homogeneous). We use the term ``array'' for this later
- kind of sequence.
- The Racket language does not distinguish between tuples and arrays,
- they are both represented by vectors. However, Typed Racket
- distinguishes between tuples and arrays: the \code{Vector} type is for
- tuples and the \code{Vectorof} type is for arrays.
- %
- Figure~\ref{fig:Rvecof-concrete-syntax} defines the concrete syntax
- for \LangArray{}, extending \LangLoop{} with the \code{Vectorof} type
- and the \code{make-vector} primitive operator for creating an array,
- whose arguments are the length of the array and an initial value for
- all the elements in the array. The \code{vector-length},
- \code{vector-ref}, and \code{vector-ref!} operators that we defined
- for tuples become overloaded for use with arrays.
- %
- We also include integer multiplication in \LangArray{}, as it is
- useful in many examples involving arrays such as computing the
- inner-product of two arrays (Figure~\ref{fig:inner-product}).
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Type &::=& \ldots \MID \LP \key{Vectorof}~\Type \RP \\
- \Exp &::=& \gray{ \Int \MID \CREAD{} \MID \CNEG{\Exp}
- \MID \CADD{\Exp}{\Exp} \MID \CSUB{\Exp}{\Exp} } \MID \CMUL{\Exp}{\Exp}\\
- &\MID& \gray{ \Var \MID \CLET{\Var}{\Exp}{\Exp} }\\
- &\MID& \gray{\key{\#t} \MID \key{\#f}
- \MID \LP\key{and}\;\Exp\;\Exp\RP
- \MID \LP\key{or}\;\Exp\;\Exp\RP
- \MID \LP\key{not}\;\Exp\RP } \\
- &\MID& \gray{ \LP\key{eq?}\;\Exp\;\Exp\RP \MID \CIF{\Exp}{\Exp}{\Exp} } \\
- &\MID& \gray{ \LP\key{vector}\;\Exp\ldots\RP \MID
- \LP\key{vector-ref}\;\Exp\;\Int\RP} \\
- &\MID& \gray{\LP\key{vector-set!}\;\Exp\;\Int\;\Exp\RP\MID \LP\key{void}\RP
- \MID \LP\Exp \; \Exp\ldots\RP } \\
- &\MID& \gray{ \LP \key{procedure-arity}~\Exp\RP
- \MID \CLAMBDA{\LP\LS\Var \key{:} \Type\RS\ldots\RP}{\Type}{\Exp} } \\
- &\MID& \gray{ \CSETBANG{\Var}{\Exp}
- \MID \CBEGIN{\Exp\ldots}{\Exp}
- \MID \CWHILE{\Exp}{\Exp} } \\
- &\MID& \CMAKEVEC{\Exp}{\Exp} \\
- \Def &::=& \gray{ \CDEF{\Var}{\LS\Var \key{:} \Type\RS\ldots}{\Type}{\Exp} } \\
- \LangArray{} &::=& \gray{\Def\ldots \; \Exp}
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The concrete syntax of \LangArray{}, extending \LangLoop{} (Figure~\ref{fig:Rwhile-concrete-syntax}).}
- \label{fig:Rvecof-concrete-syntax}
- \end{figure}
- \begin{figure}[tp]
- \begin{lstlisting}
- (define (inner-product [A : (Vectorof Integer)] [B : (Vectorof Integer)]
- [n : Integer]) : Integer
- (let ([i 0])
- (let ([prod 0])
- (begin
- (while (< i n)
- (begin
- (set! prod (+ prod (* (vector-ref A i)
- (vector-ref B i))))
- (set! i (+ i 1))
- ))
- prod))))
-
- (let ([A (make-vector 2 2)])
- (let ([B (make-vector 2 3)])
- (+ (inner-product A B 2)
- 30)))
- \end{lstlisting}
- \caption{Example program that computes the inner-product.}
- \label{fig:inner-product}
- \end{figure}
- The type checker for \LangArray{} is define in
- Figure~\ref{fig:type-check-Rvecof}. The result type of
- \code{make-vector} is \code{(Vectorof T)} where \code{T} is the type
- of the intializing expression. The length expression is required to
- have type \code{Integer}. The type checking of the operators
- \code{vector-length}, \code{vector-ref}, and \code{vector-set!} is
- updated to handle the situation where the vector has type
- \code{Vectorof}. In these cases we translate the operators to their
- \code{vectorof} form so that later passes can easily distinguish
- between operations on tuples versus arrays. We override the
- \code{operator-types} method to provide the type signature for
- multiplication: it takes two integers and returns an integer. To
- support injection and projection of arrays to the \code{Any} type
- (Section~\ref{sec:Rany-lang}), we also override the \code{flat-ty?}
- predicate.
- \begin{figure}[tbp]
- \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
- (define type-check-Rvecof_class
- (class type-check-Rwhile_class
- (super-new)
- (inherit check-type-equal?)
- (define/override (flat-ty? ty)
- (match ty
- ['(Vectorof Any) #t]
- [else (super flat-ty? ty)]))
-
- (define/override (operator-types)
- (append '((* . ((Integer Integer) . Integer)))
- (super operator-types)))
-
- (define/override (type-check-exp env)
- (lambda (e)
- (define recur (type-check-exp env))
- (match e
- [(Prim 'make-vector (list e1 e2))
- (define-values (e1^ t1) (recur e1))
- (define-values (e2^ elt-type) (recur e2))
- (define vec-type `(Vectorof ,elt-type))
- (values (HasType (Prim 'make-vector (list e1^ e2^)) vec-type)
- vec-type)]
- [(Prim 'vector-ref (list e1 e2))
- (define-values (e1^ t1) (recur e1))
- (define-values (e2^ t2) (recur e2))
- (match* (t1 t2)
- [(`(Vectorof ,elt-type) 'Integer)
- (values (Prim 'vectorof-ref (list e1^ e2^)) elt-type)]
- [(other wise) ((super type-check-exp env) e)])]
- [(Prim 'vector-set! (list e1 e2 e3) )
- (define-values (e-vec t-vec) (recur e1))
- (define-values (e2^ t2) (recur e2))
- (define-values (e-arg^ t-arg) (recur e3))
- (match t-vec
- [`(Vectorof ,elt-type)
- (check-type-equal? elt-type t-arg e)
- (values (Prim 'vectorof-set! (list e-vec e2^ e-arg^)) 'Void)]
- [else ((super type-check-exp env) e)])]
- [(Prim 'vector-length (list e1))
- (define-values (e1^ t1) (recur e1))
- (match t1
- [`(Vectorof ,t)
- (values (Prim 'vectorof-length (list e1^)) 'Integer)]
- [else ((super type-check-exp env) e)])]
- [else ((super type-check-exp env) e)])))
- ))
- (define (type-check-Rvecof p)
- (send (new type-check-Rvecof_class) type-check-program p))
- \end{lstlisting}
- \caption{Type checker for the \LangArray{} language.}
- \label{fig:type-check-Rvecof}
- \end{figure}
- The interpreter for \LangArray{} is defined in
- Figure~\ref{fig:interp-Rvecof}. The \code{make-vector} operator is
- implemented with Racket's \code{make-vector} function and
- multiplication is \code{fx*}, multiplication for \code{fixnum}
- integers.
- \begin{figure}[tbp]
- \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
- (define interp-Rvecof_class
- (class interp-Rwhile_class
- (super-new)
- (define/override (interp-op op)
- (verbose "Rvecof/interp-op" op)
- (match op
- ['make-vector make-vector]
- ['* fx*]
- [else (super interp-op op)]))
- ))
- (define (interp-Rvecof p)
- (send (new interp-Rvecof_class) interp-program p))
- \end{lstlisting}
- \caption{Interpreter for \LangArray{}.}
- \label{fig:interp-Rvecof}
- \end{figure}
- \subsection{Data Representation}
- \label{sec:array-rep}
- Just like tuples, we store arrays on the heap which means that the
- garbage collector will need to inspect arrays. An immediate thought is
- to use the same representation for arrays that we use for tuples.
- However, we limit tuples to a length of $50$ so that their length and
- pointer mask can fit into the 64-bit tag at the beginning of each
- tuple (Section~\ref{sec:data-rep-gc}). We intend arrays to allow
- millions of elements, so we need more bits to store the length.
- However, because arrays are homogeneous, we only need $1$ bit for the
- pointer mask instead of one bit per array elements. Finally, the
- garbage collector will need to be able to distinguish between tuples
- and arrays, so we need to reserve $1$ bit for that purpose. So we
- arrive at the following layout for the 64-bit tag at the beginning of
- an array:
- \begin{itemize}
- \item The right-most bit is the forwarding bit, just like in a tuple.
- A $0$ indicates it is a forwarding pointer and a $1$ indicates
- it is not.
-
- \item The next bit to the left is the pointer mask. A $0$ indicates
- that none of the elements are pointers to the heap and a $1$
- indicates that all of the elements are pointers.
- \item The next $61$ bits store the length of the array.
- \item The left-most bit distinguishes between a tuple ($0$) versus an
- array ($1$).
- \end{itemize}
- Recall that in Chapter~\ref{ch:Rdyn}, we use a $3$-bit tag to
- differentiate the kinds of values that have been injected into the
- \code{Any} type. We use the bit pattern \code{110} (or $6$ in decimal)
- to indicate that the value is an array.
- In the following subsections we provide hints regarding how to update
- the passes to handle arrays.
- \subsection{Reveal Casts}
- The array-access operators \code{vectorof-ref} and
- \code{vectorof-set!} are similar to the \code{any-vector-ref} and
- \code{any-vector-set!} operators of Chapter~\ref{ch:Rdyn} in
- that the type checker cannot tell whether the index will be in bounds,
- so the bounds check must be performed at run time. Recall that the
- \code{reveal-casts} pass (Section~\ref{sec:reveal-casts-Rany}) wraps
- an \code{If} arround a vector reference for update to check whether
- the index is less than the length. You should do the same for
- \code{vectorof-ref} and \code{vectorof-set!} .
- In addition, the handling of the \code{any-vector} operators in
- \code{reveal-casts} needs to be updated to account for arrays that are
- injected to \code{Any}. For the \code{any-vector-length} operator, the
- generated code should test whether the tag is for tuples (\code{010})
- or arrays (\code{110}) and then dispatch to either
- \code{any-vector-length} or \code{any-vectorof-length}. For the later
- we add a case in \code{select\_instructions} to generate the
- appropriate instructions for accessing the array length from the
- header of an array.
- For the \code{any-vector-ref} and \code{any-vector-set!} operators,
- the generated code needs to check that the index is less than the
- vector length, so like the code for \code{any-vector-length}, check
- the tag to determine whether to use \code{any-vector-length} or
- \code{any-vectorof-length} for this purpose. Once the bounds checking
- is complete, the generated code can use \code{any-vector-ref} and
- \code{any-vector-set!} for both tuples and arrays because the
- instructions used for those operators do not look at the tag at the
- front of the tuple or array.
- \subsection{Expose Allocation}
- This pass should translate the \code{make-vector} operator into
- lower-level operations. In particular, the new AST node
- $\LP\key{AllocateArray}~\Exp~\Type\RP$ allocates an array of the
- length specified by the $\Exp$, but does not initialize the elements
- of the array. (Analogous to the \code{Allocate} AST node for tuples.)
- The $\Type$ argument must be $\LP\key{Vectorof}~T\RP$ where $T$ is the
- element type for the array. Regarding the initialization of the array,
- we recommend generated a \code{while} loop that uses
- \code{vector-set!} to put the initializing value into every element of
- the array.
- \subsection{Remove Complex Operands}
- Add cases in the \code{rco\_atom} and \code{rco\_exp} for
- \code{AllocateArray}. In particular, an \code{AllocateArray} node is
- complex and its subexpression must be atomic.
- \subsection{Explicate Control}
- Add cases for \code{AllocateArray} to \code{explicate\_tail} and
- \code{explicate\_assign}.
- \subsection{Select Instructions}
- Generate instructions for \code{AllocateArray} similar to those for
- \code{Allocate} in Section~\ref{sec:select-instructions-gc} except
- that the tag at the front of the array should instead use the
- representation discussed in Section~\ref{sec:array-rep}.
- Regarding \code{vectorof-length}, extract the length from the tag
- according to the representation discussed in
- Section~\ref{sec:array-rep}.
- The instructions generated for \code{vectorof-ref} differ from those
- for \code{vector-ref} (Section~\ref{sec:select-instructions-gc}) in
- that the index is not a constant so the offset must be computed at
- runtime, similar to the instructions generated for
- \code{any-vector-of-ref} (Section~\ref{sec:select-Rany}). The same is
- true for \code{vectorof-set!}. Also, the \code{vectorof-set!} may
- appear in an assignment and as a stand-alone statement, so make sure
- to handle both situations in this pass.
- Finally, the instructions for \code{any-vectorof-length} should be
- similar to those for \code{vectorof-length}, except that one must
- first project the array by writing zeroes into the $3$-bit tag
- \begin{exercise}\normalfont
- Implement a compiler for the \LangArray{} language by extending your
- compiler for \LangLoop{}. Test your compiler on a half dozen new
- programs, including the one in Figure~\ref{fig:inner-product} and also
- a program that multiplies two matrices. Note that matrices are
- 2-dimensional arrays, but those can be encoded into 1-dimensional
- arrays by laying out each row in the array, one after the next.
-
- \end{exercise}
- \section{Challenge: Generational Collection}
- The copying collector described in Section~\ref{sec:GC} can incur
- significant runtime overhead because the call to \code{collect} takes
- time proportional to all of the live data. One way to reduce this
- overhead is to reduce how much data is inspected in each call to
- \code{collect}. In particular, researchers have observed that recently
- allocated data is more likely to become garbage then data that has
- survived one or more previous calls to \code{collect}. This insight
- motivated the creation of \emph{generational garbage collectors}
- \index{subject}{generational garbage collector} that
- 1) segregates data according to its age into two or more generations,
- 2) allocates less space for younger generations, so collecting them is
- faster, and more space for the older generations, and 3) performs
- collection on the younger generations more frequently then for older
- generations~\citep{Wilson:1992fk}.
- For this challenge assignment, the goal is to adapt the copying
- collector implemented in \code{runtime.c} to use two generations, one
- for young data and one for old data. Each generation consists of a
- FromSpace and a ToSpace. The following is a sketch of how to adapt the
- \code{collect} function to use the two generations.
- \begin{enumerate}
- \item Copy the young generation's FromSpace to its ToSpace then switch
- the role of the ToSpace and FromSpace
- \item If there is enough space for the requested number of bytes in
- the young FromSpace, then return from \code{collect}.
- \item If there is not enough space in the young FromSpace for the
- requested bytes, then move the data from the young generation to the
- old one with the following steps:
- \begin{enumerate}
- \item If there is enough room in the old FromSpace, copy the young
- FromSpace to the old FromSpace and then return.
- \item If there is not enough room in the old FromSpace, then collect
- the old generation by copying the old FromSpace to the old ToSpace
- and swap the roles of the old FromSpace and ToSpace.
- \item If there is enough room now, copy the young FromSpace to the
- old FromSpace and return. Otherwise, allocate a larger FromSpace
- and ToSpace for the old generation. Copy the young FromSpace and
- the old FromSpace into the larger FromSpace for the old
- generation and then return.
- \end{enumerate}
- \end{enumerate}
- We recommend that you generalize the \code{cheney} function so that it
- can be used for all the copies mentioned above: between the young
- FromSpace and ToSpace, between the old FromSpace and ToSpace, and
- between the young FromSpace and old FromSpace. This can be
- accomplished by adding parameters to \code{cheney} that replace its
- use of the global variables \code{fromspace\_begin},
- \code{fromspace\_end}, \code{tospace\_begin}, and \code{tospace\_end}.
- Note that the collection of the young generation does not traverse the
- old generation. This introduces a potential problem: there may be
- young data that is only reachable through pointers in the old
- generation. If these pointers are not taken into account, the
- collector could throw away young data that is live! One solution,
- called \emph{pointer recording}, is to maintain a set of all the
- pointers from the old generation into the new generation and consider
- this set as part of the root set. To maintain this set, the compiler
- must insert extra instructions around every \code{vector-set!}. If the
- vector being modified is in the old generation, and if the value being
- written is a pointer into the new generation, than that pointer must
- be added to the set. Also, if the value being overwritten was a
- pointer into the new generation, then that pointer should be removed
- from the set.
- \begin{exercise}\normalfont
- Adapt the \code{collect} function in \code{runtime.c} to implement
- generational garbage collection, as outlined in this section.
- Update the code generation for \code{vector-set!} to implement
- pointer recording. Make sure that your new compiler and runtime
- passes your test suite.
- \end{exercise}
- % Further Reading
- \fi % racketEd
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- \chapter{Functions}
- \label{ch:Rfun}
- \index{subject}{function}
- \if\edition\racketEd
- This chapter studies the compilation of functions similar to those
- found in the C language. This corresponds to a subset of Typed Racket
- in which only top-level function definitions are allowed. This kind of
- function is an important stepping stone to implementing
- lexically-scoped functions, that is, \key{lambda} abstractions, which
- is the topic of Chapter~\ref{ch:Rlam}.
- \section{The \LangFun{} Language}
- The concrete and abstract syntax for function definitions and function
- application is shown in Figures~\ref{fig:Rfun-concrete-syntax} and
- \ref{fig:Rfun-syntax}, where we define the \LangFun{} language. Programs in
- \LangFun{} begin with zero or more function definitions. The function
- names from these definitions are in-scope for the entire program,
- including all other function definitions (so the ordering of function
- definitions does not matter). The concrete syntax for function
- application\index{subject}{function application} is $(\Exp \; \Exp \ldots)$
- where the first expression must
- evaluate to a function and the rest are the arguments.
- The abstract syntax for function application is
- $\APPLY{\Exp}{\Exp\ldots}$.
- %% The syntax for function application does not include an explicit
- %% keyword, which is error prone when using \code{match}. To alleviate
- %% this problem, we translate the syntax from $(\Exp \; \Exp \ldots)$ to
- %% $(\key{app}\; \Exp \; \Exp \ldots)$ during type checking.
- Functions are first-class in the sense that a function pointer
- \index{subject}{function pointer} is data and can be stored in memory or passed
- as a parameter to another function. Thus, we introduce a function
- type, written
- \begin{lstlisting}
- (|$\Type_1$| |$\cdots$| |$\Type_n$| -> |$\Type_r$|)
- \end{lstlisting}
- for a function whose $n$ parameters have the types $\Type_1$ through
- $\Type_n$ and whose return type is $\Type_r$. The main limitation of
- these functions (with respect to Racket functions) is that they are
- not lexically scoped. That is, the only external entities that can be
- referenced from inside a function body are other globally-defined
- functions. The syntax of \LangFun{} prevents functions from being nested
- inside each other.
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Type &::=& \gray{ \key{Integer} \MID \key{Boolean}
- \MID (\key{Vector}\;\Type\ldots) \MID \key{Void} } \MID (\Type \ldots \; \key{->}\; \Type) \\
- \itm{cmp} &::= & \gray{ \key{eq?} \MID \key{<} \MID \key{<=} \MID \key{>} \MID \key{>=} } \\
- \Exp &::=& \gray{ \Int \MID \CREAD{} \MID \CNEG{\Exp} \MID \CADD{\Exp}{\Exp} \MID \CSUB{\Exp}{\Exp} } \\
- &\MID& \gray{ \Var \MID \CLET{\Var}{\Exp}{\Exp} }\\
- &\MID& \gray{ \key{\#t} \MID \key{\#f}
- \MID (\key{and}\;\Exp\;\Exp)
- \MID (\key{or}\;\Exp\;\Exp)
- \MID (\key{not}\;\Exp)} \\
- &\MID& \gray{(\itm{cmp}\;\Exp\;\Exp) \MID \CIF{\Exp}{\Exp}{\Exp} } \\
- &\MID& \gray{(\key{vector}\;\Exp\ldots) \MID
- (\key{vector-ref}\;\Exp\;\Int)} \\
- &\MID& \gray{(\key{vector-set!}\;\Exp\;\Int\;\Exp)\MID (\key{void})
- \MID \LP\key{has-type}~\Exp~\Type\RP } \\
- &\MID& \LP\Exp \; \Exp \ldots\RP \\
- \Def &::=& \CDEF{\Var}{\LS\Var \key{:} \Type\RS \ldots}{\Type}{\Exp} \\
- \LangFunM{} &::=& \Def \ldots \; \Exp
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The concrete syntax of \LangFun{}, extending \LangVec{} (Figure~\ref{fig:Rvec-concrete-syntax}).}
- \label{fig:Rfun-concrete-syntax}
- \end{figure}
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Exp &::=& \gray{ \INT{\Int} \MID \VAR{\Var} \MID \LET{\Var}{\Exp}{\Exp} } \\
- &\MID& \gray{ \PRIM{\itm{op}}{\Exp\ldots} }\\
- &\MID& \gray{ \BOOL{\itm{bool}}
- \MID \IF{\Exp}{\Exp}{\Exp} } \\
- &\MID& \gray{ \VOID{} \MID \LP\key{HasType}~\Exp~\Type \RP }
- \MID \APPLY{\Exp}{\Exp\ldots}\\
- \Def &::=& \FUNDEF{\Var}{\LP[\Var \code{:} \Type]\ldots\RP}{\Type}{\code{'()}}{\Exp}\\
- \LangFunM{} &::=& \PROGRAMDEFSEXP{\code{'()}}{\LP\Def\ldots\RP)}{\Exp}
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The abstract syntax of \LangFun{}, extending \LangVec{} (Figure~\ref{fig:Rvec-syntax}).}
- \label{fig:Rfun-syntax}
- \end{figure}
- The program in Figure~\ref{fig:Rfun-function-example} is a
- representative example of defining and using functions in \LangFun{}. We
- define a function \code{map-vec} that applies some other function
- \code{f} to both elements of a vector and returns a new
- vector containing the results. We also define a function \code{add1}.
- The program applies
- \code{map-vec} to \code{add1} and \code{(vector 0 41)}. The result is
- \code{(vector 1 42)}, from which we return the \code{42}.
- \begin{figure}[tbp]
- \begin{lstlisting}
- (define (map-vec [f : (Integer -> Integer)]
- [v : (Vector Integer Integer)])
- : (Vector Integer Integer)
- (vector (f (vector-ref v 0)) (f (vector-ref v 1))))
- (define (add1 [x : Integer]) : Integer
- (+ x 1))
- (vector-ref (map-vec add1 (vector 0 41)) 1)
- \end{lstlisting}
- \caption{Example of using functions in \LangFun{}.}
- \label{fig:Rfun-function-example}
- \end{figure}
- The definitional interpreter for \LangFun{} is in
- Figure~\ref{fig:interp-Rfun}. The case for the \code{ProgramDefsExp} form is
- responsible for setting up the mutual recursion between the top-level
- function definitions. We use the classic back-patching \index{subject}{back-patching}
- approach that uses mutable variables and makes two passes over the function
- definitions~\citep{Kelsey:1998di}. In the first pass we set up the
- top-level environment using a mutable cons cell for each function
- definition. Note that the \code{lambda} value for each function is
- incomplete; it does not yet include the environment. Once the
- top-level environment is constructed, we then iterate over it and
- update the \code{lambda} values to use the top-level environment.
- \begin{figure}[tp]
- \begin{lstlisting}
- (define interp-Rfun_class
- (class interp-Rvec_class
- (super-new)
- (define/override ((interp-exp env) e)
- (define recur (interp-exp env))
- (match e
- [(Var x) (unbox (dict-ref env x))]
- [(Let x e body)
- (define new-env (dict-set env x (box (recur e))))
- ((interp-exp new-env) body)]
- [(Apply fun args)
- (define fun-val (recur fun))
- (define arg-vals (for/list ([e args]) (recur e)))
- (match fun-val
- [`(function (,xs ...) ,body ,fun-env)
- (define params-args (for/list ([x xs] [arg arg-vals])
- (cons x (box arg))))
- (define new-env (append params-args fun-env))
- ((interp-exp new-env) body)]
- [else (error 'interp-exp "expected function, not ~a" fun-val)])]
- [else ((super interp-exp env) e)]
- ))
- (define/public (interp-def d)
- (match d
- [(Def f (list `[,xs : ,ps] ...) rt _ body)
- (cons f (box `(function ,xs ,body ())))]))
- (define/override (interp-program p)
- (match p
- [(ProgramDefsExp info ds body)
- (let ([top-level (for/list ([d ds]) (interp-def d))])
- (for/list ([f (in-dict-values top-level)])
- (set-box! f (match (unbox f)
- [`(function ,xs ,body ())
- `(function ,xs ,body ,top-level)])))
- ((interp-exp top-level) body))]))
- ))
- (define (interp-Rfun p)
- (send (new interp-Rfun_class) interp-program p))
- \end{lstlisting}
- \caption{Interpreter for the \LangFun{} language.}
- \label{fig:interp-Rfun}
- \end{figure}
- %\margincomment{TODO: explain type checker}
- The type checker for \LangFun{} is in Figure~\ref{fig:type-check-Rfun}.
- \begin{figure}[tp]
- \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
- (define type-check-Rfun_class
- (class type-check-Rvec_class
- (super-new)
- (inherit check-type-equal?)
- (define/public (type-check-apply env e es)
- (define-values (e^ ty) ((type-check-exp env) e))
- (define-values (e* ty*) (for/lists (e* ty*) ([e (in-list es)])
- ((type-check-exp env) e)))
- (match ty
- [`(,ty^* ... -> ,rt)
- (for ([arg-ty ty*] [param-ty ty^*])
- (check-type-equal? arg-ty param-ty (Apply e es)))
- (values e^ e* rt)]))
- (define/override (type-check-exp env)
- (lambda (e)
- (match e
- [(FunRef f)
- (values (FunRef f) (dict-ref env f))]
- [(Apply e es)
- (define-values (e^ es^ rt) (type-check-apply env e es))
- (values (Apply e^ es^) rt)]
- [(Call e es)
- (define-values (e^ es^ rt) (type-check-apply env e es))
- (values (Call e^ es^) rt)]
- [else ((super type-check-exp env) e)])))
- (define/public (type-check-def env)
- (lambda (e)
- (match e
- [(Def f (and p:t* (list `[,xs : ,ps] ...)) rt info body)
- (define new-env (append (map cons xs ps) env))
- (define-values (body^ ty^) ((type-check-exp new-env) body))
- (check-type-equal? ty^ rt body)
- (Def f p:t* rt info body^)])))
- (define/public (fun-def-type d)
- (match d
- [(Def f (list `[,xs : ,ps] ...) rt info body) `(,@ps -> ,rt)]))
- (define/override (type-check-program e)
- (match e
- [(ProgramDefsExp info ds body)
- (define new-env (for/list ([d ds])
- (cons (Def-name d) (fun-def-type d))))
- (define ds^ (for/list ([d ds]) ((type-check-def new-env) d)))
- (define-values (body^ ty) ((type-check-exp new-env) body))
- (check-type-equal? ty 'Integer body)
- (ProgramDefsExp info ds^ body^)]))))
- (define (type-check-Rfun p)
- (send (new type-check-Rfun_class) type-check-program p))
- \end{lstlisting}
- \caption{Type checker for the \LangFun{} language.}
- \label{fig:type-check-Rfun}
- \end{figure}
- \section{Functions in x86}
- \label{sec:fun-x86}
- %% \margincomment{\tiny Make sure callee-saved registers are discussed
- %% in enough depth, especially updating Fig 6.4 \\ --Jeremy }
- %% \margincomment{\tiny Talk about the return address on the
- %% stack and what callq and retq does.\\ --Jeremy }
- The x86 architecture provides a few features to support the
- implementation of functions. We have already seen that x86 provides
- labels so that one can refer to the location of an instruction, as is
- needed for jump instructions. Labels can also be used to mark the
- beginning of the instructions for a function. Going further, we can
- obtain the address of a label by using the \key{leaq} instruction and
- PC-relative addressing. For example, the following puts the
- address of the \code{add1} label into the \code{rbx} register.
- \begin{lstlisting}
- leaq add1(%rip), %rbx
- \end{lstlisting}
- The instruction pointer register \key{rip} (aka. the program counter
- \index{subject}{program counter}) always points to the next instruction to be
- executed. When combined with an label, as in \code{add1(\%rip)}, the
- linker computes the distance $d$ between the address of \code{add1}
- and where the \code{rip} would be at that moment and then changes
- \code{add1(\%rip)} to \code{$d$(\%rip)}, which at runtime will compute
- the address of \code{add1}.
- In Section~\ref{sec:x86} we used of the \code{callq} instruction to
- jump to a function whose location is given by a label. To support
- function calls in this chapter we instead will be jumping to a
- function whose location is given by an address in a register, that is,
- we need to make an \emph{indirect function call}. The x86 syntax for
- this is a \code{callq} instruction but with an asterisk before the
- register name.\index{subject}{indirect function call}
- \begin{lstlisting}
- callq *%rbx
- \end{lstlisting}
- \subsection{Calling Conventions}
- \index{subject}{calling conventions}
- The \code{callq} instruction provides partial support for implementing
- functions: it pushes the return address on the stack and it jumps to
- the target. However, \code{callq} does not handle
- \begin{enumerate}
- \item parameter passing,
- \item pushing frames on the procedure call stack and popping them off,
- or
- \item determining how registers are shared by different functions.
- \end{enumerate}
- Regarding (1) parameter passing, recall that the following six
- registers are used to pass arguments to a function, in this order.
- \begin{lstlisting}
- rdi rsi rdx rcx r8 r9
- \end{lstlisting}
- If there are
- more than six arguments, then the convention is to use space on the
- frame of the caller for the rest of the arguments. However, to ease
- the implementation of efficient tail calls
- (Section~\ref{sec:tail-call}), we arrange never to need more than six
- arguments.
- %
- Also recall that the register \code{rax} is for the return value of
- the function.
- \index{subject}{prelude}\index{subject}{conclusion}
- Regarding (2) frames \index{subject}{frame} and the procedure call stack,
- \index{subject}{procedure call stack} recall from Section~\ref{sec:x86} that
- the stack grows down, with each function call using a chunk of space
- called a frame. The caller sets the stack pointer, register
- \code{rsp}, to the last data item in its frame. The callee must not
- change anything in the caller's frame, that is, anything that is at or
- above the stack pointer. The callee is free to use locations that are
- below the stack pointer.
- Recall that we are storing variables of vector type on the root stack.
- So the prelude needs to move the root stack pointer \code{r15} up and
- the conclusion needs to move the root stack pointer back down. Also,
- the prelude must initialize to \code{0} this frame's slots in the root
- stack to signal to the garbage collector that those slots do not yet
- contain a pointer to a vector. Otherwise the garbage collector will
- interpret the garbage bits in those slots as memory addresses and try
- to traverse them, causing serious mayhem!
- Regarding (3) the sharing of registers between different functions,
- recall from Section~\ref{sec:calling-conventions} that the registers
- are divided into two groups, the caller-saved registers and the
- callee-saved registers. The caller should assume that all the
- caller-saved registers get overwritten with arbitrary values by the
- callee. That is why we recommend in
- Section~\ref{sec:calling-conventions} that variables that are live
- during a function call should not be assigned to caller-saved
- registers.
- On the flip side, if the callee wants to use a callee-saved register,
- the callee must save the contents of those registers on their stack
- frame and then put them back prior to returning to the caller. That
- is why we recommended in Section~\ref{sec:calling-conventions} that if
- the register allocator assigns a variable to a callee-saved register,
- then the prelude of the \code{main} function must save that register
- to the stack and the conclusion of \code{main} must restore it. This
- recommendation now generalizes to all functions.
- Also recall that the base pointer, register \code{rbp}, is used as a
- point-of-reference within a frame, so that each local variable can be
- accessed at a fixed offset from the base pointer
- (Section~\ref{sec:x86}).
- %
- Figure~\ref{fig:call-frames} shows the general layout of the caller
- and callee frames.
- \begin{figure}[tbp]
- \centering
- \begin{tabular}{r|r|l|l} \hline
- Caller View & Callee View & Contents & Frame \\ \hline
- 8(\key{\%rbp}) & & return address & \multirow{5}{*}{Caller}\\
- 0(\key{\%rbp}) & & old \key{rbp} \\
- -8(\key{\%rbp}) & & callee-saved $1$ \\
- \ldots & & \ldots \\
- $-8j$(\key{\%rbp}) & & callee-saved $j$ \\
- $-8(j+1)$(\key{\%rbp}) & & local variable $1$ \\
- \ldots & & \ldots \\
- $-8(j+k)$(\key{\%rbp}) & & local variable $k$ \\
- %% & & \\
- %% $8n-8$\key{(\%rsp)} & $8n+8$(\key{\%rbp})& argument $n$ \\
- %% & \ldots & \ldots \\
- %% 0\key{(\%rsp)} & 16(\key{\%rbp}) & argument $1$ & \\
- \hline
- & 8(\key{\%rbp}) & return address & \multirow{5}{*}{Callee}\\
- & 0(\key{\%rbp}) & old \key{rbp} \\
- & -8(\key{\%rbp}) & callee-saved $1$ \\
- & \ldots & \ldots \\
- & $-8n$(\key{\%rbp}) & callee-saved $n$ \\
- & $-8(n+1)$(\key{\%rbp}) & local variable $1$ \\
- & \ldots & \ldots \\
- & $-8(n+m)$(\key{\%rsp}) & local variable $m$\\ \hline
- \end{tabular}
- \caption{Memory layout of caller and callee frames.}
- \label{fig:call-frames}
- \end{figure}
- %% Recall from Section~\ref{sec:x86} that the stack is also used for
- %% local variables and for storing the values of callee-saved registers
- %% (we shall refer to all of these collectively as ``locals''), and that
- %% at the beginning of a function we move the stack pointer \code{rsp}
- %% down to make room for them.
- %% We recommend storing the local variables
- %% first and then the callee-saved registers, so that the local variables
- %% can be accessed using \code{rbp} the same as before the addition of
- %% functions.
- %% To make additional room for passing arguments, we shall
- %% move the stack pointer even further down. We count how many stack
- %% arguments are needed for each function call that occurs inside the
- %% body of the function and find their maximum. Adding this number to the
- %% number of locals gives us how much the \code{rsp} should be moved at
- %% the beginning of the function. In preparation for a function call, we
- %% offset from \code{rsp} to set up the stack arguments. We put the first
- %% stack argument in \code{0(\%rsp)}, the second in \code{8(\%rsp)}, and
- %% so on.
- %% Upon calling the function, the stack arguments are retrieved by the
- %% callee using the base pointer \code{rbp}. The address \code{16(\%rbp)}
- %% is the location of the first stack argument, \code{24(\%rbp)} is the
- %% address of the second, and so on. Figure~\ref{fig:call-frames} shows
- %% the layout of the caller and callee frames. Notice how important it is
- %% that we correctly compute the maximum number of arguments needed for
- %% function calls; if that number is too small then the arguments and
- %% local variables will smash into each other!
- \subsection{Efficient Tail Calls}
- \label{sec:tail-call}
- In general, the amount of stack space used by a program is determined
- by the longest chain of nested function calls. That is, if function
- $f_1$ calls $f_2$, $f_2$ calls $f_3$, $\ldots$, and $f_{n-1}$ calls
- $f_n$, then the amount of stack space is bounded by $O(n)$. The depth
- $n$ can grow quite large in the case of recursive or mutually
- recursive functions. However, in some cases we can arrange to use only
- constant space, i.e. $O(1)$, instead of $O(n)$.
- If a function call is the last action in a function body, then that
- call is said to be a \emph{tail call}\index{subject}{tail call}.
- For example, in the following
- program, the recursive call to \code{tail-sum} is a tail call.
- \begin{center}
- \begin{lstlisting}
- (define (tail-sum [n : Integer] [r : Integer]) : Integer
- (if (eq? n 0)
- r
- (tail-sum (- n 1) (+ n r))))
- (+ (tail-sum 5 0) 27)
- \end{lstlisting}
- \end{center}
- At a tail call, the frame of the caller is no longer needed, so we
- can pop the caller's frame before making the tail call. With this
- approach, a recursive function that only makes tail calls will only
- use $O(1)$ stack space. Functional languages like Racket typically
- rely heavily on recursive functions, so they typically guarantee that
- all tail calls will be optimized in this way.
- \index{subject}{frame}
- However, some care is needed with regards to argument passing in tail
- calls. As mentioned above, for arguments beyond the sixth, the
- convention is to use space in the caller's frame for passing
- arguments. But for a tail call we pop the caller's frame and can no
- longer use it. Another alternative is to use space in the callee's
- frame for passing arguments. However, this option is also problematic
- because the caller and callee's frame overlap in memory. As we begin
- to copy the arguments from their sources in the caller's frame, the
- target locations in the callee's frame might overlap with the sources
- for later arguments! We solve this problem by using the heap instead
- of the stack for passing more than six arguments, as we describe in
- the Section~\ref{sec:limit-functions-r4}.
- As mentioned above, for a tail call we pop the caller's frame prior to
- making the tail call. The instructions for popping a frame are the
- instructions that we usually place in the conclusion of a
- function. Thus, we also need to place such code immediately before
- each tail call. These instructions include restoring the callee-saved
- registers, so it is good that the argument passing registers are all
- caller-saved registers.
- One last note regarding which instruction to use to make the tail
- call. When the callee is finished, it should not return to the current
- function, but it should return to the function that called the current
- one. Thus, the return address that is already on the stack is the
- right one, and we should not use \key{callq} to make the tail call, as
- that would unnecessarily overwrite the return address. Instead we can
- simply use the \key{jmp} instruction. Like the indirect function call,
- we write an \emph{indirect jump}\index{subject}{indirect jump} with a register
- prefixed with an asterisk. We recommend using \code{rax} to hold the
- jump target because the preceding conclusion overwrites just about
- everything else.
- \begin{lstlisting}
- jmp *%rax
- \end{lstlisting}
- \section{Shrink \LangFun{}}
- \label{sec:shrink-r4}
- The \code{shrink} pass performs a minor modification to ease the
- later passes. This pass introduces an explicit \code{main} function
- and changes the top \code{ProgramDefsExp} form to
- \code{ProgramDefs} as follows.
- \begin{lstlisting}
- (ProgramDefsExp |$\itm{info}$| (|$\Def\ldots$|) |$\Exp$|)
- |$\Rightarrow$| (ProgramDefs |$\itm{info}$| (|$\Def\ldots$| |$\itm{mainDef}$|))
- \end{lstlisting}
- where $\itm{mainDef}$ is
- \begin{lstlisting}
- (Def 'main '() 'Integer '() |$\Exp'$|)
- \end{lstlisting}
- \section{Reveal Functions and the \LangFunRef{} language}
- \label{sec:reveal-functions-r4}
- The syntax of \LangFun{} is inconvenient for purposes of compilation in one
- respect: it conflates the use of function names and local
- variables. This is a problem because we need to compile the use of a
- function name differently than the use of a local variable; we need to
- use \code{leaq} to convert the function name (a label in x86) to an
- address in a register. Thus, it is a good idea to create a new pass
- that changes function references from just a symbol $f$ to
- $\FUNREF{f}$. This pass is named \code{reveal-functions} and the
- output language, \LangFunRef{}, is defined in Figure~\ref{fig:f1-syntax}.
- The concrete syntax for a function reference is $\CFUNREF{f}$.
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \[
- \begin{array}{lcl}
- \Exp &::=& \ldots \MID \FUNREF{\Var}\\
- \Def &::=& \gray{ \FUNDEF{\Var}{([\Var \code{:} \Type]\ldots)}{\Type}{\code{'()}}{\Exp} }\\
- \LangFunRefM{} &::=& \PROGRAMDEFS{\code{'()}}{\LP \Def\ldots \RP}
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The abstract syntax \LangFunRef{}, an extension of \LangFun{}
- (Figure~\ref{fig:Rfun-syntax}).}
- \label{fig:f1-syntax}
- \end{figure}
- %% Distinguishing between calls in tail position and non-tail position
- %% requires the pass to have some notion of context. We recommend using
- %% two mutually recursive functions, one for processing expressions in
- %% tail position and another for the rest.
- Placing this pass after \code{uniquify} will make sure that there are
- no local variables and functions that share the same name. On the
- other hand, \code{reveal-functions} needs to come before the
- \code{explicate\_control} pass because that pass helps us compile
- \code{FunRef} forms into assignment statements.
- \section{Limit Functions}
- \label{sec:limit-functions-r4}
- Recall that we wish to limit the number of function parameters to six
- so that we do not need to use the stack for argument passing, which
- makes it easier to implement efficient tail calls. However, because
- the input language \LangFun{} supports arbitrary numbers of function
- arguments, we have some work to do!
- This pass transforms functions and function calls that involve more
- than six arguments to pass the first five arguments as usual, but it
- packs the rest of the arguments into a vector and passes it as the
- sixth argument.
- Each function definition with too many parameters is transformed as
- follows.
- \begin{lstlisting}
- (Def |$f$| ([|$x_1$|:|$T_1$|] |$\ldots$| [|$x_n$|:|$T_n$|]) |$T_r$| |$\itm{info}$| |$\itm{body}$|)
- |$\Rightarrow$|
- (Def |$f$| ([|$x_1$|:|$T_1$|] |$\ldots$| [|$x_5$|:|$T_5$|] [vec : (Vector |$T_6 \ldots T_n$|)]) |$T_r$| |$\itm{info}$| |$\itm{body}'$|)
- \end{lstlisting}
- where the $\itm{body}$ is transformed into $\itm{body}'$ by replacing
- the occurrences of the later parameters with vector references.
- \begin{lstlisting}
- (Var |$x_i$|) |$\Rightarrow$| (Prim 'vector-ref (list vec (Int |$(i - 6)$|)))
- \end{lstlisting}
- For function calls with too many arguments, the \code{limit-functions}
- pass transforms them in the following way.
- \begin{tabular}{lll}
- \begin{minipage}{0.2\textwidth}
- \begin{lstlisting}
- (|$e_0$| |$e_1$| |$\ldots$| |$e_n$|)
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow$
- &
- \begin{minipage}{0.4\textwidth}
- \begin{lstlisting}
- (|$e_0$| |$e_1 \ldots e_5$| (vector |$e_6 \ldots e_n$|))
- \end{lstlisting}
- \end{minipage}
- \end{tabular}
- \section{Remove Complex Operands}
- \label{sec:rco-r4}
- The primary decisions to make for this pass is whether to classify
- \code{FunRef} and \code{Apply} as either atomic or complex
- expressions. Recall that a simple expression will eventually end up as
- just an immediate argument of an x86 instruction. Function
- application will be translated to a sequence of instructions, so
- \code{Apply} must be classified as complex expression.
- On the other hand, the arguments of \code{Apply} should be
- atomic expressions.
- %
- Regarding \code{FunRef}, as discussed above, the function label needs
- to be converted to an address using the \code{leaq} instruction. Thus,
- even though \code{FunRef} seems rather simple, it needs to be
- classified as a complex expression so that we generate an assignment
- statement with a left-hand side that can serve as the target of the
- \code{leaq}. Figure~\ref{fig:Rfun-anf-syntax} defines the
- output language \LangFunANF{} of this pass.
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{rcl}
- \Atm &::=& \gray{ \INT{\Int} \MID \VAR{\Var} \MID \BOOL{\itm{bool}}
- \MID \VOID{} } \\
- \Exp &::=& \gray{ \Atm \MID \READ{} } \\
- &\MID& \gray{ \NEG{\Atm} \MID \ADD{\Atm}{\Atm} } \\
- &\MID& \gray{ \LET{\Var}{\Exp}{\Exp} } \\
- &\MID& \gray{ \UNIOP{\key{'not}}{\Atm} } \\
- &\MID& \gray{ \BINOP{\itm{cmp}}{\Atm}{\Atm} \MID \IF{\Exp}{\Exp}{\Exp} }\\
- &\MID& \gray{ \LP\key{Collect}~\Int\RP \MID \LP\key{Allocate}~\Int~\Type\RP
- \MID \LP\key{GlobalValue}~\Var\RP }\\
- &\MID& \FUNREF{\Var} \MID \APPLY{\Atm}{\Atm\ldots}\\
- \Def &::=& \gray{ \FUNDEF{\Var}{([\Var \code{:} \Type]\ldots)}{\Type}{\code{'()}}{\Exp} }\\
- R^{\dagger}_4 &::=& \gray{ \PROGRAMDEFS{\code{'()}}{\Def} }
- \end{array}
- \]
- \end{minipage}
- }
- \caption{\LangFunANF{} is \LangFun{} in administrative normal form (ANF).}
- \label{fig:Rfun-anf-syntax}
- \end{figure}
- \section{Explicate Control and the \LangCFun{} language}
- \label{sec:explicate-control-r4}
- Figure~\ref{fig:c3-syntax} defines the abstract syntax for \LangCFun{}, the
- output of \code{explicate\_control}. (The concrete syntax is given in
- Figure~\ref{fig:c3-concrete-syntax} of the Appendix.) The auxiliary
- functions for assignment and tail contexts should be updated with
- cases for \code{Apply} and \code{FunRef} and the function for
- predicate context should be updated for \code{Apply} but not
- \code{FunRef}. (A \code{FunRef} can't be a Boolean.) In assignment
- and predicate contexts, \code{Apply} becomes \code{Call}, whereas in
- tail position \code{Apply} becomes \code{TailCall}. We recommend
- defining a new auxiliary function for processing function definitions.
- This code is similar to the case for \code{Program} in \LangVec{}. The
- top-level \code{explicate\_control} function that handles the
- \code{ProgramDefs} form of \LangFun{} can then apply this new function to
- all the function definitions.
- \begin{figure}[tp]
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Atm &::=& \gray{ \INT{\Int} \MID \VAR{\Var} \MID \BOOL{\itm{bool}} }\\
- \itm{cmp} &::= & \gray{ \key{eq?} \MID \key{<} } \\
- \Exp &::= & \gray{ \Atm \MID \READ{} } \\
- &\MID& \gray{ \NEG{\Atm} \MID \ADD{\Atm}{\Atm} }\\
- &\MID& \gray{ \UNIOP{\key{not}}{\Atm} \MID \BINOP{\itm{cmp}}{\Atm}{\Atm} } \\
- &\MID& \gray{ \LP\key{Allocate} \,\itm{int}\,\itm{type}\RP } \\
- &\MID& \gray{ \BINOP{\key{'vector-ref}}{\Atm}{\INT{\Int}} }\\
- &\MID& \gray{ \LP\key{Prim}~\key{'vector-set!}\,\LP\key{list}\,\Atm\,\INT{\Int}\,\Atm\RP\RP }\\
- &\MID& \gray{ \LP\key{GlobalValue} \,\Var\RP \MID \LP\key{Void}\RP }\\
- &\MID& \FUNREF{\itm{label}} \MID \CALL{\Atm}{\LP\Atm\ldots\RP} \\
- \Stmt &::=& \gray{ \ASSIGN{\VAR{\Var}}{\Exp}
- \MID \LP\key{Collect} \,\itm{int}\RP } \\
- \Tail &::= & \gray{ \RETURN{\Exp} \MID \SEQ{\Stmt}{\Tail}
- \MID \GOTO{\itm{label}} } \\
- &\MID& \gray{ \IFSTMT{\BINOP{\itm{cmp}}{\Atm}{\Atm}}{\GOTO{\itm{label}}}{\GOTO{\itm{label}}} }\\
- &\MID& \TAILCALL{\Atm}{\Atm\ldots} \\
- \Def &::=& \DEF{\itm{label}}{\LP[\Var\key{:}\Type]\ldots\RP}{\Type}{\itm{info}}{\LP\LP\itm{label}\,\key{.}\,\Tail\RP\ldots\RP}\\
- \LangCFunM{} & ::= & \PROGRAMDEFS{\itm{info}}{\LP\Def\ldots\RP}
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The abstract syntax of \LangCFun{}, extending \LangCVec{} (Figure~\ref{fig:c2-syntax}).}
- \label{fig:c3-syntax}
- \end{figure}
- \section{Select Instructions and the \LangXIndCall{} Language}
- \label{sec:select-r4}
- \index{subject}{instruction selection}
- The output of select instructions is a program in the \LangXIndCall{}
- language, whose syntax is defined in Figure~\ref{fig:x86-3}.
- \index{subject}{x86}
- \begin{figure}[tp]
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Arg &::=& \gray{ \key{\$}\Int \MID \key{\%}\Reg \MID \Int\key{(}\key{\%}\Reg\key{)} \MID \key{\%}\itm{bytereg} } \MID \Var \key{(\%rip)}
- \MID \LP\key{fun-ref}\; \itm{label}\RP\\
- \itm{cc} & ::= & \gray{ \key{e} \MID \key{l} \MID \key{le} \MID \key{g} \MID \key{ge} } \\
- \Instr &::=& \ldots
- \MID \key{callq}\;\key{*}\Arg \MID \key{tailjmp}\;\Arg
- \MID \key{leaq}\;\Arg\key{,}\;\key{\%}\Reg \\
- \Block &::= & \Instr\ldots \\
- \Def &::= & \LP\key{define} \; \LP\itm{label}\RP \;\LP\LP\itm{label} \,\key{.}\, \Block\RP\ldots\RP\RP\\
- \LangXIndCallM{} &::= & \Def\ldots
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The concrete syntax of \LangXIndCall{} (extends \LangXGlobal{} of Figure~\ref{fig:x86-2-concrete}).}
- \label{fig:x86-3-concrete}
- \end{figure}
- \begin{figure}[tp]
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Arg &::=& \gray{ \INT{\Int} \MID \REG{\Reg} \MID \DEREF{\Reg}{\Int}
- \MID \BYTEREG{\Reg} } \\
- &\MID& \gray{ (\key{Global}~\Var) } \MID \FUNREF{\itm{label}} \\
- \Instr &::=& \ldots \MID \INDCALLQ{\Arg}{\itm{int}}
- \MID \TAILJMP{\Arg}{\itm{int}}\\
- &\MID& \BININSTR{\code{'leaq}}{\Arg}{\REG{\Reg}}\\
- \Block &::= & \BLOCK{\itm{info}}{\LP\Instr\ldots\RP}\\
- \Def &::= & \DEF{\itm{label}}{\code{'()}}{\Type}{\itm{info}}{\LP\LP\itm{label}\,\key{.}\,\Block\RP\ldots\RP} \\
- \LangXIndCallM{} &::= & \PROGRAMDEFS{\itm{info}}{\LP\Def\ldots\RP}
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The abstract syntax of \LangXIndCall{} (extends
- \LangXGlobal{} of Figure~\ref{fig:x86-2}).}
- \label{fig:x86-3}
- \end{figure}
- An assignment of a function reference to a variable becomes a
- load-effective-address instruction as follows, where $\itm{lhs}'$
- is the translation of $\itm{lhs}$ from \Atm{} in \LangCFun{}
- to \Arg{} in \LangXIndCallVar{}. \\
- \begin{tabular}{lcl}
- \begin{minipage}{0.35\textwidth}
- \begin{lstlisting}
- |$\itm{lhs}$| = (fun-ref |$f$|);
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow$\qquad\qquad
- &
- \begin{minipage}{0.3\textwidth}
- \begin{lstlisting}
- leaq (fun-ref |$f$|), |$\itm{lhs}'$|
- \end{lstlisting}
- \end{minipage}
- \end{tabular} \\
- Regarding function definitions, we need to remove the parameters and
- instead perform parameter passing using the conventions discussed in
- Section~\ref{sec:fun-x86}. That is, the arguments are passed in
- registers. We recommend turning the parameters into local variables
- and generating instructions at the beginning of the function to move
- from the argument passing registers to these local variables.
- \begin{lstlisting}
- (Def |$f$| '([|$x_1$| : |$T_1$|] [|$x_2$| : |$T_2$|] |$\ldots$| ) |$T_r$| |$\itm{info}$| |$G$|)
- |$\Rightarrow$|
- (Def |$f$| '() 'Integer |$\itm{info}'$| |$G'$|)
- \end{lstlisting}
- The $G'$ control-flow graph is the same as $G$ except that the
- \code{start} block is modified to add the instructions for moving from
- the argument registers to the parameter variables. So the \code{start}
- block of $G$ shown on the left is changed to the code on the right.
- \begin{center}
- \begin{minipage}{0.3\textwidth}
- \begin{lstlisting}
- start:
- |$\itm{instr}_1$|
- |$\vdots$|
- |$\itm{instr}_n$|
- \end{lstlisting}
- \end{minipage}
- $\Rightarrow$
- \begin{minipage}{0.3\textwidth}
- \begin{lstlisting}
- start:
- movq %rdi, |$x_1$|
- movq %rsi, |$x_2$|
- |$\vdots$|
- |$\itm{instr}_1$|
- |$\vdots$|
- |$\itm{instr}_n$|
- \end{lstlisting}
- \end{minipage}
- \end{center}
- By changing the parameters to local variables, we are giving the
- register allocator control over which registers or stack locations to
- use for them. If you implemented the move-biasing challenge
- (Section~\ref{sec:move-biasing}), the register allocator will try to
- assign the parameter variables to the corresponding argument register,
- in which case the \code{patch\_instructions} pass will remove the
- \code{movq} instruction. This happens in the example translation in
- Figure~\ref{fig:add-fun} of Section~\ref{sec:functions-example}, in
- the \code{add} function.
- %
- Also, note that the register allocator will perform liveness analysis
- on this sequence of move instructions and build the interference
- graph. So, for example, $x_1$ will be marked as interfering with
- \code{rsi} and that will prevent the assignment of $x_1$ to
- \code{rsi}, which is good, because that would overwrite the argument
- that needs to move into $x_2$.
- Next, consider the compilation of function calls. In the mirror image
- of handling the parameters of function definitions, the arguments need
- to be moved to the argument passing registers. The function call
- itself is performed with an indirect function call. The return value
- from the function is stored in \code{rax}, so it needs to be moved
- into the \itm{lhs}.
- \begin{lstlisting}
- |\itm{lhs}| = (call |\itm{fun}| |$\itm{arg}_1~\itm{arg}_2\ldots$|));
- |$\Rightarrow$|
- movq |$\itm{arg}_1$|, %rdi
- movq |$\itm{arg}_2$|, %rsi
- |$\vdots$|
- callq *|\itm{fun}|
- movq %rax, |\itm{lhs}|
- \end{lstlisting}
- The \code{IndirectCallq} AST node includes an integer for the arity of
- the function, i.e., the number of parameters. That information is
- useful in the \code{uncover-live} pass for determining which
- argument-passing registers are potentially read during the call.
- For tail calls, the parameter passing is the same as non-tail calls:
- generate instructions to move the arguments into to the argument
- passing registers. After that we need to pop the frame from the
- procedure call stack. However, we do not yet know how big the frame
- is; that gets determined during register allocation. So instead of
- generating those instructions here, we invent a new instruction that
- means ``pop the frame and then do an indirect jump'', which we name
- \code{TailJmp}. The abstract syntax for this instruction includes an
- argument that specifies where to jump and an integer that represents
- the arity of the function being called.
- Recall that in Section~\ref{sec:explicate-control-Lvar} we recommended
- using the label \code{start} for the initial block of a program, and
- in Section~\ref{sec:select-Lvar} we recommended labeling the conclusion
- of the program with \code{conclusion}, so that $(\key{Return}\;\Arg)$
- can be compiled to an assignment to \code{rax} followed by a jump to
- \code{conclusion}. With the addition of function definitions, we will
- have a starting block and conclusion for each function, but their
- labels need to be unique. We recommend prepending the function's name
- to \code{start} and \code{conclusion}, respectively, to obtain unique
- labels. (Alternatively, one could \code{gensym} labels for the start
- and conclusion and store them in the $\itm{info}$ field of the
- function definition.)
- \section{Register Allocation}
- \label{sec:register-allocation-r4}
- \subsection{Liveness Analysis}
- \label{sec:liveness-analysis-r4}
- \index{subject}{liveness analysis}
- %% The rest of the passes need only minor modifications to handle the new
- %% kinds of AST nodes: \code{fun-ref}, \code{indirect-callq}, and
- %% \code{leaq}.
- The \code{IndirectCallq} instruction should be treated like
- \code{Callq} regarding its written locations $W$, in that they should
- include all the caller-saved registers. Recall that the reason for
- that is to force call-live variables to be assigned to callee-saved
- registers or to be spilled to the stack.
- Regarding the set of read locations $R$ the arity field of
- \code{TailJmp} and \code{IndirectCallq} determines how many of the
- argument-passing registers should be considered as read by those
- instructions.
- \subsection{Build Interference Graph}
- \label{sec:build-interference-r4}
- With the addition of function definitions, we compute an interference
- graph for each function (not just one for the whole program).
- Recall that in Section~\ref{sec:reg-alloc-gc} we discussed the need to
- spill vector-typed variables that are live during a call to the
- \code{collect}. With the addition of functions to our language, we
- need to revisit this issue. Many functions perform allocation and
- therefore have calls to the collector inside of them. Thus, we should
- not only spill a vector-typed variable when it is live during a call
- to \code{collect}, but we should spill the variable if it is live
- during any function call. Thus, in the \code{build\_interference} pass,
- we recommend adding interference edges between call-live vector-typed
- variables and the callee-saved registers (in addition to the usual
- addition of edges between call-live variables and the caller-saved
- registers).
- \subsection{Allocate Registers}
- The primary change to the \code{allocate\_registers} pass is adding an
- auxiliary function for handling definitions (the \Def{} non-terminal
- in Figure~\ref{fig:x86-3}) with one case for function definitions. The
- logic is the same as described in
- Chapter~\ref{ch:register-allocation-Lvar}, except now register
- allocation is performed many times, once for each function definition,
- instead of just once for the whole program.
- \section{Patch Instructions}
- In \code{patch\_instructions}, you should deal with the x86
- idiosyncrasy that the destination argument of \code{leaq} must be a
- register. Additionally, you should ensure that the argument of
- \code{TailJmp} is \itm{rax}, our reserved register---this is to make
- code generation more convenient, because we trample many registers
- before the tail call (as explained in the next section).
- \section{Print x86}
- For the \code{print\_x86} pass, the cases for \code{FunRef} and
- \code{IndirectCallq} are straightforward: output their concrete
- syntax.
- \begin{lstlisting}
- (FunRef |\itm{label}|) |$\Rightarrow$| |\itm{label}|(%rip)
- (IndirectCallq |\itm{arg}| |\itm{int}|) |$\Rightarrow$| callq *|\itm{arg}'|
- \end{lstlisting}
- The \code{TailJmp} node requires a bit work. A straightforward
- translation of \code{TailJmp} would be \code{jmp *$\itm{arg}$}, but
- before the jump we need to pop the current frame. This sequence of
- instructions is the same as the code for the conclusion of a function,
- except the \code{retq} is replaced with \code{jmp *$\itm{arg}$}.
- Regarding function definitions, you will need to generate a prelude
- and conclusion for each one. This code is similar to the prelude and
- conclusion that you generated for the \code{main} function in
- Chapter~\ref{ch:Rvec}. To review, the prelude of every function
- should carry out the following steps.
- \begin{enumerate}
- \item Start with \code{.global} and \code{.align} directives followed
- by the label for the function. (See Figure~\ref{fig:add-fun} for an
- example.)
- \item Push \code{rbp} to the stack and set \code{rbp} to current stack
- pointer.
- \item Push to the stack all of the callee-saved registers that were
- used for register allocation.
- \item Move the stack pointer \code{rsp} down by the size of the stack
- frame for this function, which depends on the number of regular
- spills. (Aligned to 16 bytes.)
- \item Move the root stack pointer \code{r15} up by the size of the
- root-stack frame for this function, which depends on the number of
- spilled vectors. \label{root-stack-init}
- \item Initialize to zero all of the entries in the root-stack frame.
- \item Jump to the start block.
- \end{enumerate}
- The prelude of the \code{main} function has one additional task: call
- the \code{initialize} function to set up the garbage collector and
- move the value of the global \code{rootstack\_begin} in
- \code{r15}. This should happen before step \ref{root-stack-init}
- above, which depends on \code{r15}.
- The conclusion of every function should do the following.
- \begin{enumerate}
- \item Move the stack pointer back up by the size of the stack frame
- for this function.
- \item Restore the callee-saved registers by popping them from the
- stack.
- \item Move the root stack pointer back down by the size of the
- root-stack frame for this function.
- \item Restore \code{rbp} by popping it from the stack.
- \item Return to the caller with the \code{retq} instruction.
- \end{enumerate}
- \begin{exercise}\normalfont
- Expand your compiler to handle \LangFun{} as outlined in this chapter.
- Create 5 new programs that use functions, including examples that pass
- functions and return functions from other functions, recursive
- functions, functions that create vectors, and functions that make tail
- calls. Test your compiler on these new programs and all of your
- previously created test programs.
- \end{exercise}
- \begin{figure}[tbp]
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (Rfun) at (0,2) {\large \LangFun{}};
- \node (Rfun-1) at (3,2) {\large \LangFun{}};
- \node (Rfun-2) at (6,2) {\large \LangFun{}};
- \node (F1-1) at (12,0) {\large \LangFunRef{}};
- \node (F1-2) at (9,0) {\large \LangFunRef{}};
- \node (F1-3) at (6,0) {\large \LangFunRefAlloc{}};
- \node (F1-4) at (3,0) {\large \LangFunRefAlloc{}};
- \node (C3-2) at (3,-2) {\large \LangCFun{}};
- \node (x86-2) at (3,-4) {\large \LangXIndCallVar{}};
- \node (x86-3) at (6,-4) {\large \LangXIndCallVar{}};
- \node (x86-4) at (9,-4) {\large \LangXIndCall{}};
- \node (x86-5) at (9,-6) {\large \LangXIndCall{}};
- \node (x86-2-1) at (3,-6) {\large \LangXIndCallVar{}};
- \node (x86-2-2) at (6,-6) {\large \LangXIndCallVar{}};
- \path[->,bend left=15] (Rfun) edge [above] node
- {\ttfamily\footnotesize shrink} (Rfun-1);
- \path[->,bend left=15] (Rfun-1) edge [above] node
- {\ttfamily\footnotesize uniquify} (Rfun-2);
- \path[->,bend left=15] (Rfun-2) edge [right] node
- {\ttfamily\footnotesize ~~reveal\_functions} (F1-1);
- \path[->,bend left=15] (F1-1) edge [below] node
- {\ttfamily\footnotesize limit\_functions} (F1-2);
- \path[->,bend right=15] (F1-2) edge [above] node
- {\ttfamily\footnotesize expose\_alloc.} (F1-3);
- \path[->,bend right=15] (F1-3) edge [above] node
- {\ttfamily\footnotesize remove\_complex.} (F1-4);
- \path[->,bend left=15] (F1-4) edge [right] node
- {\ttfamily\footnotesize explicate\_control} (C3-2);
- \path[->,bend right=15] (C3-2) edge [left] node
- {\ttfamily\footnotesize select\_instr.} (x86-2);
- \path[->,bend left=15] (x86-2) edge [left] node
- {\ttfamily\footnotesize uncover\_live} (x86-2-1);
- \path[->,bend right=15] (x86-2-1) edge [below] node
- {\ttfamily\footnotesize build\_inter.} (x86-2-2);
- \path[->,bend right=15] (x86-2-2) edge [left] node
- {\ttfamily\footnotesize allocate\_reg.} (x86-3);
- \path[->,bend left=15] (x86-3) edge [above] node
- {\ttfamily\footnotesize patch\_instr.} (x86-4);
- \path[->,bend right=15] (x86-4) edge [left] node {\ttfamily\footnotesize print-x86} (x86-5);
- \end{tikzpicture}
- \caption{Diagram of the passes for \LangFun{}, a language with functions.}
- \label{fig:Rfun-passes}
- \end{figure}
- Figure~\ref{fig:Rfun-passes} gives an overview of the passes for
- compiling \LangFun{} to x86.
- \section{An Example Translation}
- \label{sec:functions-example}
- Figure~\ref{fig:add-fun} shows an example translation of a simple
- function in \LangFun{} to x86. The figure also includes the results of the
- \code{explicate\_control} and \code{select\_instructions} passes.
- \begin{figure}[htbp]
- \begin{tabular}{ll}
- \begin{minipage}{0.5\textwidth}
- % s3_2.rkt
- \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
- (define (add [x : Integer] [y : Integer])
- : Integer
- (+ x y))
- (add 40 2)
- \end{lstlisting}
- $\Downarrow$
- \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
- (define (add86 [x87 : Integer]
- [y88 : Integer]) : Integer
- add86start:
- return (+ x87 y88);
- )
- (define (main) : Integer ()
- mainstart:
- tmp89 = (fun-ref add86);
- (tail-call tmp89 40 2)
- )
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow$
- \begin{minipage}{0.5\textwidth}
- \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
- (define (add86) : Integer
- add86start:
- movq %rdi, x87
- movq %rsi, y88
- movq x87, %rax
- addq y88, %rax
- jmp add11389conclusion
- )
- (define (main) : Integer
- mainstart:
- leaq (fun-ref add86), tmp89
- movq $40, %rdi
- movq $2, %rsi
- tail-jmp tmp89
- )
- \end{lstlisting}
- $\Downarrow$
- \end{minipage}
- \end{tabular}
- \begin{tabular}{ll}
- \begin{minipage}{0.3\textwidth}
- \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
- .globl add86
- .align 16
- add86:
- pushq %rbp
- movq %rsp, %rbp
- jmp add86start
- add86start:
- movq %rdi, %rax
- addq %rsi, %rax
- jmp add86conclusion
- add86conclusion:
- popq %rbp
- retq
- \end{lstlisting}
- \end{minipage}
- &
- \begin{minipage}{0.5\textwidth}
- \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
- .globl main
- .align 16
- main:
- pushq %rbp
- movq %rsp, %rbp
- movq $16384, %rdi
- movq $16384, %rsi
- callq initialize
- movq rootstack_begin(%rip), %r15
- jmp mainstart
- mainstart:
- leaq add86(%rip), %rcx
- movq $40, %rdi
- movq $2, %rsi
- movq %rcx, %rax
- popq %rbp
- jmp *%rax
- mainconclusion:
- popq %rbp
- retq
- \end{lstlisting}
- \end{minipage}
- \end{tabular}
- \caption{Example compilation of a simple function to x86.}
- \label{fig:add-fun}
- \end{figure}
- % Challenge idea: inlining! (simple version)
- % Further Reading
- \fi % racketEd
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- \chapter{Lexically Scoped Functions}
- \label{ch:Rlam}
- \index{subject}{lambda}
- \index{subject}{lexical scoping}
- \if\edition\racketEd
- This chapter studies lexically scoped functions as they appear in
- functional languages such as Racket. By lexical scoping we mean that a
- function's body may refer to variables whose binding site is outside
- of the function, in an enclosing scope.
- %
- Consider the example in Figure~\ref{fig:lexical-scoping} written in
- \LangLam{}, which extends \LangFun{} with anonymous functions using the
- \key{lambda} form. The body of the \key{lambda}, refers to three
- variables: \code{x}, \code{y}, and \code{z}. The binding sites for
- \code{x} and \code{y} are outside of the \key{lambda}. Variable
- \code{y} is bound by the enclosing \key{let} and \code{x} is a
- parameter of function \code{f}. The \key{lambda} is returned from the
- function \code{f}. The main expression of the program includes two
- calls to \code{f} with different arguments for \code{x}, first
- \code{5} then \code{3}. The functions returned from \code{f} are bound
- to variables \code{g} and \code{h}. Even though these two functions
- were created by the same \code{lambda}, they are really different
- functions because they use different values for \code{x}. Applying
- \code{g} to \code{11} produces \code{20} whereas applying \code{h} to
- \code{15} produces \code{22}. The result of this program is \code{42}.
- \begin{figure}[btp]
- % s4_6.rkt
- \begin{lstlisting}
- (define (f [x : Integer]) : (Integer -> Integer)
- (let ([y 4])
- (lambda: ([z : Integer]) : Integer
- (+ x (+ y z)))))
- (let ([g (f 5)])
- (let ([h (f 3)])
- (+ (g 11) (h 15))))
- \end{lstlisting}
- \caption{Example of a lexically scoped function.}
- \label{fig:lexical-scoping}
- \end{figure}
- The approach that we take for implementing lexically scoped
- functions is to compile them into top-level function definitions,
- translating from \LangLam{} into \LangFun{}. However, the compiler will need to
- provide special treatment for variable occurrences such as \code{x}
- and \code{y} in the body of the \code{lambda} of
- Figure~\ref{fig:lexical-scoping}. After all, an \LangFun{} function may not
- refer to variables defined outside of it. To identify such variable
- occurrences, we review the standard notion of free variable.
- \begin{definition}
- A variable is \emph{free in expression} $e$ if the variable occurs
- inside $e$ but does not have an enclosing binding in $e$.\index{subject}{free
- variable}
- \end{definition}
- For example, in the expression \code{(+ x (+ y z))} the variables
- \code{x}, \code{y}, and \code{z} are all free. On the other hand,
- only \code{x} and \code{y} are free in the following expression
- because \code{z} is bound by the \code{lambda}.
- \begin{lstlisting}
- (lambda: ([z : Integer]) : Integer
- (+ x (+ y z)))
- \end{lstlisting}
- So the free variables of a \code{lambda} are the ones that will need
- special treatment. We need to arrange for some way to transport, at
- runtime, the values of those variables from the point where the
- \code{lambda} was created to the point where the \code{lambda} is
- applied. An efficient solution to the problem, due to
- \citet{Cardelli:1983aa}, is to bundle into a vector the values of the
- free variables together with the function pointer for the lambda's
- code, an arrangement called a \emph{flat closure} (which we shorten to
- just ``closure''). \index{subject}{closure}\index{subject}{flat closure} Fortunately,
- we have all the ingredients to make closures, Chapter~\ref{ch:Rvec}
- gave us vectors and Chapter~\ref{ch:Rfun} gave us function
- pointers. The function pointer resides at index $0$ and the
- values for the free variables will fill in the rest of the vector.
- Let us revisit the example in Figure~\ref{fig:lexical-scoping} to see
- how closures work. It's a three-step dance. The program first calls
- function \code{f}, which creates a closure for the \code{lambda}. The
- closure is a vector whose first element is a pointer to the top-level
- function that we will generate for the \code{lambda}, the second
- element is the value of \code{x}, which is \code{5}, and the third
- element is \code{4}, the value of \code{y}. The closure does not
- contain an element for \code{z} because \code{z} is not a free
- variable of the \code{lambda}. Creating the closure is step 1 of the
- dance. The closure is returned from \code{f} and bound to \code{g}, as
- shown in Figure~\ref{fig:closures}.
- %
- The second call to \code{f} creates another closure, this time with
- \code{3} in the second slot (for \code{x}). This closure is also
- returned from \code{f} but bound to \code{h}, which is also shown in
- Figure~\ref{fig:closures}.
- \begin{figure}[tbp]
- \centering \includegraphics[width=0.6\textwidth]{figs/closures}
- \caption{Example closure representation for the \key{lambda}'s
- in Figure~\ref{fig:lexical-scoping}.}
- \label{fig:closures}
- \end{figure}
- Continuing with the example, consider the application of \code{g} to
- \code{11} in Figure~\ref{fig:lexical-scoping}. To apply a closure, we
- obtain the function pointer in the first element of the closure and
- call it, passing in the closure itself and then the regular arguments,
- in this case \code{11}. This technique for applying a closure is step
- 2 of the dance.
- %
- But doesn't this \code{lambda} only take 1 argument, for parameter
- \code{z}? The third and final step of the dance is generating a
- top-level function for a \code{lambda}. We add an additional
- parameter for the closure and we insert a \code{let} at the beginning
- of the function for each free variable, to bind those variables to the
- appropriate elements from the closure parameter.
- %
- This three-step dance is known as \emph{closure conversion}. We
- discuss the details of closure conversion in
- Section~\ref{sec:closure-conversion} and the code generated from the
- example in Section~\ref{sec:example-lambda}. But first we define the
- syntax and semantics of \LangLam{} in Section~\ref{sec:r5}.
- \section{The \LangLam{} Language}
- \label{sec:r5}
- The concrete and abstract syntax for \LangLam{}, a language with anonymous
- functions and lexical scoping, is defined in
- Figures~\ref{fig:Rlam-concrete-syntax} and ~\ref{fig:Rlam-syntax}. It adds
- the \key{lambda} form to the grammar for \LangFun{}, which already has
- syntax for function application.
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Type &::=& \gray{\key{Integer} \MID \key{Boolean}
- \MID (\key{Vector}\;\Type\ldots) \MID \key{Void}
- \MID (\Type\ldots \; \key{->}\; \Type)} \\
- \Exp &::=& \gray{ \Int \MID \CREAD{} \MID \CNEG{\Exp}
- \MID \CADD{\Exp}{\Exp} \MID \CSUB{\Exp}{\Exp} } \\
- &\MID& \gray{ \Var \MID \CLET{\Var}{\Exp}{\Exp} }\\
- &\MID& \gray{\key{\#t} \MID \key{\#f}
- \MID (\key{and}\;\Exp\;\Exp)
- \MID (\key{or}\;\Exp\;\Exp)
- \MID (\key{not}\;\Exp) } \\
- &\MID& \gray{ (\key{eq?}\;\Exp\;\Exp) \MID \CIF{\Exp}{\Exp}{\Exp} } \\
- &\MID& \gray{ (\key{vector}\;\Exp\ldots) \MID
- (\key{vector-ref}\;\Exp\;\Int)} \\
- &\MID& \gray{(\key{vector-set!}\;\Exp\;\Int\;\Exp)\MID (\key{void})
- \MID (\Exp \; \Exp\ldots) } \\
- &\MID& \LP \key{procedure-arity}~\Exp\RP \\
- &\MID& \CLAMBDA{\LP\LS\Var \key{:} \Type\RS\ldots\RP}{\Type}{\Exp} \\
- \Def &::=& \gray{ \CDEF{\Var}{\LS\Var \key{:} \Type\RS\ldots}{\Type}{\Exp} } \\
- \LangLamM{} &::=& \gray{\Def\ldots \; \Exp}
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The concrete syntax of \LangLam{}, extending \LangFun{} (Figure~\ref{fig:Rfun-concrete-syntax})
- with \key{lambda}.}
- \label{fig:Rlam-concrete-syntax}
- \end{figure}
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \itm{op} &::=& \ldots \MID \code{procedure-arity} \\
- \Exp &::=& \gray{ \INT{\Int} \VAR{\Var} \MID \LET{\Var}{\Exp}{\Exp} } \\
- &\MID& \gray{ \PRIM{\itm{op}}{\Exp\ldots} }\\
- &\MID& \gray{ \BOOL{\itm{bool}}
- \MID \IF{\Exp}{\Exp}{\Exp} } \\
- &\MID& \gray{ \VOID{} \MID \LP\key{HasType}~\Exp~\Type \RP
- \MID \APPLY{\Exp}{\Exp\ldots} }\\
- &\MID& \LAMBDA{\LP\LS\Var\code{:}\Type\RS\ldots\RP}{\Type}{\Exp}\\
- \Def &::=& \gray{ \FUNDEF{\Var}{\LP\LS\Var \code{:} \Type\RS\ldots\RP}{\Type}{\code{'()}}{\Exp} }\\
- \LangLamM{} &::=& \gray{ \PROGRAMDEFSEXP{\code{'()}}{\LP\Def\ldots\RP}{\Exp} }
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The abstract syntax of \LangLam{}, extending \LangFun{} (Figure~\ref{fig:Rfun-syntax}).}
- \label{fig:Rlam-syntax}
- \end{figure}
- \index{subject}{interpreter}
- \label{sec:interp-Rlambda}
- Figure~\ref{fig:interp-Rlambda} shows the definitional interpreter for
- \LangLam{}. The case for \key{lambda} saves the current environment
- inside the returned \key{lambda}. Then the case for \key{Apply} uses
- the environment from the \key{lambda}, the \code{lam-env}, when
- interpreting the body of the \key{lambda}. The \code{lam-env}
- environment is extended with the mapping of parameters to argument
- values.
- \begin{figure}[tbp]
- \begin{lstlisting}
- (define interp-Rlambda_class
- (class interp-Rfun_class
- (super-new)
- (define/override (interp-op op)
- (match op
- ['procedure-arity
- (lambda (v)
- (match v
- [`(function (,xs ...) ,body ,lam-env) (length xs)]
- [else (error 'interp-op "expected a function, not ~a" v)]))]
- [else (super interp-op op)]))
- (define/override ((interp-exp env) e)
- (define recur (interp-exp env))
- (match e
- [(Lambda (list `[,xs : ,Ts] ...) rT body)
- `(function ,xs ,body ,env)]
- [else ((super interp-exp env) e)]))
- ))
- (define (interp-Rlambda p)
- (send (new interp-Rlambda_class) interp-program p))
- \end{lstlisting}
- \caption{Interpreter for \LangLam{}.}
- \label{fig:interp-Rlambda}
- \end{figure}
- \label{sec:type-check-r5}
- \index{subject}{type checking}
- Figure~\ref{fig:type-check-Rlambda} shows how to type check the new
- \key{lambda} form. The body of the \key{lambda} is checked in an
- environment that includes the current environment (because it is
- lexically scoped) and also includes the \key{lambda}'s parameters. We
- require the body's type to match the declared return type.
- \begin{figure}[tbp]
- \begin{lstlisting}
- (define (type-check-Rlambda env)
- (lambda (e)
- (match e
- [(Lambda (and params `([,xs : ,Ts] ...)) rT body)
- (define-values (new-body bodyT)
- ((type-check-exp (append (map cons xs Ts) env)) body))
- (define ty `(,@Ts -> ,rT))
- (cond
- [(equal? rT bodyT)
- (values (HasType (Lambda params rT new-body) ty) ty)]
- [else
- (error "mismatch in return type" bodyT rT)])]
- ...
- )))
- \end{lstlisting}
- \caption{Type checking the \key{lambda}'s in \LangLam{}.}
- \label{fig:type-check-Rlambda}
- \end{figure}
- \section{Assignment and Lexically Scoped Functions}
- \label{sec:assignment-scoping}
- [UNDER CONSTRUCTION: This section was just moved into this location
- and may need to be updated. -Jeremy]
- The combination of lexically-scoped functions and assignment
- (i.e. \code{set!}) raises a challenge with our approach to
- implementing lexically-scoped functions. Consider the following
- example in which function \code{f} has a free variable \code{x} that
- is changed after \code{f} is created but before the call to \code{f}.
- % loop_test_11.rkt
- \begin{lstlisting}
- (let ([x 0])
- (let ([y 0])
- (let ([z 20])
- (let ([f (lambda: ([a : Integer]) : Integer (+ a (+ x z)))])
- (begin
- (set! x 10)
- (set! y 12)
- (f y))))))
- \end{lstlisting}
- The correct output for this example is \code{42} because the call to
- \code{f} is required to use the current value of \code{x} (which is
- \code{10}). Unfortunately, the closure conversion pass
- (Section~\ref{sec:closure-conversion}) generates code for the
- \code{lambda} that copies the old value of \code{x} into a
- closure. Thus, if we naively add support for assignment to our current
- compiler, the output of this program would be \code{32}.
- A first attempt at solving this problem would be to save a pointer to
- \code{x} in the closure and change the occurrences of \code{x} inside
- the lambda to dereference the pointer. Of course, this would require
- assigning \code{x} to the stack and not to a register. However, the
- problem goes a bit deeper. Consider the following example in which we
- create a counter abstraction by creating a pair of functions that
- share the free variable \code{x}.
- % similar to loop_test_10.rkt
- \begin{lstlisting}
- (define (f [x : Integer]) : (Vector ( -> Integer) ( -> Void))
- (vector
- (lambda: () : Integer x)
- (lambda: () : Void (set! x (+ 1 x)))))
- (let ([counter (f 0)])
- (let ([get (vector-ref counter 0)])
- (let ([inc (vector-ref counter 1)])
- (begin
- (inc)
- (get)))))
- \end{lstlisting}
- In this example, the lifetime of \code{x} extends beyond the lifetime
- of the call to \code{f}. Thus, if we were to store \code{x} on the
- stack frame for the call to \code{f}, it would be gone by the time we
- call \code{inc} and \code{get}, leaving us with dangling pointers for
- \code{x}. This example demonstrates that when a variable occurs free
- inside a \code{lambda}, its lifetime becomes indefinite. Thus, the
- value of the variable needs to live on the heap. The verb ``box'' is
- often used for allocating a single value on the heap, producing a
- pointer, and ``unbox'' for dereferencing the pointer.
- We recommend solving these problems by ``boxing'' the local variables
- that are in the intersection of 1) variables that appear on the
- left-hand-side of a \code{set!} and 2) variables that occur free
- inside a \code{lambda}. We shall introduce a new pass named
- \code{convert-assignments} in Section~\ref{sec:convert-assignments} to
- perform this translation. But before diving into the compiler passes,
- we one more problem to discuss.
- \section{Reveal Functions and the $F_2$ language}
- \label{sec:reveal-functions-r5}
- To support the \code{procedure-arity} operator we need to communicate
- the arity of a function to the point of closure creation. We can
- accomplish this by replacing the $\FUNREF{\Var}$ struct with one that
- has a second field for the arity: $\FUNREFARITY{\Var}{\Int}$. The
- output of this pass is the language $F_2$, whose syntax is defined in
- Figure~\ref{fig:f2-syntax}.
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \[
- \begin{array}{lcl}
- \Exp &::=& \ldots \MID \FUNREFARITY{\Var}{\Int}\\
- \Def &::=& \gray{ \FUNDEF{\Var}{([\Var \code{:} \Type]\ldots)}{\Type}{\code{'()}}{\Exp} }\\
- F_2 &::=& \gray{\PROGRAMDEFS{\code{'()}}{\LP \Def\ldots \RP}}
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The abstract syntax $F_2$, an extension of \LangLam{}
- (Figure~\ref{fig:Rlam-syntax}).}
- \label{fig:f2-syntax}
- \end{figure}
- \section{Convert Assignments}
- \label{sec:convert-assignments}
- [UNDER CONSTRUCTION: This section was just moved into this location
- and may need to be updated. -Jeremy]
- Recall that in Section~\ref{sec:assignment-scoping} we learned that
- the combination of assignments and lexically-scoped functions requires
- that we box those variables that are both assigned-to and that appear
- free inside a \code{lambda}. The purpose of the
- \code{convert-assignments} pass is to carry out that transformation.
- We recommend placing this pass after \code{uniquify} but before
- \code{reveal-functions}.
- Consider again the first example from
- Section~\ref{sec:assignment-scoping}:
- \begin{lstlisting}
- (let ([x 0])
- (let ([y 0])
- (let ([z 20])
- (let ([f (lambda: ([a : Integer]) : Integer (+ a (+ x z)))])
- (begin
- (set! x 10)
- (set! y 12)
- (f y))))))
- \end{lstlisting}
- The variables \code{x} and \code{y} are assigned-to. The variables
- \code{x} and \code{z} occur free inside the \code{lambda}. Thus,
- variable \code{x} needs to be boxed but not \code{y} and \code{z}.
- The boxing of \code{x} consists of three transformations: initialize
- \code{x} with a vector, replace reads from \code{x} with
- \code{vector-ref}'s, and replace each \code{set!} on \code{x} with a
- \code{vector-set!}. The output of \code{convert-assignments} for this
- example is as follows.
- \begin{lstlisting}
- (define (main) : Integer
- (let ([x0 (vector 0)])
- (let ([y1 0])
- (let ([z2 20])
- (let ([f4 (lambda: ([a3 : Integer]) : Integer
- (+ a3 (+ (vector-ref x0 0) z2)))])
- (begin
- (vector-set! x0 0 10)
- (set! y1 12)
- (f4 y1)))))))
- \end{lstlisting}
- \paragraph{Assigned \& Free}
- We recommend defining an auxiliary function named
- \code{assigned\&free} that takes an expression and simultaneously
- computes 1) a set of assigned variables $A$, 2) a set $F$ of variables
- that occur free within lambda's, and 3) a new version of the
- expression that records which bound variables occurred in the
- intersection of $A$ and $F$. You can use the struct
- \code{AssignedFree} to do this. Consider the case for
- $\LET{x}{\itm{rhs}}{\itm{body}}$. Suppose the the recursive call on
- $\itm{rhs}$ produces $\itm{rhs}'$, $A_r$, and $F_r$ and the recursive
- call on the $\itm{body}$ produces $\itm{body}'$, $A_b$, and $F_b$. If
- $x$ is in $A_b\cap F_b$, then transforms the \code{Let} as follows.
- \begin{lstlisting}
- (Let |$x$| |$rhs$| |$body$|)
- |$\Rightarrow$|
- (Let (AssignedFree |$x$|) |$rhs'$| |$body'$|)
- \end{lstlisting}
- If $x$ is not in $A_b\cap F_b$ then omit the use of \code{AssignedFree}.
- The set of assigned variables for this \code{Let} is
- $A_r \cup (A_b - \{x\})$
- and the set of variables free in lambda's is
- $F_r \cup (F_b - \{x\})$.
- The case for $\SETBANG{x}{\itm{rhs}}$ is straightforward but
- important. Recursively process \itm{rhs} to obtain \itm{rhs'}, $A_r$,
- and $F_r$. The result is $\SETBANG{x}{\itm{rhs'}}$, $\{x\} \cup A_r$,
- and $F_r$.
- The case for $\LAMBDA{\itm{params}}{T}{\itm{body}}$ is a bit more
- involved. Let \itm{body'}, $A_b$, and $F_b$ be the result of
- recursively processing \itm{body}. Wrap each of parameter that occurs
- in $A_b \cap F_b$ with \code{AssignedFree} to produce \itm{params'}.
- Let $P$ be the set of parameter names in \itm{params}. The result is
- $\LAMBDA{\itm{params'}}{T}{\itm{body'}}$, $A_b - P$, and $(F_b \cup
- \mathrm{FV}(\itm{body})) - P$, where $\mathrm{FV}$ computes the free
- variables of an expression (see Chapter~\ref{ch:Rlam}).
- \paragraph{Convert Assignments}
- Next we discuss the \code{convert-assignment} pass with its auxiliary
- functions for expressions and definitions. The function for
- expressions, \code{cnvt-assign-exp}, should take an expression and a
- set of assigned-and-free variables (obtained from the result of
- \code{assigned\&free}. In the case for $\VAR{x}$, if $x$ is
- assigned-and-free, then unbox it by translating $\VAR{x}$ to a
- \code{vector-ref}.
- \begin{lstlisting}
- (Var |$x$|)
- |$\Rightarrow$|
- (Prim 'vector-ref (list (Var |$x$|) (Int 0)))
- \end{lstlisting}
- %
- In the case for $\LET{\LP\code{AssignedFree}\,
- x\RP}{\itm{rhs}}{\itm{body}}$, recursively process \itm{rhs} to
- obtain \itm{rhs'}. Next, recursively process \itm{body} to obtain
- \itm{body'} but with $x$ added to the set of assigned-and-free
- variables. Translate the let-expression as follows to bind $x$ to a
- boxed value.
- \begin{lstlisting}
- (Let (AssignedFree |$x$|) |$rhs$| |$body$|)
- |$\Rightarrow$|
- (Let |$x$| (Prim 'vector (list |$rhs'$|)) |$body'$|)
- \end{lstlisting}
- %
- In the case for $\SETBANG{x}{\itm{rhs}}$, recursively process
- \itm{rhs} to obtain \itm{rhs'}. If $x$ is in the assigned-and-free
- variables, translate the \code{set!} into a \code{vector-set!}
- as follows.
- \begin{lstlisting}
- (SetBang |$x$| |$\itm{rhs}$|)
- |$\Rightarrow$|
- (Prim 'vector-set! (list (Var |$x$|) (Int 0) |$\itm{rhs'}$|))
- \end{lstlisting}
- %
- The case for \code{Lambda} is non-trivial, but it is similar to the
- case for function definitions, which we discuss next.
- The auxiliary function for definitions, \code{cnvt-assign-def},
- applies assignment conversion to function definitions.
- We translate a function definition as follows.
- \begin{lstlisting}
- (Def |$f$| |$\itm{params}$| |$T$| |$\itm{info}$| |$\itm{body_1}$|)
- |$\Rightarrow$|
- (Def |$f$| |$\itm{params'}$| |$T$| |$\itm{info}$| |$\itm{body_4}$|)
- \end{lstlisting}
- So it remains to explain \itm{params'} and $\itm{body}_4$.
- Let \itm{body_2}, $A_b$, and $F_b$ be the result of
- \code{assigned\&free} on $\itm{body_1}$.
- Let $P$ be the parameter names in \itm{params}.
- We then apply \code{cnvt-assign-exp} to $\itm{body_2}$ to
- obtain \itm{body_3}, passing $A_b \cap F_b \cap P$
- as the set of assigned-and-free variables.
- Finally, we obtain \itm{body_4} by wrapping \itm{body_3}
- in a sequence of let-expressions that box the parameters
- that are in $A_b \cap F_b$.
- %
- Regarding \itm{params'}, change the names of the parameters that are
- in $A_b \cap F_b$ to maintain uniqueness (and so the let-bound
- variables can retain the original names). Recall the second example in
- Section~\ref{sec:assignment-scoping} involving a counter
- abstraction. The following is the output of assignment version for
- function \code{f}.
- \begin{lstlisting}
- (define (f0 [x1 : Integer]) : (Vector ( -> Integer) ( -> Void))
- (vector
- (lambda: () : Integer x1)
- (lambda: () : Void (set! x1 (+ 1 x1)))))
- |$\Rightarrow$|
- (define (f0 [param_x1 : Integer]) : (Vector (-> Integer) (-> Void))
- (let ([x1 (vector param_x1)])
- (vector (lambda: () : Integer (vector-ref x1 0))
- (lambda: () : Void
- (vector-set! x1 0 (+ 1 (vector-ref x1 0)))))))
- \end{lstlisting}
- \section{Closure Conversion}
- \label{sec:closure-conversion}
- \index{subject}{closure conversion}
- The compiling of lexically-scoped functions into top-level function
- definitions is accomplished in the pass \code{convert-to-closures}
- that comes after \code{reveal-functions} and before
- \code{limit-functions}.
- As usual, we implement the pass as a recursive function over the
- AST. All of the action is in the cases for \key{Lambda} and
- \key{Apply}. We transform a \key{Lambda} expression into an expression
- that creates a closure, that is, a vector whose first element is a
- function pointer and the rest of the elements are the free variables
- of the \key{Lambda}. We use the struct \code{Closure} here instead of
- using \code{vector} so that we can distinguish closures from vectors
- in Section~\ref{sec:optimize-closures} and to record the arity. In
- the generated code below, the \itm{name} is a unique symbol generated
- to identify the function and the \itm{arity} is the number of
- parameters (the length of \itm{ps}).
- \begin{lstlisting}
- (Lambda |\itm{ps}| |\itm{rt}| |\itm{body}|)
- |$\Rightarrow$|
- (Closure |\itm{arity}| (cons (FunRef |\itm{name}|) |\itm{fvs}|))
- \end{lstlisting}
- In addition to transforming each \key{Lambda} into a \key{Closure}, we
- create a top-level function definition for each \key{Lambda}, as
- shown below.\\
- \begin{minipage}{0.8\textwidth}
- \begin{lstlisting}
- (Def |\itm{name}| ([clos : (Vector _ |\itm{fvts}| ...)] |\itm{ps'}| ...) |\itm{rt'}|
- (Let |$\itm{fvs}_1$| (Prim 'vector-ref (list (Var clos) (Int 1)))
- ...
- (Let |$\itm{fvs}_n$| (Prim 'vector-ref (list (Var clos) (Int |$n$|)))
- |\itm{body'}|)...))
- \end{lstlisting}
- \end{minipage}\\
- The \code{clos} parameter refers to the closure. Translate the type
- annotations in \itm{ps} and the return type \itm{rt}, as discussed in
- the next paragraph, to obtain \itm{ps'} and \itm{rt'}. The types
- $\itm{fvts}$ are the types of the free variables in the lambda and the
- underscore \code{\_} is a dummy type that we use because it is rather
- difficult to give a type to the function in the closure's
- type.\footnote{To give an accurate type to a closure, we would need to
- add existential types to the type checker~\citep{Minamide:1996ys}.}
- The dummy type is considered to be equal to any other type during type
- checking. The sequence of \key{Let} forms bind the free variables to
- their values obtained from the closure.
- Closure conversion turns functions into vectors, so the type
- annotations in the program must also be translated. We recommend
- defining a auxiliary recursive function for this purpose. Function
- types should be translated as follows.
- \begin{lstlisting}
- (|$T_1, \ldots, T_n$| -> |$T_r$|)
- |$\Rightarrow$|
- (Vector ((Vector _) |$T'_1, \ldots, T'_n$| -> |$T'_r$|))
- \end{lstlisting}
- The above type says that the first thing in the vector is a function
- pointer. The first parameter of the function pointer is a vector (a
- closure) and the rest of the parameters are the ones from the original
- function, with types $T'_1, \ldots, T'_n$. The \code{Vector} type for
- the closure omits the types of the free variables because 1) those
- types are not available in this context and 2) we do not need them in
- the code that is generated for function application.
- We transform function application into code that retrieves the
- function pointer from the closure and then calls the function, passing
- in the closure as the first argument. We bind $e'$ to a temporary
- variable to avoid code duplication.
- \begin{lstlisting}
- (Apply |$e$| |\itm{es}|)
- |$\Rightarrow$|
- (Let |\itm{tmp}| |$e'$|
- (Apply (Prim 'vector-ref (list (Var |\itm{tmp}|) (Int 0))) (cons |\itm{tmp}| |\itm{es'}|)))
- \end{lstlisting}
- There is also the question of what to do with references top-level
- function definitions. To maintain a uniform translation of function
- application, we turn function references into closures.
- \begin{tabular}{lll}
- \begin{minipage}{0.3\textwidth}
- \begin{lstlisting}
- (FunRefArity |$f$| |$n$|)
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow$
- &
- \begin{minipage}{0.5\textwidth}
- \begin{lstlisting}
- (Closure |$n$| (FunRef |$f$|) '())
- \end{lstlisting}
- \end{minipage}
- \end{tabular} \\
- %
- The top-level function definitions need to be updated as well to take
- an extra closure parameter.
- \section{An Example Translation}
- \label{sec:example-lambda}
- Figure~\ref{fig:lexical-functions-example} shows the result of
- \code{reveal-functions} and \code{convert-to-closures} for the example
- program demonstrating lexical scoping that we discussed at the
- beginning of this chapter.
- \begin{figure}[tbp]
- \begin{minipage}{0.8\textwidth}
- % tests/lambda_test_6.rkt
- \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
- (define (f6 [x7 : Integer]) : (Integer -> Integer)
- (let ([y8 4])
- (lambda: ([z9 : Integer]) : Integer
- (+ x7 (+ y8 z9)))))
- (define (main) : Integer
- (let ([g0 ((fun-ref-arity f6 1) 5)])
- (let ([h1 ((fun-ref-arity f6 1) 3)])
- (+ (g0 11) (h1 15)))))
- \end{lstlisting}
- $\Rightarrow$
- \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
- (define (f6 [fvs4 : _] [x7 : Integer]) : (Vector ((Vector _) Integer -> Integer))
- (let ([y8 4])
- (closure 1 (list (fun-ref lambda2) x7 y8))))
- (define (lambda2 [fvs3 : (Vector _ Integer Integer)] [z9 : Integer]) : Integer
- (let ([x7 (vector-ref fvs3 1)])
- (let ([y8 (vector-ref fvs3 2)])
- (+ x7 (+ y8 z9)))))
- (define (main) : Integer
- (let ([g0 (let ([clos5 (closure 1 (list (fun-ref f6)))])
- ((vector-ref clos5 0) clos5 5))])
- (let ([h1 (let ([clos6 (closure 1 (list (fun-ref f6)))])
- ((vector-ref clos6 0) clos6 3))])
- (+ ((vector-ref g0 0) g0 11) ((vector-ref h1 0) h1 15)))))
- \end{lstlisting}
- \end{minipage}
- \caption{Example of closure conversion.}
- \label{fig:lexical-functions-example}
- \end{figure}
- \begin{exercise}\normalfont
- Expand your compiler to handle \LangLam{} as outlined in this chapter.
- Create 5 new programs that use \key{lambda} functions and make use of
- lexical scoping. Test your compiler on these new programs and all of
- your previously created test programs.
- \end{exercise}
- \section{Expose Allocation}
- \label{sec:expose-allocation-r5}
- Compile the $\CLOSURE{\itm{arity}}{\LP\Exp\ldots\RP}$ form into code
- that allocates and initializes a vector, similar to the translation of
- the \code{vector} operator in Section~\ref{sec:expose-allocation}.
- The only difference is replacing the use of
- \ALLOC{\itm{len}}{\itm{type}} with
- \ALLOCCLOS{\itm{len}}{\itm{type}}{\itm{arity}}.
- \section{Explicate Control and \LangCLam{}}
- \label{sec:explicate-r5}
- The output language of \code{explicate\_control} is \LangCLam{} whose
- abstract syntax is defined in Figure~\ref{fig:c4-syntax}. The only
- difference with respect to \LangCFun{} is the addition of the
- \code{AllocateClosure} form to the grammar for $\Exp$. The handling
- of \code{AllocateClosure} in the \code{explicate\_control} pass is
- similar to the handling of other expressions such as primitive
- operators.
- \begin{figure}[tp]
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Exp &::= & \ldots
- \MID \ALLOCCLOS{\Int}{\Type}{\Int} \\
- \Stmt &::=& \gray{ \ASSIGN{\VAR{\Var}}{\Exp}
- \MID \LP\key{Collect} \,\itm{int}\RP } \\
- \Tail &::= & \gray{ \RETURN{\Exp} \MID \SEQ{\Stmt}{\Tail}
- \MID \GOTO{\itm{label}} } \\
- &\MID& \gray{ \IFSTMT{\BINOP{\itm{cmp}}{\Atm}{\Atm}}{\GOTO{\itm{label}}}{\GOTO{\itm{label}}} }\\
- &\MID& \gray{ \TAILCALL{\Atm}{\Atm\ldots} } \\
- \Def &::=& \gray{ \DEF{\itm{label}}{\LP[\Var\key{:}\Type]\ldots\RP}{\Type}{\itm{info}}{\LP\LP\itm{label}\,\key{.}\,\Tail\RP\ldots\RP} }\\
- \LangCLamM{} & ::= & \gray{ \PROGRAMDEFS{\itm{info}}{\LP\Def\ldots\RP} }
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The abstract syntax of \LangCLam{}, extending \LangCFun{} (Figure~\ref{fig:c3-syntax}).}
- \label{fig:c4-syntax}
- \end{figure}
- \section{Select Instructions}
- \label{sec:select-instructions-Rlambda}
- Compile \ALLOCCLOS{\itm{len}}{\itm{type}}{\itm{arity}} in almost the
- same way as the \ALLOC{\itm{len}}{\itm{type}} form
- (Section~\ref{sec:select-instructions-gc}). The only difference is
- that you should place the \itm{arity} in the tag that is stored at
- position $0$ of the vector. Recall that in
- Section~\ref{sec:select-instructions-gc} a portion of the 64-bit tag
- was not used. We store the arity in the $5$ bits starting at position
- $58$.
- Compile the \code{procedure-arity} operator into a sequence of
- instructions that access the tag from position $0$ of the vector and
- extract the $5$-bits starting at position $58$ from the tag.
- \begin{figure}[p]
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (Rfun) at (0,2) {\large \LangFun{}};
- \node (Rfun-2) at (3,2) {\large \LangFun{}};
- \node (Rfun-3) at (6,2) {\large \LangFun{}};
- \node (F1-0) at (9,2) {\large \LangFunRef{}};
- \node (F1-1) at (12,0) {\large \LangFunRef{}};
- \node (F1-2) at (9,0) {\large \LangFunRef{}};
- \node (F1-3) at (6,0) {\large $F_1$};
- \node (F1-4) at (3,0) {\large $F_1$};
- \node (F1-5) at (0,0) {\large $F_1$};
- \node (C3-2) at (3,-2) {\large \LangCFun{}};
- \node (x86-2) at (3,-4) {\large \LangXIndCallVar{}};
- \node (x86-2-1) at (3,-6) {\large \LangXIndCallVar{}};
- \node (x86-2-2) at (6,-6) {\large \LangXIndCallVar{}};
- \node (x86-3) at (6,-4) {\large \LangXIndCallVar{}};
- \node (x86-4) at (9,-4) {\large \LangXIndCall{}};
- \node (x86-5) at (9,-6) {\large \LangXIndCall{}};
- \path[->,bend left=15] (Rfun) edge [above] node
- {\ttfamily\footnotesize shrink} (Rfun-2);
- \path[->,bend left=15] (Rfun-2) edge [above] node
- {\ttfamily\footnotesize uniquify} (Rfun-3);
- \path[->,bend left=15] (Rfun-3) edge [above] node
- {\ttfamily\footnotesize reveal\_functions} (F1-0);
- \path[->,bend left=15] (F1-0) edge [right] node
- {\ttfamily\footnotesize convert\_assignments} (F1-1);
- \path[->,bend left=15] (F1-1) edge [below] node
- {\ttfamily\footnotesize convert\_to\_clos.} (F1-2);
- \path[->,bend right=15] (F1-2) edge [above] node
- {\ttfamily\footnotesize limit\_fun.} (F1-3);
- \path[->,bend right=15] (F1-3) edge [above] node
- {\ttfamily\footnotesize expose\_alloc.} (F1-4);
- \path[->,bend right=15] (F1-4) edge [above] node
- {\ttfamily\footnotesize remove\_complex.} (F1-5);
- \path[->,bend right=15] (F1-5) edge [right] node
- {\ttfamily\footnotesize explicate\_control} (C3-2);
- \path[->,bend left=15] (C3-2) edge [left] node
- {\ttfamily\footnotesize select\_instr.} (x86-2);
- \path[->,bend right=15] (x86-2) edge [left] node
- {\ttfamily\footnotesize uncover\_live} (x86-2-1);
- \path[->,bend right=15] (x86-2-1) edge [below] node
- {\ttfamily\footnotesize build\_inter.} (x86-2-2);
- \path[->,bend right=15] (x86-2-2) edge [left] node
- {\ttfamily\footnotesize allocate\_reg.} (x86-3);
- \path[->,bend left=15] (x86-3) edge [above] node
- {\ttfamily\footnotesize patch\_instr.} (x86-4);
- \path[->,bend left=15] (x86-4) edge [right] node
- {\ttfamily\footnotesize print\_x86} (x86-5);
- \end{tikzpicture}
- \caption{Diagram of the passes for \LangLam{}, a language with lexically-scoped
- functions.}
- \label{fig:Rlambda-passes}
- \end{figure}
- Figure~\ref{fig:Rlambda-passes} provides an overview of all the passes needed
- for the compilation of \LangLam{}.
- \clearpage
- \section{Challenge: Optimize Closures}
- \label{sec:optimize-closures}
- In this chapter we compiled lexically-scoped functions into a
- relatively efficient representation: flat closures. However, even this
- representation comes with some overhead. For example, consider the
- following program with a function \code{tail-sum} that does not have
- any free variables and where all the uses of \code{tail-sum} are in
- applications where we know that only \code{tail-sum} is being applied
- (and not any other functions).
- \begin{center}
- \begin{minipage}{0.95\textwidth}
- \begin{lstlisting}
- (define (tail-sum [n : Integer] [r : Integer]) : Integer
- (if (eq? n 0)
- r
- (tail-sum (- n 1) (+ n r))))
- (+ (tail-sum 5 0) 27)
- \end{lstlisting}
- \end{minipage}
- \end{center}
- As described in this chapter, we uniformly apply closure conversion to
- all functions, obtaining the following output for this program.
- \begin{center}
- \begin{minipage}{0.95\textwidth}
- \begin{lstlisting}
- (define (tail_sum1 [fvs5 : _] [n2 : Integer] [r3 : Integer]) : Integer
- (if (eq? n2 0)
- r3
- (let ([clos4 (closure (list (fun-ref tail_sum1)))])
- ((vector-ref clos4 0) clos4 (+ n2 -1) (+ n2 r3)))))
- (define (main) : Integer
- (+ (let ([clos6 (closure (list (fun-ref tail_sum1)))])
- ((vector-ref clos6 0) clos6 5 0)) 27))
- \end{lstlisting}
- \end{minipage}
- \end{center}
- In the previous Chapter, there would be no allocation in the program
- and the calls to \code{tail-sum} would be direct calls. In contrast,
- the above program allocates memory for each \code{closure} and the
- calls to \code{tail-sum} are indirect. These two differences incur
- considerable overhead in a program such as this one, where the
- allocations and indirect calls occur inside a tight loop.
- One might think that this problem is trivial to solve: can't we just
- recognize calls of the form \code{((fun-ref $f$) $e_1 \ldots e_n$)}
- and compile them to direct calls \code{((fun-ref $f$) $e'_1 \ldots
- e'_n$)} instead of treating it like a call to a closure? We would
- also drop the \code{fvs5} parameter of \code{tail\_sum1}.
- %
- However, this problem is not so trivial because a global function may
- ``escape'' and become involved in applications that also involve
- closures. Consider the following example in which the application
- \code{(f 41)} needs to be compiled into a closure application, because
- the \code{lambda} may get bound to \code{f}, but the \code{add1}
- function might also get bound to \code{f}.
- \begin{lstlisting}
- (define (add1 [x : Integer]) : Integer
- (+ x 1))
- (let ([y (read)])
- (let ([f (if (eq? (read) 0)
- add1
- (lambda: ([x : Integer]) : Integer (- x y)))])
- (f 41)))
- \end{lstlisting}
- If a global function name is used in any way other than as the
- operator in a direct call, then we say that the function
- \emph{escapes}. If a global function does not escape, then we do not
- need to perform closure conversion on the function.
- \begin{exercise}\normalfont
- Implement an auxiliary function for detecting which global
- functions escape. Using that function, implement an improved version
- of closure conversion that does not apply closure conversion to
- global functions that do not escape but instead compiles them as
- regular functions. Create several new test cases that check whether
- you properly detect whether global functions escape or not.
- \end{exercise}
- So far we have reduced the overhead of calling global functions, but
- it would also be nice to reduce the overhead of calling a
- \code{lambda} when we can determine at compile time which
- \code{lambda} will be called. We refer to such calls as \emph{known
- calls}. Consider the following example in which a \code{lambda} is
- bound to \code{f} and then applied.
- \begin{lstlisting}
- (let ([y (read)])
- (let ([f (lambda: ([x : Integer]) : Integer
- (+ x y))])
- (f 21)))
- \end{lstlisting}
- Closure conversion compiles \code{(f 21)} into an indirect call:
- \begin{lstlisting}
- (define (lambda5 [fvs6 : (Vector _ Integer)] [x3 : Integer]) : Integer
- (let ([y2 (vector-ref fvs6 1)])
- (+ x3 y2)))
- (define (main) : Integer
- (let ([y2 (read)])
- (let ([f4 (Closure 1 (list (fun-ref lambda5) y2))])
- ((vector-ref f4 0) f4 21))))
- \end{lstlisting}
- but we can instead compile the application \code{(f 21)} into a direct call
- to \code{lambda5}:
- \begin{lstlisting}
- (define (main) : Integer
- (let ([y2 (read)])
- (let ([f4 (Closure 1 (list (fun-ref lambda5) y2))])
- ((fun-ref lambda5) f4 21))))
- \end{lstlisting}
- The problem of determining which lambda will be called from a
- particular application is quite challenging in general and the topic
- of considerable research~\citep{Shivers:1988aa,Gilray:2016aa}. For the
- following exercise we recommend that you compile an application to a
- direct call when the operator is a variable and the variable is
- \code{let}-bound to a closure. This can be accomplished by maintaining
- an environment mapping \code{let}-bound variables to function names.
- Extend the environment whenever you encounter a closure on the
- right-hand side of a \code{let}, mapping the \code{let}-bound variable
- to the name of the global function for the closure. This pass should
- come after closure conversion.
- \begin{exercise}\normalfont
- Implement a compiler pass, named \code{optimize-known-calls}, that
- compiles known calls into direct calls. Verify that your compiler is
- successful in this regard on several example programs.
- \end{exercise}
- These exercises only scratches the surface of optimizing of
- closures. A good next step for the interested reader is to look at the
- work of \citet{Keep:2012ab}.
- \section{Further Reading}
- The notion of lexically scoped anonymous functions predates modern
- computers by about a decade. They were invented by
- \citet{Church:1932aa}, who proposed the $\lambda$ calculus as a
- foundation for logic. Anonymous functions were included in the
- LISP~\citep{McCarthy:1960dz} programming language but were initially
- dynamically scoped. The Scheme dialect of LISP adopted lexical scoping
- and \citet{Guy-L.-Steele:1978yq} demonstrated how to efficiently
- compile Scheme programs. However, environments were represented as
- linked lists, so variable lookup was linear in the size of the
- environment. In this chapter we represent environments using flat
- closures, which were invented by
- \citet{Cardelli:1983aa,Cardelli:1984aa} for the purposes of compiling
- the ML language~\citep{Gordon:1978aa,Milner:1990fk}. With flat
- closures, variable lookup is constant time but the time to create a
- closure is proportional to the number of its free variables. Flat
- closures were reinvented by \citet{Dybvig:1987ab} in his Ph.D. thesis
- and used in Chez Scheme version 1~\citep{Dybvig:2006aa}.
- \fi
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- \chapter{Dynamic Typing}
- \label{ch:Rdyn}
- \index{subject}{dynamic typing}
- \if\edition\racketEd
- In this chapter we discuss the compilation of \LangDyn{}, a dynamically
- typed language that is a subset of Racket. This is in contrast to the
- previous chapters, which have studied the compilation of Typed
- Racket. In dynamically typed languages such as \LangDyn{}, a given
- expression may produce a value of a different type each time it is
- executed. Consider the following example with a conditional \code{if}
- expression that may return a Boolean or an integer depending on the
- input to the program.
- % part of dynamic_test_25.rkt
- \begin{lstlisting}
- (not (if (eq? (read) 1) #f 0))
- \end{lstlisting}
- Languages that allow expressions to produce different kinds of values
- are called \emph{polymorphic}, a word composed of the Greek roots
- ``poly'', meaning ``many'', and ``morph'', meaning ``shape''. There
- are several kinds of polymorphism in programming languages, such as
- subtype polymorphism and parametric
- polymorphism~\citep{Cardelli:1985kx}. The kind of polymorphism we
- study in this chapter does not have a special name but it is the kind
- that arises in dynamically typed languages.
- Another characteristic of dynamically typed languages is that
- primitive operations, such as \code{not}, are often defined to operate
- on many different types of values. In fact, in Racket, the \code{not}
- operator produces a result for any kind of value: given \code{\#f} it
- returns \code{\#t} and given anything else it returns \code{\#f}.
- Furthermore, even when primitive operations restrict their inputs to
- values of a certain type, this restriction is enforced at runtime
- instead of during compilation. For example, the following vector
- reference results in a run-time contract violation because the index
- must be in integer, not a Boolean such as \code{\#t}.
- \begin{lstlisting}
- (vector-ref (vector 42) #t)
- \end{lstlisting}
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.97\textwidth}
- \[
- \begin{array}{rcl}
- \itm{cmp} &::= & \key{eq?} \MID \key{<} \MID \key{<=} \MID \key{>} \MID \key{>=} \\
- \Exp &::=& \Int \MID \CREAD{} \MID \CNEG{\Exp}
- \MID \CADD{\Exp}{\Exp} \MID \CSUB{\Exp}{\Exp} \\
- &\MID& \Var \MID \CLET{\Var}{\Exp}{\Exp} \\
- &\MID& \key{\#t} \MID \key{\#f}
- \MID \CBINOP{\key{and}}{\Exp}{\Exp}
- \MID \CBINOP{\key{or}}{\Exp}{\Exp}
- \MID \CUNIOP{\key{not}}{\Exp} \\
- &\MID& \LP\itm{cmp}\;\Exp\;\Exp\RP \MID \CIF{\Exp}{\Exp}{\Exp} \\
- &\MID& \LP\key{vector}\;\Exp\ldots\RP \MID
- \LP\key{vector-ref}\;\Exp\;\Exp\RP \\
- &\MID& \LP\key{vector-set!}\;\Exp\;\Exp\;\Exp\RP \MID \LP\key{void}\RP \\
- &\MID& \LP\Exp \; \Exp\ldots\RP
- \MID \LP\key{lambda}\;\LP\Var\ldots\RP\;\Exp\RP \\
- & \MID & \LP\key{boolean?}\;\Exp\RP \MID \LP\key{integer?}\;\Exp\RP\\
- & \MID & \LP\key{vector?}\;\Exp\RP \MID \LP\key{procedure?}\;\Exp\RP \MID \LP\key{void?}\;\Exp\RP \\
- \Def &::=& \LP\key{define}\; \LP\Var \; \Var\ldots\RP \; \Exp\RP \\
- \LangDynM{} &::=& \Def\ldots\; \Exp
- \end{array}
- \]
- \end{minipage}
- }
- \caption{Syntax of \LangDyn{}, an untyped language (a subset of Racket).}
- \label{fig:r7-concrete-syntax}
- \end{figure}
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Exp &::=& \INT{\Int} \MID \VAR{\Var} \MID \LET{\Var}{\Exp}{\Exp} \\
- &\MID& \PRIM{\itm{op}}{\Exp\ldots} \\
- &\MID& \BOOL{\itm{bool}}
- \MID \IF{\Exp}{\Exp}{\Exp} \\
- &\MID& \VOID{} \MID \APPLY{\Exp}{\Exp\ldots} \\
- &\MID& \LAMBDA{\LP\Var\ldots\RP}{\code{'Any}}{\Exp}\\
- \Def &::=& \FUNDEF{\Var}{\LP\Var\ldots\RP}{\code{'Any}}{\code{'()}}{\Exp} \\
- \LangDynM{} &::=& \PROGRAMDEFSEXP{\code{'()}}{\LP\Def\ldots\RP}{\Exp}
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The abstract syntax of \LangDyn{}.}
- \label{fig:r7-syntax}
- \end{figure}
- The concrete and abstract syntax of \LangDyn{}, our subset of Racket, is
- defined in Figures~\ref{fig:r7-concrete-syntax} and
- \ref{fig:r7-syntax}.
- %
- There is no type checker for \LangDyn{} because it is not a statically
- typed language (it's dynamically typed!).
- The definitional interpreter for \LangDyn{} is presented in
- Figure~\ref{fig:interp-Rdyn} and its auxiliary functions are defined i
- Figure~\ref{fig:interp-Rdyn-aux}. Consider the match case for
- \code{(Int n)}. Instead of simply returning the integer \code{n} (as
- in the interpreter for \LangVar{} in Figure~\ref{fig:interp-Lvar}), the
- interpreter for \LangDyn{} creates a \emph{tagged value}\index{subject}{tagged
- value} that combines an underlying value with a tag that identifies
- what kind of value it is. We define the following struct
- to represented tagged values.
- \begin{lstlisting}
- (struct Tagged (value tag) #:transparent)
- \end{lstlisting}
- The tags are \code{Integer}, \code{Boolean}, \code{Void},
- \code{Vector}, and \code{Procedure}. Tags are closely related to types
- but don't always capture all the information that a type does. For
- example, a vector of type \code{(Vector Any Any)} is tagged with
- \code{Vector} and a procedure of type \code{(Any Any -> Any)}
- is tagged with \code{Procedure}.
- Next consider the match case for \code{vector-ref}. The
- \code{check-tag} auxiliary function (Figure~\ref{fig:interp-Rdyn-aux})
- is used to ensure that the first argument is a vector and the second
- is an integer. If they are not, a \code{trapped-error} is raised.
- Recall from Section~\ref{sec:interp_Lint} that when a definition
- interpreter raises a \code{trapped-error} error, the compiled code
- must also signal an error by exiting with return code \code{255}. A
- \code{trapped-error} is also raised if the index is not less than
- length of the vector.
- \begin{figure}[tbp]
- \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
- (define ((interp-Rdyn-exp env) ast)
- (define recur (interp-Rdyn-exp env))
- (match ast
- [(Var x) (lookup x env)]
- [(Int n) (Tagged n 'Integer)]
- [(Bool b) (Tagged b 'Boolean)]
- [(Lambda xs rt body)
- (Tagged `(function ,xs ,body ,env) 'Procedure)]
- [(Prim 'vector es)
- (Tagged (apply vector (for/list ([e es]) (recur e))) 'Vector)]
- [(Prim 'vector-ref (list e1 e2))
- (define vec (recur e1)) (define i (recur e2))
- (check-tag vec 'Vector ast) (check-tag i 'Integer ast)
- (unless (< (Tagged-value i) (vector-length (Tagged-value vec)))
- (error 'trapped-error "index ~a too big\nin ~v" (Tagged-value i) ast))
- (vector-ref (Tagged-value vec) (Tagged-value i))]
- [(Prim 'vector-set! (list e1 e2 e3))
- (define vec (recur e1)) (define i (recur e2)) (define arg (recur e3))
- (check-tag vec 'Vector ast) (check-tag i 'Integer ast)
- (unless (< (Tagged-value i) (vector-length (Tagged-value vec)))
- (error 'trapped-error "index ~a too big\nin ~v" (Tagged-value i) ast))
- (vector-set! (Tagged-value vec) (Tagged-value i) arg)
- (Tagged (void) 'Void)]
- [(Let x e body) ((interp-Rdyn-exp (cons (cons x (recur e)) env)) body)]
- [(Prim 'and (list e1 e2)) (recur (If e1 e2 (Bool #f)))]
- [(Prim 'or (list e1 e2))
- (define v1 (recur e1))
- (match (Tagged-value v1) [#f (recur e2)] [else v1])]
- [(Prim 'eq? (list l r)) (Tagged (equal? (recur l) (recur r)) 'Boolean)]
- [(Prim op (list e1))
- #:when (set-member? type-predicates op)
- (tag-value ((interp-op op) (Tagged-value (recur e1))))]
- [(Prim op es)
- (define args (map recur es))
- (define tags (for/list ([arg args]) (Tagged-tag arg)))
- (unless (for/or ([expected-tags (op-tags op)])
- (equal? expected-tags tags))
- (error 'trapped-error "illegal argument tags ~a\nin ~v" tags ast))
- (tag-value
- (apply (interp-op op) (for/list ([a args]) (Tagged-value a))))]
- [(If q t f)
- (match (Tagged-value (recur q)) [#f (recur f)] [else (recur t)])]
- [(Apply f es)
- (define new-f (recur f)) (define args (map recur es))
- (check-tag new-f 'Procedure ast) (define f-val (Tagged-value new-f))
- (match f-val
- [`(function ,xs ,body ,lam-env)
- (unless (eq? (length xs) (length args))
- (error 'trapped-error "~a != ~a\nin ~v" (length args) (length xs) ast))
- (define new-env (append (map cons xs args) lam-env))
- ((interp-Rdyn-exp new-env) body)]
- [else (error "interp-Rdyn-exp, expected function, not" f-val)])]))
- \end{lstlisting}
- \caption{Interpreter for the \LangDyn{} language.}
- \label{fig:interp-Rdyn}
- \end{figure}
- \begin{figure}[tbp]
- \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
- (define (interp-op op)
- (match op
- ['+ fx+]
- ['- fx-]
- ['read read-fixnum]
- ['not (lambda (v) (match v [#t #f] [#f #t]))]
- ['< (lambda (v1 v2)
- (cond [(and (fixnum? v1) (fixnum? v2)) (< v1 v2)]))]
- ['<= (lambda (v1 v2)
- (cond [(and (fixnum? v1) (fixnum? v2)) (<= v1 v2)]))]
- ['> (lambda (v1 v2)
- (cond [(and (fixnum? v1) (fixnum? v2)) (> v1 v2)]))]
- ['>= (lambda (v1 v2)
- (cond [(and (fixnum? v1) (fixnum? v2)) (>= v1 v2)]))]
- ['boolean? boolean?]
- ['integer? fixnum?]
- ['void? void?]
- ['vector? vector?]
- ['vector-length vector-length]
- ['procedure? (match-lambda
- [`(functions ,xs ,body ,env) #t] [else #f])]
- [else (error 'interp-op "unknown operator" op)]))
- (define (op-tags op)
- (match op
- ['+ '((Integer Integer))]
- ['- '((Integer Integer) (Integer))]
- ['read '(())]
- ['not '((Boolean))]
- ['< '((Integer Integer))]
- ['<= '((Integer Integer))]
- ['> '((Integer Integer))]
- ['>= '((Integer Integer))]
- ['vector-length '((Vector))]))
- (define type-predicates
- (set 'boolean? 'integer? 'vector? 'procedure? 'void?))
- (define (tag-value v)
- (cond [(boolean? v) (Tagged v 'Boolean)]
- [(fixnum? v) (Tagged v 'Integer)]
- [(procedure? v) (Tagged v 'Procedure)]
- [(vector? v) (Tagged v 'Vector)]
- [(void? v) (Tagged v 'Void)]
- [else (error 'tag-value "unidentified value ~a" v)]))
- (define (check-tag val expected ast)
- (define tag (Tagged-tag val))
- (unless (eq? tag expected)
- (error 'trapped-error "expected ~a, not ~a\nin ~v" expected tag ast)))
- \end{lstlisting}
- \caption{Auxiliary functions for the \LangDyn{} interpreter.}
- \label{fig:interp-Rdyn-aux}
- \end{figure}
- \clearpage
- \section{Representation of Tagged Values}
- The interpreter for \LangDyn{} introduced a new kind of value, a tagged
- value. To compile \LangDyn{} to x86 we must decide how to represent tagged
- values at the bit level. Because almost every operation in \LangDyn{}
- involves manipulating tagged values, the representation must be
- efficient. Recall that all of our values are 64 bits. We shall steal
- the 3 right-most bits to encode the tag. We use $001$ to identify
- integers, $100$ for Booleans, $010$ for vectors, $011$ for procedures,
- and $101$ for the void value. We define the following auxiliary
- function for mapping types to tag codes.
- \begin{align*}
- \itm{tagof}(\key{Integer}) &= 001 \\
- \itm{tagof}(\key{Boolean}) &= 100 \\
- \itm{tagof}((\key{Vector} \ldots)) &= 010 \\
- \itm{tagof}((\ldots \key{->} \ldots)) &= 011 \\
- \itm{tagof}(\key{Void}) &= 101
- \end{align*}
- This stealing of 3 bits comes at some price: our integers are reduced
- to ranging from $-2^{60}$ to $2^{60}$. The stealing does not adversely
- affect vectors and procedures because those values are addresses, and
- our addresses are 8-byte aligned so the rightmost 3 bits are unused,
- they are always $000$. Thus, we do not lose information by overwriting
- the rightmost 3 bits with the tag and we can simply zero-out the tag
- to recover the original address.
- To make tagged values into first-class entities, we can give them a
- type, called \code{Any}, and define operations such as \code{Inject}
- and \code{Project} for creating and using them, yielding the \LangAny{}
- intermediate language. We describe how to compile \LangDyn{} to \LangAny{} in
- Section~\ref{sec:compile-r7} but first we describe the \LangAny{} language
- in greater detail.
- \section{The \LangAny{} Language}
- \label{sec:Rany-lang}
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Type &::= & \ldots \MID \key{Any} \\
- \itm{op} &::= & \ldots \MID \code{any-vector-length}
- \MID \code{any-vector-ref} \MID \code{any-vector-set!}\\
- &\MID& \code{boolean?} \MID \code{integer?} \MID \code{vector?}
- \MID \code{procedure?} \MID \code{void?} \\
- \Exp &::=& \ldots
- \MID \gray{ \PRIM{\itm{op}}{\Exp\ldots} } \\
- &\MID& \INJECT{\Exp}{\FType} \MID \PROJECT{\Exp}{\FType} \\
- \Def &::=& \gray{ \FUNDEF{\Var}{\LP[\Var \code{:} \Type]\ldots\RP}{\Type}{\code{'()}}{\Exp} }\\
- \LangAnyM{} &::=& \gray{ \PROGRAMDEFSEXP{\code{'()}}{\LP\Def\ldots\RP}{\Exp} }
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The abstract syntax of \LangAny{}, extending \LangLam{} (Figure~\ref{fig:Rlam-syntax}).}
- \label{fig:Rany-syntax}
- \end{figure}
- The abstract syntax of \LangAny{} is defined in Figure~\ref{fig:Rany-syntax}.
- (The concrete syntax of \LangAny{} is in the Appendix,
- Figure~\ref{fig:Rany-concrete-syntax}.) The $\INJECT{e}{T}$ form
- converts the value produced by expression $e$ of type $T$ into a
- tagged value. The $\PROJECT{e}{T}$ form converts the tagged value
- produced by expression $e$ into a value of type $T$ or else halts the
- program if the type tag is not equivalent to $T$.
- %
- Note that in both \code{Inject} and \code{Project}, the type $T$ is
- restricted to a flat type $\FType$, which simplifies the
- implementation and corresponds with what is needed for compiling \LangDyn{}.
- The \code{any-vector} operators adapt the vector operations so that
- they can be applied to a value of type \code{Any}. They also
- generalize the vector operations in that the index is not restricted
- to be a literal integer in the grammar but is allowed to be any
- expression.
- The type predicates such as \key{boolean?} expect their argument to
- produce a tagged value; they return \key{\#t} if the tag corresponds
- to the predicate and they return \key{\#f} otherwise.
- The type checker for \LangAny{} is shown in
- Figures~\ref{fig:type-check-Rany-part-1} and
- \ref{fig:type-check-Rany-part-2} and uses the auxiliary functions in
- Figure~\ref{fig:type-check-Rany-aux}.
- %
- The interpreter for \LangAny{} is in Figure~\ref{fig:interp-Rany} and the
- auxiliary functions \code{apply-inject} and \code{apply-project} are
- in Figure~\ref{fig:apply-project}.
- \begin{figure}[btp]
- \begin{lstlisting}[basicstyle=\ttfamily\small]
- (define type-check-Rany_class
- (class type-check-Rlambda_class
- (super-new)
- (inherit check-type-equal?)
- (define/override (type-check-exp env)
- (lambda (e)
- (define recur (type-check-exp env))
- (match e
- [(Inject e1 ty)
- (unless (flat-ty? ty)
- (error 'type-check "may only inject from flat type, not ~a" ty))
- (define-values (new-e1 e-ty) (recur e1))
- (check-type-equal? e-ty ty e)
- (values (Inject new-e1 ty) 'Any)]
- [(Project e1 ty)
- (unless (flat-ty? ty)
- (error 'type-check "may only project to flat type, not ~a" ty))
- (define-values (new-e1 e-ty) (recur e1))
- (check-type-equal? e-ty 'Any e)
- (values (Project new-e1 ty) ty)]
- [(Prim 'any-vector-length (list e1))
- (define-values (e1^ t1) (recur e1))
- (check-type-equal? t1 'Any e)
- (values (Prim 'any-vector-length (list e1^)) 'Integer)]
- [(Prim 'any-vector-ref (list e1 e2))
- (define-values (e1^ t1) (recur e1))
- (define-values (e2^ t2) (recur e2))
- (check-type-equal? t1 'Any e)
- (check-type-equal? t2 'Integer e)
- (values (Prim 'any-vector-ref (list e1^ e2^)) 'Any)]
- [(Prim 'any-vector-set! (list e1 e2 e3))
- (define-values (e1^ t1) (recur e1))
- (define-values (e2^ t2) (recur e2))
- (define-values (e3^ t3) (recur e3))
- (check-type-equal? t1 'Any e)
- (check-type-equal? t2 'Integer e)
- (check-type-equal? t3 'Any e)
- (values (Prim 'any-vector-set! (list e1^ e2^ e3^)) 'Void)]
- \end{lstlisting}
- \caption{Type checker for the \LangAny{} language, part 1.}
- \label{fig:type-check-Rany-part-1}
- \end{figure}
- \begin{figure}[btp]
- \begin{lstlisting}[basicstyle=\ttfamily\small]
- [(ValueOf e ty)
- (define-values (new-e e-ty) (recur e))
- (values (ValueOf new-e ty) ty)]
- [(Prim pred (list e1))
- #:when (set-member? (type-predicates) pred)
- (define-values (new-e1 e-ty) (recur e1))
- (check-type-equal? e-ty 'Any e)
- (values (Prim pred (list new-e1)) 'Boolean)]
- [(If cnd thn els)
- (define-values (cnd^ Tc) (recur cnd))
- (define-values (thn^ Tt) (recur thn))
- (define-values (els^ Te) (recur els))
- (check-type-equal? Tc 'Boolean cnd)
- (check-type-equal? Tt Te e)
- (values (If cnd^ thn^ els^) (combine-types Tt Te))]
- [(Exit) (values (Exit) '_)]
- [(Prim 'eq? (list arg1 arg2))
- (define-values (e1 t1) (recur arg1))
- (define-values (e2 t2) (recur arg2))
- (match* (t1 t2)
- [(`(Vector ,ts1 ...) `(Vector ,ts2 ...)) (void)]
- [(other wise) (check-type-equal? t1 t2 e)])
- (values (Prim 'eq? (list e1 e2)) 'Boolean)]
- [else ((super type-check-exp env) e)])))
- ))
- \end{lstlisting}
- \caption{Type checker for the \LangAny{} language, part 2.}
- \label{fig:type-check-Rany-part-2}
- \end{figure}
- \begin{figure}[tbp]
- \begin{lstlisting}
- (define/override (operator-types)
- (append
- '((integer? . ((Any) . Boolean))
- (vector? . ((Any) . Boolean))
- (procedure? . ((Any) . Boolean))
- (void? . ((Any) . Boolean))
- (tag-of-any . ((Any) . Integer))
- (make-any . ((_ Integer) . Any))
- )
- (super operator-types)))
- (define/public (type-predicates)
- (set 'boolean? 'integer? 'vector? 'procedure? 'void?))
- (define/public (combine-types t1 t2)
- (match (list t1 t2)
- [(list '_ t2) t2]
- [(list t1 '_) t1]
- [(list `(Vector ,ts1 ...)
- `(Vector ,ts2 ...))
- `(Vector ,@(for/list ([t1 ts1] [t2 ts2])
- (combine-types t1 t2)))]
- [(list `(,ts1 ... -> ,rt1)
- `(,ts2 ... -> ,rt2))
- `(,@(for/list ([t1 ts1] [t2 ts2])
- (combine-types t1 t2))
- -> ,(combine-types rt1 rt2))]
- [else t1]))
- (define/public (flat-ty? ty)
- (match ty
- [(or `Integer `Boolean '_ `Void) #t]
- [`(Vector ,ts ...) (for/and ([t ts]) (eq? t 'Any))]
- [`(,ts ... -> ,rt)
- (and (eq? rt 'Any) (for/and ([t ts]) (eq? t 'Any)))]
- [else #f]))
- \end{lstlisting}
- \caption{Auxiliary methods for type checking \LangAny{}.}
- \label{fig:type-check-Rany-aux}
- \end{figure}
- \begin{figure}[btp]
- \begin{lstlisting}
- (define interp-Rany_class
- (class interp-Rlambda_class
- (super-new)
- (define/override (interp-op op)
- (match op
- ['boolean? (match-lambda
- [`(tagged ,v1 ,tg) (equal? tg (any-tag 'Boolean))]
- [else #f])]
- ['integer? (match-lambda
- [`(tagged ,v1 ,tg) (equal? tg (any-tag 'Integer))]
- [else #f])]
- ['vector? (match-lambda
- [`(tagged ,v1 ,tg) (equal? tg (any-tag `(Vector Any)))]
- [else #f])]
- ['procedure? (match-lambda
- [`(tagged ,v1 ,tg) (equal? tg (any-tag `(Any -> Any)))]
- [else #f])]
- ['eq? (match-lambda*
- [`((tagged ,v1^ ,tg1) (tagged ,v2^ ,tg2))
- (and (eq? v1^ v2^) (equal? tg1 tg2))]
- [ls (apply (super interp-op op) ls)])]
- ['any-vector-ref (lambda (v i)
- (match v [`(tagged ,v^ ,tg) (vector-ref v^ i)]))]
- ['any-vector-set! (lambda (v i a)
- (match v [`(tagged ,v^ ,tg) (vector-set! v^ i a)]))]
- ['any-vector-length (lambda (v)
- (match v [`(tagged ,v^ ,tg) (vector-length v^)]))]
- [else (super interp-op op)]))
- (define/override ((interp-exp env) e)
- (define recur (interp-exp env))
- (match e
- [(Inject e ty) `(tagged ,(recur e) ,(any-tag ty))]
- [(Project e ty2) (apply-project (recur e) ty2)]
- [else ((super interp-exp env) e)]))
- ))
- (define (interp-Rany p)
- (send (new interp-Rany_class) interp-program p))
- \end{lstlisting}
- \caption{Interpreter for \LangAny{}.}
- \label{fig:interp-Rany}
- \end{figure}
- \begin{figure}[tbp]
- \begin{lstlisting}
- (define/public (apply-inject v tg) (Tagged v tg))
- (define/public (apply-project v ty2)
- (define tag2 (any-tag ty2))
- (match v
- [(Tagged v1 tag1)
- (cond
- [(eq? tag1 tag2)
- (match ty2
- [`(Vector ,ts ...)
- (define l1 ((interp-op 'vector-length) v1))
- (cond
- [(eq? l1 (length ts)) v1]
- [else (error 'apply-project "vector length mismatch, ~a != ~a"
- l1 (length ts))])]
- [`(,ts ... -> ,rt)
- (match v1
- [`(function ,xs ,body ,env)
- (cond [(eq? (length xs) (length ts)) v1]
- [else
- (error 'apply-project "arity mismatch ~a != ~a"
- (length xs) (length ts))])]
- [else (error 'apply-project "expected function not ~a" v1)])]
- [else v1])]
- [else (error 'apply-project "tag mismatch ~a != ~a" tag1 tag2)])]
- [else (error 'apply-project "expected tagged value, not ~a" v)]))
- \end{lstlisting}
- \caption{Auxiliary functions for injection and projection.}
- \label{fig:apply-project}
- \end{figure}
- \clearpage
- \section{Cast Insertion: Compiling \LangDyn{} to \LangAny{}}
- \label{sec:compile-r7}
- The \code{cast-insert} pass compiles from \LangDyn{} to \LangAny{}.
- Figure~\ref{fig:compile-r7-Rany} shows the compilation of many of the
- \LangDyn{} forms into \LangAny{}. An important invariant of this pass is that
- given a subexpression $e$ in the \LangDyn{} program, the pass will produce
- an expression $e'$ in \LangAny{} that has type \key{Any}. For example, the
- first row in Figure~\ref{fig:compile-r7-Rany} shows the compilation of
- the Boolean \code{\#t}, which must be injected to produce an
- expression of type \key{Any}.
- %
- The second row of Figure~\ref{fig:compile-r7-Rany}, the compilation of
- addition, is representative of compilation for many primitive
- operations: the arguments have type \key{Any} and must be projected to
- \key{Integer} before the addition can be performed.
- The compilation of \key{lambda} (third row of
- Figure~\ref{fig:compile-r7-Rany}) shows what happens when we need to
- produce type annotations: we simply use \key{Any}.
- %
- The compilation of \code{if} and \code{eq?} demonstrate how this pass
- has to account for some differences in behavior between \LangDyn{} and
- \LangAny{}. The \LangDyn{} language is more permissive than \LangAny{} regarding what
- kind of values can be used in various places. For example, the
- condition of an \key{if} does not have to be a Boolean. For \key{eq?},
- the arguments need not be of the same type (in that case the
- result is \code{\#f}).
- \begin{figure}[btp]
- \centering
- \begin{tabular}{|lll|} \hline
- \begin{minipage}{0.27\textwidth}
- \begin{lstlisting}
- #t
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow$
- &
- \begin{minipage}{0.65\textwidth}
- \begin{lstlisting}
- (inject #t Boolean)
- \end{lstlisting}
- \end{minipage}
- \\[2ex]\hline
- \begin{minipage}{0.27\textwidth}
- \begin{lstlisting}
- (+ |$e_1$| |$e_2$|)
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow$
- &
- \begin{minipage}{0.65\textwidth}
- \begin{lstlisting}
- (inject
- (+ (project |$e'_1$| Integer)
- (project |$e'_2$| Integer))
- Integer)
- \end{lstlisting}
- \end{minipage}
- \\[2ex]\hline
- \begin{minipage}{0.27\textwidth}
- \begin{lstlisting}
- (lambda (|$x_1 \ldots x_n$|) |$e$|)
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow$
- &
- \begin{minipage}{0.65\textwidth}
- \begin{lstlisting}
- (inject
- (lambda: ([|$x_1$|:Any]|$\ldots$|[|$x_n$|:Any]):Any |$e'$|)
- (Any|$\ldots$|Any -> Any))
- \end{lstlisting}
- \end{minipage}
- \\[2ex]\hline
- \begin{minipage}{0.27\textwidth}
- \begin{lstlisting}
- (|$e_0$| |$e_1 \ldots e_n$|)
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow$
- &
- \begin{minipage}{0.65\textwidth}
- \begin{lstlisting}
- ((project |$e'_0$| (Any|$\ldots$|Any -> Any)) |$e'_1 \ldots e'_n$|)
- \end{lstlisting}
- \end{minipage}
- \\[2ex]\hline
- \begin{minipage}{0.27\textwidth}
- \begin{lstlisting}
- (vector-ref |$e_1$| |$e_2$|)
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow$
- &
- \begin{minipage}{0.65\textwidth}
- \begin{lstlisting}
- (any-vector-ref |$e_1'$| |$e_2'$|)
- \end{lstlisting}
- \end{minipage}
- \\[2ex]\hline
- \begin{minipage}{0.27\textwidth}
- \begin{lstlisting}
- (if |$e_1$| |$e_2$| |$e_3$|)
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow$
- &
- \begin{minipage}{0.65\textwidth}
- \begin{lstlisting}
- (if (eq? |$e'_1$| (inject #f Boolean)) |$e'_3$| |$e'_2$|)
- \end{lstlisting}
- \end{minipage}
- \\[2ex]\hline
- \begin{minipage}{0.27\textwidth}
- \begin{lstlisting}
- (eq? |$e_1$| |$e_2$|)
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow$
- &
- \begin{minipage}{0.65\textwidth}
- \begin{lstlisting}
- (inject (eq? |$e'_1$| |$e'_2$|) Boolean)
- \end{lstlisting}
- \end{minipage}
- \\[2ex]\hline
- \begin{minipage}{0.27\textwidth}
- \begin{lstlisting}
- (not |$e_1$|)
- \end{lstlisting}
- \end{minipage}
- &
- $\Rightarrow$
- &
- \begin{minipage}{0.65\textwidth}
- \begin{lstlisting}
- (if (eq? |$e'_1$| (inject #f Boolean))
- (inject #t Boolean) (inject #f Boolean))
- \end{lstlisting}
- \end{minipage}
- \\[2ex]\hline
- \end{tabular}
- \caption{Cast Insertion}
- \label{fig:compile-r7-Rany}
- \end{figure}
- \section{Reveal Casts}
- \label{sec:reveal-casts-Rany}
- % TODO: define R'_6
- In the \code{reveal-casts} pass we recommend compiling \code{project}
- into an \code{if} expression that checks whether the value's tag
- matches the target type; if it does, the value is converted to a value
- of the target type by removing the tag; if it does not, the program
- exits. To perform these actions we need a new primitive operation,
- \code{tag-of-any}, and two new forms, \code{ValueOf} and \code{Exit}.
- The \code{tag-of-any} operation retrieves the type tag from a tagged
- value of type \code{Any}. The \code{ValueOf} form retrieves the
- underlying value from a tagged value. The \code{ValueOf} form
- includes the type for the underlying value which is used by the type
- checker. Finally, the \code{Exit} form ends the execution of the
- program.
- If the target type of the projection is \code{Boolean} or
- \code{Integer}, then \code{Project} can be translated as follows.
- \begin{center}
- \begin{minipage}{1.0\textwidth}
- \begin{lstlisting}
- (Project |$e$| |$\FType$|)
- |$\Rightarrow$|
- (Let |$\itm{tmp}$| |$e'$|
- (If (Prim 'eq? (list (Prim 'tag-of-any (list (Var |$\itm{tmp}$|)))
- (Int |$\itm{tagof}(\FType)$|)))
- (ValueOf |$\itm{tmp}$| |$\FType$|)
- (Exit)))
- \end{lstlisting}
- \end{minipage}
- \end{center}
- If the target type of the projection is a vector or function type,
- then there is a bit more work to do. For vectors, check that the
- length of the vector type matches the length of the vector (using the
- \code{vector-length} primitive). For functions, check that the number
- of parameters in the function type matches the function's arity (using
- \code{procedure-arity}).
- Regarding \code{inject}, we recommend compiling it to a slightly
- lower-level primitive operation named \code{make-any}. This operation
- takes a tag instead of a type.
- \begin{center}
- \begin{minipage}{1.0\textwidth}
- \begin{lstlisting}
- (Inject |$e$| |$\FType$|)
- |$\Rightarrow$|
- (Prim 'make-any (list |$e'$| (Int |$\itm{tagof}(\FType)$|)))
- \end{lstlisting}
- \end{minipage}
- \end{center}
- The type predicates (\code{boolean?}, etc.) can be translated into
- uses of \code{tag-of-any} and \code{eq?} in a similar way as in the
- translation of \code{Project}.
- The \code{any-vector-ref} and \code{any-vector-set!} operations
- combine the projection action with the vector operation. Also, the
- read and write operations allow arbitrary expressions for the index so
- the type checker for \LangAny{} (Figure~\ref{fig:type-check-Rany-part-1})
- cannot guarantee that the index is within bounds. Thus, we insert code
- to perform bounds checking at runtime. The translation for
- \code{any-vector-ref} is as follows and the other two operations are
- translated in a similar way.
- \begin{lstlisting}
- (Prim 'any-vector-ref (list |$e_1$| |$e_2$|))
- |$\Rightarrow$|
- (Let |$v$| |$e'_1$|
- (Let |$i$| |$e'_2$|
- (If (Prim 'eq? (list (Prim 'tag-of-any (list (Var |$v$|))) (Int 2)))
- (If (Prim '< (list (Var |$i$|)
- (Prim 'any-vector-length (list (Var |$v$|)))))
- (Prim 'any-vector-ref (list (Var |$v$|) (Var |$i$|)))
- (Exit))))
- \end{lstlisting}
- \section{Remove Complex Operands}
- \label{sec:rco-Rany}
- The \code{ValueOf} and \code{Exit} forms are both complex expressions.
- The subexpression of \code{ValueOf} must be atomic.
- \section{Explicate Control and \LangCAny{}}
- \label{sec:explicate-Rany}
- The output of \code{explicate\_control} is the \LangCAny{} language whose
- syntax is defined in Figure~\ref{fig:c5-syntax}. The \code{ValueOf}
- form that we added to \LangAny{} remains an expression and the \code{Exit}
- expression becomes a $\Tail$. Also, note that the index argument of
- \code{vector-ref} and \code{vector-set!} is an $\Atm$ instead
- of an integer, as in \LangCVec{} (Figure~\ref{fig:c2-syntax}).
- \begin{figure}[tp]
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Exp &::= & \ldots
- \MID \BINOP{\key{'any-vector-ref}}{\Atm}{\Atm} \\
- &\MID& (\key{Prim}~\key{'any-vector-set!}\,(\key{list}\,\Atm\,\Atm\,\Atm))\\
- &\MID& \VALUEOF{\Exp}{\FType} \\
- \Stmt &::=& \gray{ \ASSIGN{\VAR{\Var}}{\Exp}
- \MID \LP\key{Collect} \,\itm{int}\RP }\\
- \Tail &::= & \gray{ \RETURN{\Exp} \MID \SEQ{\Stmt}{\Tail}
- \MID \GOTO{\itm{label}} } \\
- &\MID& \gray{ \IFSTMT{\BINOP{\itm{cmp}}{\Atm}{\Atm}}{\GOTO{\itm{label}}}{\GOTO{\itm{label}}} }\\
- &\MID& \gray{ \TAILCALL{\Atm}{\Atm\ldots} }
- \MID \LP\key{Exit}\RP \\
- \Def &::=& \gray{ \DEF{\itm{label}}{\LP[\Var\key{:}\Type]\ldots\RP}{\Type}{\itm{info}}{\LP\LP\itm{label}\,\key{.}\,\Tail\RP\ldots\RP} }\\
- \LangCAnyM{} & ::= & \gray{ \PROGRAMDEFS{\itm{info}}{\LP\Def\ldots\RP} }
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The abstract syntax of \LangCAny{}, extending \LangCLam{} (Figure~\ref{fig:c4-syntax}).}
- \label{fig:c5-syntax}
- \end{figure}
- \section{Select Instructions}
- \label{sec:select-Rany}
- In the \code{select\_instructions} pass we translate the primitive
- operations on the \code{Any} type to x86 instructions that involve
- manipulating the 3 tag bits of the tagged value.
- \paragraph{Make-any}
- We recommend compiling the \key{make-any} primitive as follows if the
- tag is for \key{Integer} or \key{Boolean}. The \key{salq} instruction
- shifts the destination to the left by the number of bits specified its
- source argument (in this case $3$, the length of the tag) and it
- preserves the sign of the integer. We use the \key{orq} instruction to
- combine the tag and the value to form the tagged value. \\
- \begin{lstlisting}
- (Assign |\itm{lhs}| (Prim 'make-any (list |$e$| (Int |$\itm{tag}$|))))
- |$\Rightarrow$|
- movq |$e'$|, |\itm{lhs'}|
- salq $3, |\itm{lhs'}|
- orq $|$\itm{tag}$|, |\itm{lhs'}|
- \end{lstlisting}
- The instruction selection for vectors and procedures is different
- because their is no need to shift them to the left. The rightmost 3
- bits are already zeros as described at the beginning of this
- chapter. So we just combine the value and the tag using \key{orq}. \\
- \begin{lstlisting}
- (Assign |\itm{lhs}| (Prim 'make-any (list |$e$| (Int |$\itm{tag}$|))))
- |$\Rightarrow$|
- movq |$e'$|, |\itm{lhs'}|
- orq $|$\itm{tag}$|, |\itm{lhs'}|
- \end{lstlisting}
- \paragraph{Tag-of-any}
- Recall that the \code{tag-of-any} operation extracts the type tag from
- a value of type \code{Any}. The type tag is the bottom three bits, so
- we obtain the tag by taking the bitwise-and of the value with $111$
- ($7$ in decimal).
- \begin{lstlisting}
- (Assign |\itm{lhs}| (Prim 'tag-of-any (list |$e$|)))
- |$\Rightarrow$|
- movq |$e'$|, |\itm{lhs'}|
- andq $7, |\itm{lhs'}|
- \end{lstlisting}
- \paragraph{ValueOf}
- Like \key{make-any}, the instructions for \key{ValueOf} are different
- depending on whether the type $T$ is a pointer (vector or procedure)
- or not (Integer or Boolean). The following shows the instruction
- selection for Integer and Boolean. We produce an untagged value by
- shifting it to the right by 3 bits.
- \begin{lstlisting}
- (Assign |\itm{lhs}| (ValueOf |$e$| |$T$|))
- |$\Rightarrow$|
- movq |$e'$|, |\itm{lhs'}|
- sarq $3, |\itm{lhs'}|
- \end{lstlisting}
- %
- In the case for vectors and procedures, there is no need to
- shift. Instead we just need to zero-out the rightmost 3 bits. We
- accomplish this by creating the bit pattern $\ldots 0111$ ($7$ in
- decimal) and apply \code{bitwise-not} to obtain $\ldots 11111000$ (-8
- in decimal) which we \code{movq} into the destination $\itm{lhs}$. We
- then apply \code{andq} with the tagged value to get the desired
- result. \\
- \begin{lstlisting}
- (Assign |\itm{lhs}| (ValueOf |$e$| |$T$|))
- |$\Rightarrow$|
- movq $|$-8$|, |\itm{lhs'}|
- andq |$e'$|, |\itm{lhs'}|
- \end{lstlisting}
- %% \paragraph{Type Predicates} We leave it to the reader to
- %% devise a sequence of instructions to implement the type predicates
- %% \key{boolean?}, \key{integer?}, \key{vector?}, and \key{procedure?}.
- \paragraph{Any-vector-length}
- \begin{lstlisting}
- (Assign |$\itm{lhs}$| (Prim 'any-vector-length (list |$a_1$|)))
- |$\Longrightarrow$|
- movq |$\neg 111$|, %r11
- andq |$a_1'$|, %r11
- movq 0(%r11), %r11
- andq $126, %r11
- sarq $1, %r11
- movq %r11, |$\itm{lhs'}$|
- \end{lstlisting}
- \paragraph{Any-vector-ref}
- The index may be an arbitrary atom so instead of computing the offset
- at compile time, instructions need to be generated to compute the
- offset at runtime as follows. Note the use of the new instruction
- \code{imulq}.
- \begin{center}
- \begin{minipage}{0.96\textwidth}
- \begin{lstlisting}
- (Assign |$\itm{lhs}$| (Prim 'any-vector-ref (list |$a_1$| |$a_2$|)))
- |$\Longrightarrow$|
- movq |$\neg 111$|, %r11
- andq |$a_1'$|, %r11
- movq |$a_2'$|, %rax
- addq $1, %rax
- imulq $8, %rax
- addq %rax, %r11
- movq 0(%r11) |$\itm{lhs'}$|
- \end{lstlisting}
- \end{minipage}
- \end{center}
- \paragraph{Any-vector-set!}
- The code generation for \code{any-vector-set!} is similar to the other
- \code{any-vector} operations.
- \section{Register Allocation for \LangAny{}}
- \label{sec:register-allocation-Rany}
- \index{subject}{register allocation}
- There is an interesting interaction between tagged values and garbage
- collection that has an impact on register allocation. A variable of
- type \code{Any} might refer to a vector and therefore it might be a
- root that needs to be inspected and copied during garbage
- collection. Thus, we need to treat variables of type \code{Any} in a
- similar way to variables of type \code{Vector} for purposes of
- register allocation. In particular,
- \begin{itemize}
- \item If a variable of type \code{Any} is live during a function call,
- then it must be spilled. This can be accomplished by changing
- \code{build\_interference} to mark all variables of type \code{Any}
- that are live after a \code{callq} as interfering with all the
- registers.
- \item If a variable of type \code{Any} is spilled, it must be spilled
- to the root stack instead of the normal procedure call stack.
- \end{itemize}
- Another concern regarding the root stack is that the garbage collector
- needs to differentiate between (1) plain old pointers to tuples, (2) a
- tagged value that points to a tuple, and (3) a tagged value that is
- not a tuple. We enable this differentiation by choosing not to use the
- tag $000$ in the $\itm{tagof}$ function. Instead, that bit pattern is
- reserved for identifying plain old pointers to tuples. That way, if
- one of the first three bits is set, then we have a tagged value and
- inspecting the tag can differentiation between vectors ($010$) and the
- other kinds of values.
- \begin{exercise}\normalfont
- Expand your compiler to handle \LangAny{} as discussed in the last few
- sections. Create 5 new programs that use the \code{Any} type and the
- new operations (\code{inject}, \code{project}, \code{boolean?},
- etc.). Test your compiler on these new programs and all of your
- previously created test programs.
- \end{exercise}
- \begin{exercise}\normalfont
- Expand your compiler to handle \LangDyn{} as outlined in this chapter.
- Create tests for \LangDyn{} by adapting ten of your previous test programs
- by removing type annotations. Add 5 more tests programs that
- specifically rely on the language being dynamically typed. That is,
- they should not be legal programs in a statically typed language, but
- nevertheless, they should be valid \LangDyn{} programs that run to
- completion without error.
- \end{exercise}
- \begin{figure}[p]
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (Rfun) at (0,4) {\large \LangDyn{}};
- \node (Rfun-2) at (3,4) {\large \LangDyn{}};
- \node (Rfun-3) at (6,4) {\large \LangDyn{}};
- \node (Rfun-4) at (9,4) {\large \LangDynFunRef{}};
- \node (Rfun-5) at (9,2) {\large \LangAnyFunRef{}};
- \node (Rfun-6) at (12,2) {\large \LangAnyFunRef{}};
- \node (Rfun-7) at (12,0) {\large \LangAnyFunRef{}};
- \node (F1-2) at (9,0) {\large \LangAnyFunRef{}};
- \node (F1-3) at (6,0) {\large \LangAnyFunRef{}};
- \node (F1-4) at (3,0) {\large \LangAnyAlloc{}};
- \node (F1-5) at (0,0) {\large \LangAnyAlloc{}};
- \node (C3-2) at (3,-2) {\large \LangCAny{}};
- \node (x86-2) at (3,-4) {\large \LangXIndCallVar{}};
- \node (x86-2-1) at (3,-6) {\large \LangXIndCallVar{}};
- \node (x86-2-2) at (6,-6) {\large \LangXIndCallVar{}};
- \node (x86-3) at (6,-4) {\large \LangXIndCallVar{}};
- \node (x86-4) at (9,-4) {\large \LangXIndCall{}};
- \node (x86-5) at (9,-6) {\large \LangXIndCall{}};
- \path[->,bend left=15] (Rfun) edge [above] node
- {\ttfamily\footnotesize shrink} (Rfun-2);
- \path[->,bend left=15] (Rfun-2) edge [above] node
- {\ttfamily\footnotesize uniquify} (Rfun-3);
- \path[->,bend left=15] (Rfun-3) edge [above] node
- {\ttfamily\footnotesize reveal\_functions} (Rfun-4);
- \path[->,bend right=15] (Rfun-4) edge [left] node
- {\ttfamily\footnotesize cast\_insert} (Rfun-5);
- \path[->,bend left=15] (Rfun-5) edge [above] node
- {\ttfamily\footnotesize check\_bounds} (Rfun-6);
- \path[->,bend left=15] (Rfun-6) edge [left] node
- {\ttfamily\footnotesize reveal\_casts} (Rfun-7);
-
- \path[->,bend left=15] (Rfun-7) edge [below] node
- {\ttfamily\footnotesize convert\_to\_clos.} (F1-2);
- \path[->,bend right=15] (F1-2) edge [above] node
- {\ttfamily\footnotesize limit\_fun.} (F1-3);
- \path[->,bend right=15] (F1-3) edge [above] node
- {\ttfamily\footnotesize expose\_alloc.} (F1-4);
- \path[->,bend right=15] (F1-4) edge [above] node
- {\ttfamily\footnotesize remove\_complex.} (F1-5);
- \path[->,bend right=15] (F1-5) edge [right] node
- {\ttfamily\footnotesize explicate\_control} (C3-2);
- \path[->,bend left=15] (C3-2) edge [left] node
- {\ttfamily\footnotesize select\_instr.} (x86-2);
- \path[->,bend right=15] (x86-2) edge [left] node
- {\ttfamily\footnotesize uncover\_live} (x86-2-1);
- \path[->,bend right=15] (x86-2-1) edge [below] node
- {\ttfamily\footnotesize build\_inter.} (x86-2-2);
- \path[->,bend right=15] (x86-2-2) edge [left] node
- {\ttfamily\footnotesize allocate\_reg.} (x86-3);
- \path[->,bend left=15] (x86-3) edge [above] node
- {\ttfamily\footnotesize patch\_instr.} (x86-4);
- \path[->,bend left=15] (x86-4) edge [right] node
- {\ttfamily\footnotesize print\_x86} (x86-5);
- \end{tikzpicture}
- \caption{Diagram of the passes for \LangDyn{}, a dynamically typed language.}
- \label{fig:Rdyn-passes}
- \end{figure}
- Figure~\ref{fig:Rdyn-passes} provides an overview of all the passes needed
- for the compilation of \LangDyn{}.
- % Further Reading
- \fi % racketEd
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- \chapter{Objects}
- \label{ch:Robject}
- \index{subject}{objects}
- \index{subject}{classes}
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- \chapter{Gradual Typing}
- \label{ch:Rgrad}
- \index{subject}{gradual typing}
- \if\edition\racketEd
- This chapter studies a language, \LangGrad{}, in which the programmer
- can choose between static and dynamic type checking in different parts
- of a program, thereby mixing the statically typed \LangLoop{} language
- with the dynamically typed \LangDyn{}. There are several approaches to
- mixing static and dynamic typing, including multi-language
- integration~\citep{Tobin-Hochstadt:2006fk,Matthews:2007zr} and hybrid
- type checking~\citep{Flanagan:2006mn,Gronski:2006uq}. In this chapter
- we focus on \emph{gradual typing}\index{subject}{gradual typing}, in which the
- programmer controls the amount of static versus dynamic checking by
- adding or removing type annotations on parameters and
- variables~\citep{Anderson:2002kd,Siek:2006bh}.
- %
- The concrete syntax of \LangGrad{} is defined in
- Figure~\ref{fig:Rgrad-concrete-syntax} and its abstract syntax is defined
- in Figure~\ref{fig:Rgrad-syntax}. The main syntactic difference between
- \LangLoop{} and \LangGrad{} is the additional \itm{param} and \itm{ret}
- non-terminals that make type annotations optional. The return types
- are not optional in the abstract syntax; the parser fills in
- \code{Any} when the return type is not specified in the concrete
- syntax.
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \itm{param} &::=& \Var \MID \LS\Var \key{:} \Type\RS \\
- \itm{ret} &::=& \epsilon \MID \key{:} \Type \\
- \Exp &::=& \gray{ \Int \MID \CREAD{} \MID \CNEG{\Exp}
- \MID \CADD{\Exp}{\Exp} \MID \CSUB{\Exp}{\Exp} } \\
- &\MID& \gray{ \Var \MID \CLET{\Var}{\Exp}{\Exp} }\\
- &\MID& \gray{\key{\#t} \MID \key{\#f}
- \MID (\key{and}\;\Exp\;\Exp)
- \MID (\key{or}\;\Exp\;\Exp)
- \MID (\key{not}\;\Exp) } \\
- &\MID& \gray{ (\key{eq?}\;\Exp\;\Exp) \MID \CIF{\Exp}{\Exp}{\Exp} } \\
- &\MID& \gray{ (\key{vector}\;\Exp\ldots) \MID
- (\key{vector-ref}\;\Exp\;\Int)} \\
- &\MID& \gray{(\key{vector-set!}\;\Exp\;\Int\;\Exp)\MID (\key{void})
- \MID (\Exp \; \Exp\ldots) } \\
- &\MID& \gray{ \LP \key{procedure-arity}~\Exp\RP }
- \MID \CGLAMBDA{\LP\itm{param}\ldots\RP}{\itm{ret}}{\Exp} \\
- &\MID& \gray{ \CSETBANG{\Var}{\Exp}
- \MID \CBEGIN{\Exp\ldots}{\Exp}
- \MID \CWHILE{\Exp}{\Exp} } \\
- \Def &::=& \CGDEF{\Var}{\itm{param}\ldots}{\itm{ret}}{\Exp} \\
- \LangGradM{} &::=& \gray{\Def\ldots \; \Exp}
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The concrete syntax of \LangGrad{}, extending \LangLoop{} (Figure~\ref{fig:Rwhile-concrete-syntax}).}
- \label{fig:Rgrad-concrete-syntax}
- \end{figure}
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \itm{param} &::=& \Var \MID \LS\Var \key{:} \Type\RS \\
- \Exp &::=& \gray{ \INT{\Int} \VAR{\Var} \MID \LET{\Var}{\Exp}{\Exp} } \\
- &\MID& \gray{ \PRIM{\itm{op}}{\Exp\ldots} }\\
- &\MID& \gray{ \BOOL{\itm{bool}}
- \MID \IF{\Exp}{\Exp}{\Exp} } \\
- &\MID& \gray{ \VOID{} \MID \LP\key{HasType}~\Exp~\Type \RP
- \MID \APPLY{\Exp}{\Exp\ldots} }\\
- &\MID& \LAMBDA{\LP\itm{param}\ldots\RP}{\Type}{\Exp} \\
- &\MID& \gray{ \SETBANG{\Var}{\Exp} \MID \BEGIN{\LP\Exp\ldots\RP}{\Exp} } \\
- &\MID& \gray{ \WHILE{\Exp}{\Exp} } \\
- \Def &::=& \FUNDEF{\Var}{\LP\itm{param}\ldots\RP}{\Type}{\code{'()}}{\Exp} \\
- \LangGradM{} &::=& \gray{ \PROGRAMDEFSEXP{\code{'()}}{\LP\Def\ldots\RP}{\Exp} }
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The abstract syntax of \LangGrad{}, extending \LangLoop{} (Figure~\ref{fig:Rwhile-syntax}).}
- \label{fig:Rgrad-syntax}
- \end{figure}
- Both the type checker and the interpreter for \LangGrad{} require some
- interesting changes to enable gradual typing, which we discuss in the
- next two sections in the context of the \code{map-vec} example from
- Chapter~\ref{ch:Rfun}. In Figure~\ref{fig:gradual-map-vec} we
- revised the \code{map-vec} example, omitting the type annotations from
- the \code{add1} function.
- \begin{figure}[btp]
- % gradual_test_9.rkt
- \begin{lstlisting}
- (define (map-vec [f : (Integer -> Integer)]
- [v : (Vector Integer Integer)])
- : (Vector Integer Integer)
- (vector (f (vector-ref v 0)) (f (vector-ref v 1))))
- (define (add1 x) (+ x 1))
- (vector-ref (map-vec add1 (vector 0 41)) 1)
- \end{lstlisting}
- \caption{A partially-typed version of the \code{map-vec} example.}
- \label{fig:gradual-map-vec}
- \end{figure}
- \section{Type Checking \LangGrad{} and \LangCast{}}
- \label{sec:gradual-type-check}
- The type checker for \LangGrad{} uses the \code{Any} type for missing
- parameter and return types. For example, the \code{x} parameter of
- \code{add1} in Figure~\ref{fig:gradual-map-vec} is given the type
- \code{Any} and the return type of \code{add1} is \code{Any}. Next
- consider the \code{+} operator inside \code{add1}. It expects both
- arguments to have type \code{Integer}, but its first argument \code{x}
- has type \code{Any}. In a gradually typed language, such differences
- are allowed so long as the types are \emph{consistent}, that is, they
- are equal except in places where there is an \code{Any} type. The type
- \code{Any} is consistent with every other type.
- Figure~\ref{fig:consistent} defines the \code{consistent?} predicate.
- \begin{figure}[tbp]
- \begin{lstlisting}
- (define/public (consistent? t1 t2)
- (match* (t1 t2)
- [('Integer 'Integer) #t]
- [('Boolean 'Boolean) #t]
- [('Void 'Void) #t]
- [('Any t2) #t]
- [(t1 'Any) #t]
- [(`(Vector ,ts1 ...) `(Vector ,ts2 ...))
- (for/and ([t1 ts1] [t2 ts2]) (consistent? t1 t2))]
- [(`(,ts1 ... -> ,rt1) `(,ts2 ... -> ,rt2))
- (and (for/and ([t1 ts1] [t2 ts2]) (consistent? t1 t2))
- (consistent? rt1 rt2))]
- [(other wise) #f]))
- \end{lstlisting}
- \caption{The consistency predicate on types.}
- \label{fig:consistent}
- \end{figure}
- Returning to the \code{map-vec} example of
- Figure~\ref{fig:gradual-map-vec}, the \code{add1} function has type
- \code{(Any -> Any)} but parameter \code{f} of \code{map-vec} has type
- \code{(Integer -> Integer)}. The type checker for \LangGrad{} allows this
- because the two types are consistent. In particular, \code{->} is
- equal to \code{->} and because \code{Any} is consistent with
- \code{Integer}.
- Next consider a program with an error, such as applying the
- \code{map-vec} to a function that sometimes returns a Boolean, as
- shown in Figure~\ref{fig:map-vec-maybe-add1}. The type checker for
- \LangGrad{} accepts this program because the type of \code{maybe-add1} is
- consistent with the type of parameter \code{f} of \code{map-vec}, that
- is, \code{(Any -> Any)} is consistent with \code{(Integer ->
- Integer)}. One might say that a gradual type checker is optimistic
- in that it accepts programs that might execute without a runtime type
- error.
- %
- Unfortunately, running this program with input \code{1} triggers an
- error when the \code{maybe-add1} function returns \code{\#t}. \LangGrad{}
- performs checking at runtime to ensure the integrity of the static
- types, such as the \code{(Integer -> Integer)} annotation on parameter
- \code{f} of \code{map-vec}. This runtime checking is carried out by a
- new \code{Cast} form that is inserted by the type checker. Thus, the
- output of the type checker is a program in the \LangCast{} language, which
- adds \code{Cast} to \LangLoop{}, as shown in
- Figure~\ref{fig:Rgrad-prime-syntax}.
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Exp &::=& \ldots \MID \CAST{\Exp}{\Type}{\Type} \\
- \LangCastM{} &::=& \gray{ \PROGRAMDEFSEXP{\code{'()}}{\LP\Def\ldots\RP}{\Exp} }
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The abstract syntax of \LangCast{}, extending \LangLoop{} (Figure~\ref{fig:Rwhile-syntax}).}
- \label{fig:Rgrad-prime-syntax}
- \end{figure}
- \begin{figure}[tbp]
- \begin{lstlisting}
- (define (map-vec [f : (Integer -> Integer)]
- [v : (Vector Integer Integer)])
- : (Vector Integer Integer)
- (vector (f (vector-ref v 0)) (f (vector-ref v 1))))
- (define (add1 x) (+ x 1))
- (define (true) #t)
- (define (maybe-add1 x) (if (eq? 0 (read)) (add1 x) (true)))
- (vector-ref (map-vec maybe-add1 (vector 0 41)) 0)
- \end{lstlisting}
- \caption{A variant of the \code{map-vec} example with an error.}
- \label{fig:map-vec-maybe-add1}
- \end{figure}
- Figure~\ref{fig:map-vec-cast} shows the output of the type checker for
- \code{map-vec} and \code{maybe-add1}. The idea is that \code{Cast} is
- inserted every time the type checker sees two types that are
- consistent but not equal. In the \code{add1} function, \code{x} is
- cast to \code{Integer} and the result of the \code{+} is cast to
- \code{Any}. In the call to \code{map-vec}, the \code{add1} argument
- is cast from \code{(Any -> Any)} to \code{(Integer -> Integer)}.
- \begin{figure}[btp]
- \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
- (define (map-vec [f : (Integer -> Integer)] [v : (Vector Integer Integer)])
- : (Vector Integer Integer)
- (vector (f (vector-ref v 0)) (f (vector-ref v 1))))
- (define (add1 [x : Any]) : Any
- (cast (+ (cast x Any Integer) 1) Integer Any))
- (define (true) : Any (cast #t Boolean Any))
- (define (maybe-add1 [x : Any]) : Any
- (if (eq? 0 (read)) (add1 x) (true)))
- (vector-ref (map-vec (cast maybe-add1 (Any -> Any) (Integer -> Integer))
- (vector 0 41)) 0)
- \end{lstlisting}
- \caption{Output of type checking \code{map-vec}
- and \code{maybe-add1}.}
- \label{fig:map-vec-cast}
- \end{figure}
- The type checker for \LangGrad{} is defined in
- Figures~\ref{fig:type-check-Rgradual-1}, \ref{fig:type-check-Rgradual-2},
- and \ref{fig:type-check-Rgradual-3}.
- \begin{figure}[tbp]
- \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
- (define type-check-gradual_class
- (class type-check-Rwhile_class
- (super-new)
- (inherit operator-types type-predicates)
- (define/override (type-check-exp env)
- (lambda (e)
- (define recur (type-check-exp env))
- (match e
- [(Prim 'vector-length (list e1))
- (define-values (e1^ t) (recur e1))
- (match t
- [`(Vector ,ts ...)
- (values (Prim 'vector-length (list e1^)) 'Integer)]
- ['Any (values (Prim 'any-vector-length (list e1^)) 'Integer)])]
- [(Prim 'vector-ref (list e1 e2))
- (define-values (e1^ t1) (recur e1))
- (define-values (e2^ t2) (recur e2))
- (check-consistent? t2 'Integer e)
- (match t1
- [`(Vector ,ts ...)
- (match e2^
- [(Int i)
- (unless (and (0 . <= . i) (i . < . (length ts)))
- (error 'type-check "invalid index ~a in ~a" i e))
- (values (Prim 'vector-ref (list e1^ (Int i))) (list-ref ts i))]
- [else (define e1^^ (make-cast e1^ t1 'Any))
- (define e2^^ (make-cast e2^ t2 'Integer))
- (values (Prim 'any-vector-ref (list e1^^ e2^^)) 'Any)])]
- ['Any
- (define e2^^ (make-cast e2^ t2 'Integer))
- (values (Prim 'any-vector-ref (list e1^ e2^^)) 'Any)]
- [else (error 'type-check "expected vector not ~a\nin ~v" t1 e)])]
- [(Prim 'vector-set! (list e1 e2 e3) )
- (define-values (e1^ t1) (recur e1))
- (define-values (e2^ t2) (recur e2))
- (define-values (e3^ t3) (recur e3))
- (check-consistent? t2 'Integer e)
- (match t1
- [`(Vector ,ts ...)
- (match e2^
- [(Int i)
- (unless (and (0 . <= . i) (i . < . (length ts)))
- (error 'type-check "invalid index ~a in ~a" i e))
- (check-consistent? (list-ref ts i) t3 e)
- (define e3^^ (make-cast e3^ t3 (list-ref ts i)))
- (values (Prim 'vector-set! (list e1^ (Int i) e3^^)) 'Void)]
- [else
- (define e1^^ (make-cast e1^ t1 'Any))
- (define e2^^ (make-cast e2^ t2 'Integer))
- (define e3^^ (make-cast e3^ t3 'Any))
- (values (Prim 'any-vector-set! (list e1^^ e2^^ e3^^)) 'Void)])]
- ['Any
- (define e2^^ (make-cast e2^ t2 'Integer))
- (define e3^^ (make-cast e3^ t3 'Any))
- (values (Prim 'any-vector-set! (list e1^ e2^^ e3^^)) 'Void)]
- [else (error 'type-check "expected vector not ~a\nin ~v" t1 e)])]
- \end{lstlisting}
- \caption{Type checker for the \LangGrad{} language, part 1.}
- \label{fig:type-check-Rgradual-1}
- \end{figure}
- \begin{figure}[tbp]
- \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
- [(Prim 'eq? (list e1 e2))
- (define-values (e1^ t1) (recur e1))
- (define-values (e2^ t2) (recur e2))
- (check-consistent? t1 t2 e)
- (define T (meet t1 t2))
- (values (Prim 'eq? (list (make-cast e1^ t1 T) (make-cast e2^ t2 T)))
- 'Boolean)]
- [(Prim 'not (list e1))
- (define-values (e1^ t1) (recur e1))
- (match t1
- ['Any
- (recur (If (Prim 'eq? (list e1 (Inject (Bool #f) 'Boolean)))
- (Bool #t) (Bool #f)))]
- [else
- (define-values (t-ret new-es^)
- (type-check-op 'not (list t1) (list e1^) e))
- (values (Prim 'not new-es^) t-ret)])]
- [(Prim 'and (list e1 e2))
- (recur (If e1 e2 (Bool #f)))]
- [(Prim 'or (list e1 e2))
- (define tmp (gensym 'tmp))
- (recur (Let tmp e1 (If (Var tmp) (Var tmp) e2)))]
- [(Prim op es)
- #:when (not (set-member? explicit-prim-ops op))
- (define-values (new-es ts)
- (for/lists (exprs types) ([e es])
- (recur e)))
- (define-values (t-ret new-es^) (type-check-op op ts new-es e))
- (values (Prim op new-es^) t-ret)]
- [(If e1 e2 e3)
- (define-values (e1^ T1) (recur e1))
- (define-values (e2^ T2) (recur e2))
- (define-values (e3^ T3) (recur e3))
- (check-consistent? T2 T3 e)
- (match T1
- ['Boolean
- (define Tif (join T2 T3))
- (values (If e1^ (make-cast e2^ T2 Tif)
- (make-cast e3^ T3 Tif)) Tif)]
- ['Any
- (define Tif (meet T2 T3))
- (values (If (Prim 'eq? (list e1^ (Inject (Bool #f) 'Boolean)))
- (make-cast e3^ T3 Tif) (make-cast e2^ T2 Tif))
- Tif)]
- [else (error 'type-check "expected Boolean not ~a\nin ~v" T1 e)])]
- [(HasType e1 T)
- (define-values (e1^ T1) (recur e1))
- (check-consistent? T1 T)
- (values (make-cast e1^ T1 T) T)]
- [(SetBang x e1)
- (define-values (e1^ T1) (recur e1))
- (define varT (dict-ref env x))
- (check-consistent? T1 varT e)
- (values (SetBang x (make-cast e1^ T1 varT)) 'Void)]
- [(WhileLoop e1 e2)
- (define-values (e1^ T1) (recur e1))
- (check-consistent? T1 'Boolean e)
- (define-values (e2^ T2) ((type-check-exp env) e2))
- (values (WhileLoop (make-cast e1^ T1 'Boolean) e2^) 'Void)]
- \end{lstlisting}
- \caption{Type checker for the \LangGrad{} language, part 2.}
- \label{fig:type-check-Rgradual-2}
- \end{figure}
- \begin{figure}[tbp]
- \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
- [(Apply e1 e2s)
- (define-values (e1^ T1) (recur e1))
- (define-values (e2s^ T2s) (for/lists (e* ty*) ([e2 e2s]) (recur e2)))
- (match T1
- [`(,T1ps ... -> ,T1rt)
- (for ([T2 T2s] [Tp T1ps])
- (check-consistent? T2 Tp e))
- (define e2s^^ (for/list ([e2 e2s^] [src T2s] [tgt T1ps])
- (make-cast e2 src tgt)))
- (values (Apply e1^ e2s^^) T1rt)]
- [`Any
- (define e1^^ (make-cast e1^ 'Any
- `(,@(for/list ([e e2s]) 'Any) -> Any)))
- (define e2s^^ (for/list ([e2 e2s^] [src T2s])
- (make-cast e2 src 'Any)))
- (values (Apply e1^^ e2s^^) 'Any)]
- [else (error 'type-check "expected function not ~a\nin ~v" T1 e)])]
- [(Lambda params Tr e1)
- (define-values (xs Ts) (for/lists (l1 l2) ([p params])
- (match p
- [`[,x : ,T] (values x T)]
- [(? symbol? x) (values x 'Any)])))
- (define-values (e1^ T1)
- ((type-check-exp (append (map cons xs Ts) env)) e1))
- (check-consistent? Tr T1 e)
- (values (Lambda (for/list ([x xs] [T Ts]) `[,x : ,T]) Tr
- (make-cast e1^ T1 Tr)) `(,@Ts -> ,Tr))]
- [else ((super type-check-exp env) e)]
- )))
- \end{lstlisting}
- \caption{Type checker for the \LangGrad{} language, part 3.}
- \label{fig:type-check-Rgradual-3}
- \end{figure}
- \begin{figure}[tbp]
- \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
- (define/public (join t1 t2)
- (match* (t1 t2)
- [('Integer 'Integer) 'Integer]
- [('Boolean 'Boolean) 'Boolean]
- [('Void 'Void) 'Void]
- [('Any t2) t2]
- [(t1 'Any) t1]
- [(`(Vector ,ts1 ...) `(Vector ,ts2 ...))
- `(Vector ,@(for/list ([t1 ts1] [t2 ts2]) (join t1 t2)))]
- [(`(,ts1 ... -> ,rt1) `(,ts2 ... -> ,rt2))
- `(,@(for/list ([t1 ts1] [t2 ts2]) (join t1 t2))
- -> ,(join rt1 rt2))]))
- (define/public (meet t1 t2)
- (match* (t1 t2)
- [('Integer 'Integer) 'Integer]
- [('Boolean 'Boolean) 'Boolean]
- [('Void 'Void) 'Void]
- [('Any t2) 'Any]
- [(t1 'Any) 'Any]
- [(`(Vector ,ts1 ...) `(Vector ,ts2 ...))
- `(Vector ,@(for/list ([t1 ts1] [t2 ts2]) (meet t1 t2)))]
- [(`(,ts1 ... -> ,rt1) `(,ts2 ... -> ,rt2))
- `(,@(for/list ([t1 ts1] [t2 ts2]) (meet t1 t2))
- -> ,(meet rt1 rt2))]))
- (define/public (make-cast e src tgt)
- (cond [(equal? src tgt) e] [else (Cast e src tgt)]))
- (define/public (check-consistent? t1 t2 e)
- (unless (consistent? t1 t2)
- (error 'type-check "~a is inconsistent with ~a\nin ~v" t1 t2 e)))
- (define/override (type-check-op op arg-types args e)
- (match (dict-ref (operator-types) op)
- [`(,param-types . ,return-type)
- (for ([at arg-types] [pt param-types])
- (check-consistent? at pt e))
- (values return-type
- (for/list ([e args] [s arg-types] [t param-types])
- (make-cast e s t)))]
- [else (error 'type-check-op "unrecognized ~a" op)]))
- (define explicit-prim-ops
- (set-union
- (type-predicates)
- (set 'procedure-arity 'eq?
- 'vector 'vector-length 'vector-ref 'vector-set!
- 'any-vector-length 'any-vector-ref 'any-vector-set!)))
- (define/override (fun-def-type d)
- (match d
- [(Def f params rt info body)
- (define ps
- (for/list ([p params])
- (match p
- [`[,x : ,T] T]
- [(? symbol?) 'Any]
- [else (error 'fun-def-type "unmatched parameter ~a" p)])))
- `(,@ps -> ,rt)]
- [else (error 'fun-def-type "ill-formed function definition in ~a" d)]))
- \end{lstlisting}
- \caption{Auxiliary functions for type checking \LangGrad{}.}
- \label{fig:type-check-Rgradual-aux}
- \end{figure}
- \clearpage
- \section{Interpreting \LangCast{}}
- \label{sec:interp-casts}
- The runtime behavior of first-order casts is straightforward, that is,
- casts involving simple types such as \code{Integer} and
- \code{Boolean}. For example, a cast from \code{Integer} to \code{Any}
- can be accomplished with the \code{Inject} operator of \LangAny{}, which
- puts the integer into a tagged value
- (Figure~\ref{fig:interp-Rany}). Similarly, a cast from \code{Any} to
- \code{Integer} is accomplished with the \code{Project} operator, that
- is, by checking the value's tag and either retrieving the underlying
- integer or signaling an error if it the tag is not the one for
- integers (Figure~\ref{fig:apply-project}).
- %
- Things get more interesting for higher-order casts, that is, casts
- involving function or vector types.
- Consider the cast of the function \code{maybe-add1} from \code{(Any ->
- Any)} to \code{(Integer -> Integer)}. When a function flows through
- this cast at runtime, we can't know in general whether the function
- will always return an integer.\footnote{Predicting the return value of
- a function is equivalent to the halting problem, which is
- undecidable.} The \LangCast{} interpreter therefore delays the checking
- of the cast until the function is applied. This is accomplished by
- wrapping \code{maybe-add1} in a new function that casts its parameter
- from \code{Integer} to \code{Any}, applies \code{maybe-add1}, and then
- casts the return value from \code{Any} to \code{Integer}.
- Turning our attention to casts involving vector types, we consider the
- example in Figure~\ref{fig:map-vec-bang} that defines a
- partially-typed version of \code{map-vec} whose parameter \code{v} has
- type \code{(Vector Any Any)} and that updates \code{v} in place
- instead of returning a new vector. So we name this function
- \code{map-vec!}. We apply \code{map-vec!} to a vector of integers, so
- the type checker inserts a cast from \code{(Vector Integer Integer)}
- to \code{(Vector Any Any)}. A naive way for the \LangCast{} interpreter to
- cast between vector types would be a build a new vector whose elements
- are the result of casting each of the original elements to the
- appropriate target type. However, this approach is only valid for
- immutable vectors; and our vectors are mutable. In the example of
- Figure~\ref{fig:map-vec-bang}, if the cast created a new vector, then
- the updates inside of \code{map-vec!} would happen to the new vector
- and not the original one.
- \begin{figure}[tbp]
- % gradual_test_11.rkt
- \begin{lstlisting}
- (define (map-vec! [f : (Any -> Any)]
- [v : (Vector Any Any)]) : Void
- (begin
- (vector-set! v 0 (f (vector-ref v 0)))
- (vector-set! v 1 (f (vector-ref v 1)))))
- (define (add1 x) (+ x 1))
- (let ([v (vector 0 41)])
- (begin (map-vec! add1 v) (vector-ref v 1)))
- \end{lstlisting}
- \caption{An example involving casts on vectors.}
- \label{fig:map-vec-bang}
- \end{figure}
- Instead the interpreter needs to create a new kind of value, a
- \emph{vector proxy}, that intercepts every vector operation. On a
- read, the proxy reads from the underlying vector and then applies a
- cast to the resulting value. On a write, the proxy casts the argument
- value and then performs the write to the underlying vector. For the
- first \code{(vector-ref v 0)} in \code{map-vec!}, the proxy casts
- \code{0} from \code{Integer} to \code{Any}. For the first
- \code{vector-set!}, the proxy casts a tagged \code{1} from \code{Any}
- to \code{Integer}.
- The final category of cast that we need to consider are casts between
- the \code{Any} type and either a function or a vector
- type. Figure~\ref{fig:map-vec-any} shows a variant of \code{map-vec!}
- in which parameter \code{v} does not have a type annotation, so it is
- given type \code{Any}. In the call to \code{map-vec!}, the vector has
- type \code{(Vector Integer Integer)} so the type checker inserts a
- cast from \code{(Vector Integer Integer)} to \code{Any}. A first
- thought is to use \code{Inject}, but that doesn't work because
- \code{(Vector Integer Integer)} is not a flat type. Instead, we must
- first cast to \code{(Vector Any Any)} (which is flat) and then inject
- to \code{Any}.
- \begin{figure}[tbp]
- \begin{lstlisting}
- (define (map-vec! [f : (Any -> Any)] v) : Void
- (begin
- (vector-set! v 0 (f (vector-ref v 0)))
- (vector-set! v 1 (f (vector-ref v 1)))))
- (define (add1 x) (+ x 1))
- (let ([v (vector 0 41)])
- (begin (map-vec! add1 v) (vector-ref v 1)))
- \end{lstlisting}
- \caption{Casting a vector to \code{Any}.}
- \label{fig:map-vec-any}
- \end{figure}
- The \LangCast{} interpreter uses an auxiliary function named
- \code{apply-cast} to cast a value from a source type to a target type,
- shown in Figure~\ref{fig:apply-cast}. You'll find that it handles all
- of the kinds of casts that we've discussed in this section.
- \begin{figure}[tbp]
- \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
- (define/public (apply-cast v s t)
- (match* (s t)
- [(t1 t2) #:when (equal? t1 t2) v]
- [('Any t2)
- (match t2
- [`(,ts ... -> ,rt)
- (define any->any `(,@(for/list ([t ts]) 'Any) -> Any))
- (define v^ (apply-project v any->any))
- (apply-cast v^ any->any `(,@ts -> ,rt))]
- [`(Vector ,ts ...)
- (define vec-any `(Vector ,@(for/list ([t ts]) 'Any)))
- (define v^ (apply-project v vec-any))
- (apply-cast v^ vec-any `(Vector ,@ts))]
- [else (apply-project v t2)])]
- [(t1 'Any)
- (match t1
- [`(,ts ... -> ,rt)
- (define any->any `(,@(for/list ([t ts]) 'Any) -> Any))
- (define v^ (apply-cast v `(,@ts -> ,rt) any->any))
- (apply-inject v^ (any-tag any->any))]
- [`(Vector ,ts ...)
- (define vec-any `(Vector ,@(for/list ([t ts]) 'Any)))
- (define v^ (apply-cast v `(Vector ,@ts) vec-any))
- (apply-inject v^ (any-tag vec-any))]
- [else (apply-inject v (any-tag t1))])]
- [(`(Vector ,ts1 ...) `(Vector ,ts2 ...))
- (define x (gensym 'x))
- (define cast-reads (for/list ([t1 ts1] [t2 ts2])
- `(function (,x) ,(Cast (Var x) t1 t2) ())))
- (define cast-writes
- (for/list ([t1 ts1] [t2 ts2])
- `(function (,x) ,(Cast (Var x) t2 t1) ())))
- `(vector-proxy ,(vector v (apply vector cast-reads)
- (apply vector cast-writes)))]
- [(`(,ts1 ... -> ,rt1) `(,ts2 ... -> ,rt2))
- (define xs (for/list ([t2 ts2]) (gensym 'x)))
- `(function ,xs ,(Cast
- (Apply (Value v)
- (for/list ([x xs][t1 ts1][t2 ts2])
- (Cast (Var x) t2 t1)))
- rt1 rt2) ())]
- ))
- \end{lstlisting}
- \caption{The \code{apply-cast} auxiliary method.}
- \label{fig:apply-cast}
- \end{figure}
- The interpreter for \LangCast{} is defined in
- Figure~\ref{fig:interp-Rcast}, with the case for \code{Cast}
- dispatching to \code{apply-cast}. To handle the addition of vector
- proxies, we update the vector primitives in \code{interp-op} using the
- functions in Figure~\ref{fig:guarded-vector}.
- \begin{figure}[tbp]
- \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
- (define interp-Rcast_class
- (class interp-Rwhile_class
- (super-new)
- (inherit apply-fun apply-inject apply-project)
- (define/override (interp-op op)
- (match op
- ['vector-length guarded-vector-length]
- ['vector-ref guarded-vector-ref]
- ['vector-set! guarded-vector-set!]
- ['any-vector-ref (lambda (v i)
- (match v [`(tagged ,v^ ,tg)
- (guarded-vector-ref v^ i)]))]
- ['any-vector-set! (lambda (v i a)
- (match v [`(tagged ,v^ ,tg)
- (guarded-vector-set! v^ i a)]))]
- ['any-vector-length (lambda (v)
- (match v [`(tagged ,v^ ,tg)
- (guarded-vector-length v^)]))]
- [else (super interp-op op)]
- ))
- (define/override ((interp-exp env) e)
- (define (recur e) ((interp-exp env) e))
- (match e
- [(Value v) v]
- [(Cast e src tgt) (apply-cast (recur e) src tgt)]
- [else ((super interp-exp env) e)]))
- ))
- (define (interp-Rcast p)
- (send (new interp-Rcast_class) interp-program p))
- \end{lstlisting}
- \caption{The interpreter for \LangCast{}.}
- \label{fig:interp-Rcast}
- \end{figure}
- \begin{figure}[tbp]
- \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
- (define (guarded-vector-ref vec i)
- (match vec
- [`(vector-proxy ,proxy)
- (define val (guarded-vector-ref (vector-ref proxy 0) i))
- (define rd (vector-ref (vector-ref proxy 1) i))
- (apply-fun rd (list val) 'guarded-vector-ref)]
- [else (vector-ref vec i)]))
-
- (define (guarded-vector-set! vec i arg)
- (match vec
- [`(vector-proxy ,proxy)
- (define wr (vector-ref (vector-ref proxy 2) i))
- (define arg^ (apply-fun wr (list arg) 'guarded-vector-set!))
- (guarded-vector-set! (vector-ref proxy 0) i arg^)]
- [else (vector-set! vec i arg)]))
-
- (define (guarded-vector-length vec)
- (match vec
- [`(vector-proxy ,proxy)
- (guarded-vector-length (vector-ref proxy 0))]
- [else (vector-length vec)]))
- \end{lstlisting}
- \caption{The guarded-vector auxiliary functions.}
- \label{fig:guarded-vector}
- \end{figure}
- \section{Lower Casts}
- \label{sec:lower-casts}
- The next step in the journey towards x86 is the \code{lower-casts}
- pass that translates the casts in \LangCast{} to the lower-level
- \code{Inject} and \code{Project} operators and a new operator for
- creating vector proxies, extending the \LangLoop{} language to create
- \LangProxy{}. We recommend creating an auxiliary function named
- \code{lower-cast} that takes an expression (in \LangCast{}), a source type,
- and a target type, and translates it to expression in \LangProxy{} that has
- the same behavior as casting the expression from the source to the
- target type in the interpreter.
- The \code{lower-cast} function can follow a code structure similar to
- the \code{apply-cast} function (Figure~\ref{fig:apply-cast}) used in
- the interpreter for \LangCast{} because it must handle the same cases as
- \code{apply-cast} and it needs to mimic the behavior of
- \code{apply-cast}. The most interesting cases are those concerning the
- casts between two vector types and between two function types.
- As mentioned in Section~\ref{sec:interp-casts}, a cast from one vector
- type to another vector type is accomplished by creating a proxy that
- intercepts the operations on the underlying vector. Here we make the
- creation of the proxy explicit with the \code{vector-proxy} primitive
- operation. It takes three arguments, the first is an expression for
- the vector, the second is a vector of functions for casting an element
- that is being read from the vector, and the third is a vector of
- functions for casting an element that is being written to the vector.
- You can create the functions using \code{Lambda}. Also, as we shall
- see in the next section, we need to differentiate these vectors from
- the user-created ones, so we recommend using a new primitive operator
- named \code{raw-vector} instead of \code{vector} to create these
- vectors of functions. Figure~\ref{fig:map-vec-bang-lower-cast} shows
- the output of \code{lower-casts} on the example in
- Figure~\ref{fig:map-vec-bang} that involved casting a vector of
- integers to a vector of \code{Any}.
- \begin{figure}[tbp]
- \begin{lstlisting}
- (define (map-vec! [f : (Any -> Any)] [v : (Vector Any Any)]) : Void
- (begin
- (vector-set! v 0 (f (vector-ref v 0)))
- (vector-set! v 1 (f (vector-ref v 1)))))
-
- (define (add1 [x : Any]) : Any
- (inject (+ (project x Integer) 1) Integer))
- (let ([v (vector 0 41)])
- (begin
- (map-vec! add1 (vector-proxy v
- (raw-vector (lambda: ([x9 : Integer]) : Any
- (inject x9 Integer))
- (lambda: ([x9 : Integer]) : Any
- (inject x9 Integer)))
- (raw-vector (lambda: ([x9 : Any]) : Integer
- (project x9 Integer))
- (lambda: ([x9 : Any]) : Integer
- (project x9 Integer)))))
- (vector-ref v 1)))
- \end{lstlisting}
- \caption{Output of \code{lower-casts} on the example in
- Figure~\ref{fig:map-vec-bang}.}
- \label{fig:map-vec-bang-lower-cast}
- \end{figure}
- A cast from one function type to another function type is accomplished
- by generating a \code{Lambda} whose parameter and return types match
- the target function type. The body of the \code{Lambda} should cast
- the parameters from the target type to the source type (yes,
- backwards! functions are contravariant\index{subject}{contravariant} in the
- parameters), then call the underlying function, and finally cast the
- result from the source return type to the target return type.
- Figure~\ref{fig:map-vec-lower-cast} shows the output of the
- \code{lower-casts} pass on the \code{map-vec} example in
- Figure~\ref{fig:gradual-map-vec}. Note that the \code{add1} argument
- in the call to \code{map-vec} is wrapped in a \code{lambda}.
- \begin{figure}[tbp]
- \begin{lstlisting}
- (define (map-vec [f : (Integer -> Integer)]
- [v : (Vector Integer Integer)])
- : (Vector Integer Integer)
- (vector (f (vector-ref v 0)) (f (vector-ref v 1))))
- (define (add1 [x : Any]) : Any
- (inject (+ (project x Integer) 1) Integer))
- (vector-ref (map-vec (lambda: ([x9 : Integer]) : Integer
- (project (add1 (inject x9 Integer)) Integer))
- (vector 0 41)) 1)
- \end{lstlisting}
- \caption{Output of \code{lower-casts} on the example in
- Figure~\ref{fig:gradual-map-vec}.}
- \label{fig:map-vec-lower-cast}
- \end{figure}
- \section{Differentiate Proxies}
- \label{sec:differentiate-proxies}
- So far the job of differentiating vectors and vector proxies has been
- the job of the interpreter. For example, the interpreter for \LangCast{}
- implements \code{vector-ref} using the \code{guarded-vector-ref}
- function in Figure~\ref{fig:guarded-vector}. In the
- \code{differentiate-proxies} pass we shift this responsibility to the
- generated code.
- We begin by designing the output language $R^p_8$. In
- \LangGrad{} we used the type \code{Vector} for both real vectors and vector
- proxies. In $R^p_8$ we return the \code{Vector} type to
- its original meaning, as the type of real vectors, and we introduce a
- new type, \code{PVector}, whose values can be either real vectors or
- vector proxies. This new type comes with a suite of new primitive
- operations for creating and using values of type \code{PVector}. We
- don't need to introduce a new type to represent vector proxies. A
- proxy is represented by a vector containing three things: 1) the
- underlying vector, 2) a vector of functions for casting elements that
- are read from the vector, and 3) a vector of functions for casting
- values to be written to the vector. So we define the following
- abbreviation for the type of a vector proxy:
- \[
- \itm{Proxy} (T\ldots \Rightarrow T'\ldots)
- = (\ttm{Vector}~(\ttm{PVector}~ T\ldots) ~R~ W)
- \to (\key{PVector}~ T' \ldots)
- \]
- where $R = (\ttm{Vector}~(T\to T') \ldots)$ and
- $W = (\ttm{Vector}~(T'\to T) \ldots)$.
- %
- Next we describe each of the new primitive operations.
- \begin{description}
- \item[\code{inject-vector} : (\key{Vector} $T \ldots$) $\to$
- (\key{PVector} $T \ldots$)]\ \\
- %
- This operation brands a vector as a value of the \code{PVector} type.
- \item[\code{inject-proxy} : $\itm{Proxy}(T\ldots \Rightarrow T'\ldots)$
- $\to$ (\key{PVector} $T' \ldots$)]\ \\
- %
- This operation brands a vector proxy as value of the \code{PVector} type.
- \item[\code{proxy?} : (\key{PVector} $T \ldots$) $\to$
- \code{Boolean}] \ \\
- %
- returns true if the value is a vector proxy and false if it is a
- real vector.
- \item[\code{project-vector} : (\key{PVector} $T \ldots$) $\to$
- (\key{Vector} $T \ldots$)]\ \\
- %
- Assuming that the input is a vector (and not a proxy), this
- operation returns the vector.
-
- \item[\code{proxy-vector-length} : (\key{PVector} $T \ldots$)
- $\to$ \code{Boolean}]\ \\
- %
- Given a vector proxy, this operation returns the length of the
- underlying vector.
-
- \item[\code{proxy-vector-ref} : (\key{PVector} $T \ldots$)
- $\to$ ($i$ : \code{Integer}) $\to$ $T_i$]\ \\
- %
- Given a vector proxy, this operation returns the $i$th element of
- the underlying vector.
-
- \item[\code{proxy-vector-set!} : (\key{PVector} $T \ldots$) $\to$ ($i$
- : \code{Integer}) $\to$ $T_i$ $\to$ \key{Void}]\ \\ Given a vector
- proxy, this operation writes a value to the $i$th element of the
- underlying vector.
- \end{description}
- Now to discuss the translation that differentiates vectors from
- proxies. First, every type annotation in the program must be
- translated (recursively) to replace \code{Vector} with \code{PVector}.
- Next, we must insert uses of \code{PVector} operations in the
- appropriate places. For example, we wrap every vector creation with an
- \code{inject-vector}.
- \begin{lstlisting}
- (vector |$e_1 \ldots e_n$|)
- |$\Rightarrow$|
- (inject-vector (vector |$e'_1 \ldots e'_n$|))
- \end{lstlisting}
- The \code{raw-vector} operator that we introduced in the previous
- section does not get injected.
- \begin{lstlisting}
- (raw-vector |$e_1 \ldots e_n$|)
- |$\Rightarrow$|
- (vector |$e'_1 \ldots e'_n$|)
- \end{lstlisting}
- The \code{vector-proxy} primitive translates as follows.
- \begin{lstlisting}
- (vector-proxy |$e_1~e_2~e_3$|)
- |$\Rightarrow$|
- (inject-proxy (vector |$e'_1~e'_2~e'_3$|))
- \end{lstlisting}
- We translate the vector operations into conditional expressions that
- check whether the value is a proxy and then dispatch to either the
- appropriate proxy vector operation or the regular vector operation.
- For example, the following is the translation for \code{vector-ref}.
- \begin{lstlisting}
- (vector-ref |$e_1$| |$i$|)
- |$\Rightarrow$|
- (let ([|$v~e_1$|])
- (if (proxy? |$v$|)
- (proxy-vector-ref |$v$| |$i$|)
- (vector-ref (project-vector |$v$|) |$i$|)
- \end{lstlisting}
- Note in the case of a real vector, we must apply \code{project-vector}
- before the \code{vector-ref}.
- \section{Reveal Casts}
- \label{sec:reveal-casts-gradual}
- Recall that the \code{reveal-casts} pass
- (Section~\ref{sec:reveal-casts-Rany}) is responsible for lowering
- \code{Inject} and \code{Project} into lower-level operations. In
- particular, \code{Project} turns into a conditional expression that
- inspects the tag and retrieves the underlying value. Here we need to
- augment the translation of \code{Project} to handle the situation when
- the target type is \code{PVector}. Instead of using
- \code{vector-length} we need to use \code{proxy-vector-length}.
- \begin{lstlisting}
- (project |$e$| (PVector Any|$_1$| |$\ldots$| Any|$_n$|))
- |$\Rightarrow$|
- (let |$\itm{tmp}$| |$e'$|
- (if (eq? (tag-of-any |$\itm{tmp}$| 2))
- (let |$\itm{vec}$| (value-of |$\itm{tmp}$| (PVector Any |$\ldots$| Any))
- (if (eq? (proxy-vector-length |$\itm{vec}$|) |$n$|) |$\itm{vec}$| (exit)))
- (exit)))
- \end{lstlisting}
- \section{Closure Conversion}
- \label{sec:closure-conversion-gradual}
- The closure conversion pass only requires one minor adjustment. The
- auxiliary function that translates type annotations needs to be
- updated to handle the \code{PVector} type.
- \section{Explicate Control}
- \label{sec:explicate-control-gradual}
- Update the \code{explicate\_control} pass to handle the new primitive
- operations on the \code{PVector} type.
- \section{Select Instructions}
- \label{sec:select-instructions-gradual}
- Recall that the \code{select\_instructions} pass is responsible for
- lowering the primitive operations into x86 instructions. So we need
- to translate the new \code{PVector} operations to x86. To do so, the
- first question we need to answer is how will we differentiate the two
- kinds of values (vectors and proxies) that can inhabit \code{PVector}.
- We need just one bit to accomplish this, and use the bit in position
- $57$ of the 64-bit tag at the front of every vector (see
- Figure~\ref{fig:tuple-rep}). So far, this bit has been set to $0$, so
- for \code{inject-vector} we leave it that way.
- \begin{lstlisting}
- (Assign |$\itm{lhs}$| (Prim 'inject-vector (list |$e_1$|)))
- |$\Rightarrow$|
- movq |$e'_1$|, |$\itm{lhs'}$|
- \end{lstlisting}
- On the other hand, \code{inject-proxy} sets bit $57$ to $1$.
- \begin{lstlisting}
- (Assign |$\itm{lhs}$| (Prim 'inject-proxy (list |$e_1$|)))
- |$\Rightarrow$|
- movq |$e'_1$|, %r11
- movq |$(1 << 57)$|, %rax
- orq 0(%r11), %rax
- movq %rax, 0(%r11)
- movq %r11, |$\itm{lhs'}$|
- \end{lstlisting}
- The \code{proxy?} operation consumes the information so carefully
- stashed away by \code{inject-vector} and \code{inject-proxy}. It
- isolates the $57$th bit to tell whether the value is a real vector or
- a proxy.
- \begin{lstlisting}
- (Assign |$\itm{lhs}$| (Prim 'proxy? (list e)))
- |$\Rightarrow$|
- movq |$e_1'$|, %r11
- movq 0(%r11), %rax
- sarq $57, %rax
- andq $1, %rax
- movq %rax, |$\itm{lhs'}$|
- \end{lstlisting}
- The \code{project-vector} operation is straightforward to translate,
- so we leave it up to the reader.
- Regarding the \code{proxy-vector} operations, the runtime provides
- procedures that implement them (they are recursive functions!) so
- here we simply need to translate these vector operations into the
- appropriate function call. For example, here is the translation for
- \code{proxy-vector-ref}.
- \begin{lstlisting}
- (Assign |$\itm{lhs}$| (Prim 'proxy-vector-ref (list |$e_1$| |$e_2$|)))
- |$\Rightarrow$|
- movq |$e_1'$|, %rdi
- movq |$e_2'$|, %rsi
- callq proxy_vector_ref
- movq %rax, |$\itm{lhs'}$|
- \end{lstlisting}
- We have another batch of vector operations to deal with, those for the
- \code{Any} type. Recall that the type checker for \LangGrad{} generates an
- \code{any-vector-ref} when there is a \code{vector-ref} on something
- of type \code{Any}, and similarly for \code{any-vector-set!} and
- \code{any-vector-length} (Figure~\ref{fig:type-check-Rgradual-1}). In
- Section~\ref{sec:select-Rany} we selected instructions for these
- operations based on the idea that the underlying value was a real
- vector. But in the current setting, the underlying value is of type
- \code{PVector}. So \code{any-vector-ref} can be translates to
- pseudo-x86 as follows. We begin by projecting the underlying value out
- of the tagged value and then call the \code{proxy\_vector\_ref}
- procedure in the runtime.
- \begin{lstlisting}
- (Assign |$\itm{lhs}$| (Prim 'any-vector-ref (list |$e_1$| |$e_2$|)))
- movq |$\neg 111$|, %rdi
- andq |$e_1'$|, %rdi
- movq |$e_2'$|, %rsi
- callq proxy_vector_ref
- movq %rax, |$\itm{lhs'}$|
- \end{lstlisting}
- The \code{any-vector-set!} and \code{any-vector-length} operators can
- be translated in a similar way.
- \begin{exercise}\normalfont
- Implement a compiler for the gradually-typed \LangGrad{} language by
- extending and adapting your compiler for \LangLoop{}. Create 10 new
- partially-typed test programs. In addition to testing with these
- new programs, also test your compiler on all the tests for \LangLoop{}
- and tests for \LangDyn{}. Sometimes you may get a type checking error
- on the \LangDyn{} programs but you can adapt them by inserting
- a cast to the \code{Any} type around each subexpression
- causing a type error. While \LangDyn{} doesn't have explicit casts,
- you can induce one by wrapping the subexpression \code{e}
- with a call to an un-annotated identity function, like this:
- \code{((lambda (x) x) e)}.
- \end{exercise}
- \begin{figure}[p]
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (Rgradual) at (6,4) {\large \LangGrad{}};
- \node (Rgradualp) at (3,4) {\large \LangCast{}};
- \node (Rwhilepp) at (0,4) {\large \LangProxy{}};
- \node (Rwhileproxy) at (0,2) {\large \LangPVec{}};
- \node (Rwhileproxy-2) at (3,2) {\large \LangPVec{}};
- \node (Rwhileproxy-3) at (6,2) {\large \LangPVec{}};
- \node (Rwhileproxy-4) at (9,2) {\large \LangPVecFunRef{}};
- \node (Rwhileproxy-5) at (12,2) {\large \LangPVecFunRef{}};
- \node (F1-1) at (12,0) {\large \LangPVecFunRef{}};
- \node (F1-2) at (9,0) {\large \LangPVecFunRef{}};
- \node (F1-3) at (6,0) {\large \LangPVecFunRef{}};
- \node (F1-4) at (3,0) {\large \LangPVecAlloc{}};
- \node (F1-5) at (0,0) {\large \LangPVecAlloc{}};
- \node (C3-2) at (3,-2) {\large \LangCLoopPVec{}};
- \node (x86-2) at (3,-4) {\large \LangXIndCallVar{}};
- \node (x86-2-1) at (3,-6) {\large \LangXIndCallVar{}};
- \node (x86-2-2) at (6,-6) {\large \LangXIndCallVar{}};
- \node (x86-3) at (6,-4) {\large \LangXIndCallVar{}};
- \node (x86-4) at (9,-4) {\large \LangXIndCall{}};
- \node (x86-5) at (9,-6) {\large \LangXIndCall{}};
- \path[->,bend right=15] (Rgradual) edge [above] node
- {\ttfamily\footnotesize type\_check} (Rgradualp);
- \path[->,bend right=15] (Rgradualp) edge [above] node
- {\ttfamily\footnotesize lower\_casts} (Rwhilepp);
- \path[->,bend right=15] (Rwhilepp) edge [right] node
- {\ttfamily\footnotesize differentiate\_proxies} (Rwhileproxy);
- \path[->,bend left=15] (Rwhileproxy) edge [above] node
- {\ttfamily\footnotesize shrink} (Rwhileproxy-2);
- \path[->,bend left=15] (Rwhileproxy-2) edge [above] node
- {\ttfamily\footnotesize uniquify} (Rwhileproxy-3);
- \path[->,bend left=15] (Rwhileproxy-3) edge [above] node
- {\ttfamily\footnotesize reveal\_functions} (Rwhileproxy-4);
- \path[->,bend left=15] (Rwhileproxy-4) edge [above] node
- {\ttfamily\footnotesize reveal\_casts} (Rwhileproxy-5);
- \path[->,bend left=15] (Rwhileproxy-5) edge [left] node
- {\ttfamily\footnotesize convert\_assignments} (F1-1);
- \path[->,bend left=15] (F1-1) edge [below] node
- {\ttfamily\footnotesize convert\_to\_clos.} (F1-2);
- \path[->,bend right=15] (F1-2) edge [above] node
- {\ttfamily\footnotesize limit\_fun.} (F1-3);
- \path[->,bend right=15] (F1-3) edge [above] node
- {\ttfamily\footnotesize expose\_alloc.} (F1-4);
- \path[->,bend right=15] (F1-4) edge [above] node
- {\ttfamily\footnotesize remove\_complex.} (F1-5);
- \path[->,bend right=15] (F1-5) edge [right] node
- {\ttfamily\footnotesize explicate\_control} (C3-2);
- \path[->,bend left=15] (C3-2) edge [left] node
- {\ttfamily\footnotesize select\_instr.} (x86-2);
- \path[->,bend right=15] (x86-2) edge [left] node
- {\ttfamily\footnotesize uncover\_live} (x86-2-1);
- \path[->,bend right=15] (x86-2-1) edge [below] node
- {\ttfamily\footnotesize build\_inter.} (x86-2-2);
- \path[->,bend right=15] (x86-2-2) edge [left] node
- {\ttfamily\footnotesize allocate\_reg.} (x86-3);
- \path[->,bend left=15] (x86-3) edge [above] node
- {\ttfamily\footnotesize patch\_instr.} (x86-4);
- \path[->,bend left=15] (x86-4) edge [right] node {\ttfamily\footnotesize print-x86} (x86-5);
- \end{tikzpicture}
- \caption{Diagram of the passes for \LangGrad{} (gradual typing).}
- \label{fig:Rgradual-passes}
- \end{figure}
- Figure~\ref{fig:Rgradual-passes} provides an overview of all the passes needed
- for the compilation of \LangGrad{}.
- \section{Further Reading}
- This chapter just scratches the surface of gradual typing. The basic
- approach described here is missing two key ingredients that one would
- want in a implementation of gradual typing: blame
- tracking~\citep{Tobin-Hochstadt:2006fk,Wadler:2009qv} and
- space-efficient casts~\citep{Herman:2006uq,Herman:2010aa}. The
- problem addressed by blame tracking is that when a cast on a
- higher-order value fails, it often does so at a point in the program
- that is far removed from the original cast. Blame tracking is a
- technique for propagating extra information through casts and proxies
- so that when a cast fails, the error message can point back to the
- original location of the cast in the source program.
- The problem addressed by space-efficient casts also relates to
- higher-order casts. It turns out that in partially typed programs, a
- function or vector can flow through very-many casts at runtime. With
- the approach described in this chapter, each cast adds another
- \code{lambda} wrapper or a vector proxy. Not only does this take up
- considerable space, but it also makes the function calls and vector
- operations slow. For example, a partially-typed version of quicksort
- could, in the worst case, build a chain of proxies of length $O(n)$
- around the vector, changing the overall time complexity of the
- algorithm from $O(n^2)$ to $O(n^3)$! \citet{Herman:2006uq} suggested a
- solution to this problem by representing casts using the coercion
- calculus of \citet{Henglein:1994nz}, which prevents the creation of
- long chains of proxies by compressing them into a concise normal
- form. \citet{Siek:2015ab} give and algorithm for compressing coercions
- and \citet{Kuhlenschmidt:2019aa} show how to implement these ideas in
- the Grift compiler.
- \begin{center}
- \url{https://github.com/Gradual-Typing/Grift}
- \end{center}
- There are also interesting interactions between gradual typing and
- other language features, such as parametetric polymorphism,
- information-flow types, and type inference, to name a few. We
- recommend the reader to the online gradual typing bibliography:
- \begin{center}
- \url{http://samth.github.io/gradual-typing-bib/}
- \end{center}
- % TODO: challenge problem:
- % type analysis and type specialization?
- % coercions?
- \fi
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- \chapter{Parametric Polymorphism}
- \label{ch:Rpoly}
- \index{subject}{parametric polymorphism}
- \index{subject}{generics}
- \if\edition\racketEd
- This chapter studies the compilation of parametric
- polymorphism\index{subject}{parametric polymorphism}
- (aka. generics\index{subject}{generics}) in the subset \LangPoly{} of Typed
- Racket. Parametric polymorphism enables improved code reuse by
- parameterizing functions and data structures with respect to the types
- that they operate on. For example, Figure~\ref{fig:map-vec-poly}
- revisits the \code{map-vec} example but this time gives it a more
- fitting type. This \code{map-vec} function is parameterized with
- respect to the element type of the vector. The type of \code{map-vec}
- is the following polymorphic type as specified by the \code{All} and
- the type parameter \code{a}.
- \begin{lstlisting}
- (All (a) ((a -> a) (Vector a a) -> (Vector a a)))
- \end{lstlisting}
- The idea is that \code{map-vec} can be used at \emph{all} choices of a
- type for parameter \code{a}. In Figure~\ref{fig:map-vec-poly} we apply
- \code{map-vec} to a vector of integers, a choice of \code{Integer} for
- \code{a}, but we could have just as well applied \code{map-vec} to a
- vector of Booleans (and a function on Booleans).
- \begin{figure}[tbp]
- % poly_test_2.rkt
- \begin{lstlisting}
- (: map-vec (All (a) ((a -> a) (Vector a a) -> (Vector a a))))
- (define (map-vec f v)
- (vector (f (vector-ref v 0)) (f (vector-ref v 1))))
- (define (add1 [x : Integer]) : Integer (+ x 1))
- (vector-ref (map-vec add1 (vector 0 41)) 1)
- \end{lstlisting}
- \caption{The \code{map-vec} example using parametric polymorphism.}
- \label{fig:map-vec-poly}
- \end{figure}
- Figure~\ref{fig:Rpoly-concrete-syntax} defines the concrete syntax of
- \LangPoly{} and Figure~\ref{fig:Rpoly-syntax} defines the abstract
- syntax. We add a second form for function definitions in which a type
- declaration comes before the \code{define}. In the abstract syntax,
- the return type in the \code{Def} is \code{Any}, but that should be
- ignored in favor of the return type in the type declaration. (The
- \code{Any} comes from using the same parser as in
- Chapter~\ref{ch:Rdyn}.) The presence of a type declaration
- enables the use of an \code{All} type for a function, thereby making
- it polymorphic. The grammar for types is extended to include
- polymorphic types and type variables.
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Type &::=& \ldots \MID \LP\key{All}~\LP\Var\ldots\RP~ \Type\RP \MID \Var \\
- \Def &::=& \gray{ \CDEF{\Var}{\LS\Var \key{:} \Type\RS \ldots}{\Type}{\Exp} } \\
- &\MID& \LP\key{:}~\Var~\Type\RP \\
- && \LP\key{define}~ \LP\Var ~ \Var\ldots\RP ~ \Exp\RP \\
- \LangPoly{} &::=& \gray{ \Def \ldots ~ \Exp }
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The concrete syntax of \LangPoly{}, extending \LangLoop{}
- (Figure~\ref{fig:Rwhile-concrete-syntax}).}
- \label{fig:Rpoly-concrete-syntax}
- \end{figure}
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Type &::=& \ldots \MID \LP\key{All}~\LP\Var\ldots\RP~ \Type\RP \MID \Var \\
- \Def &::=& \gray{ \DEF{\Var}{\LP\LS\Var \key{:} \Type\RS \ldots\RP}{\Type}{\code{'()}}{\Exp} } \\
- &\MID& \DECL{\Var}{\Type} \\
- && \DEF{\Var}{\LP\Var \ldots\RP}{\key{'Any}}{\code{'()}}{\Exp} \\
- \LangPoly{} &::=& \gray{ \PROGRAMDEFSEXP{\code{'()}}{\LP\Def\ldots\RP}{\Exp} }
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The abstract syntax of \LangPoly{}, extending \LangLoop{}
- (Figure~\ref{fig:Rwhile-syntax}).}
- \label{fig:Rpoly-syntax}
- \end{figure}
- By including polymorphic types in the $\Type$ non-terminal we choose
- to make them first-class which has interesting repercussions on the
- compiler. Many languages with polymorphism, such as
- C++~\citep{stroustrup88:_param_types} and Standard
- ML~\citep{Milner:1990fk}, only support second-class polymorphism, so
- it is useful to see an example of first-class polymorphism. In
- Figure~\ref{fig:apply-twice} we define a function \code{apply-twice}
- whose parameter is a polymorphic function. The occurrence of a
- polymorphic type underneath a function type is enabled by the normal
- recursive structure of the grammar for $\Type$ and the categorization
- of the \code{All} type as a $\Type$. The body of \code{apply-twice}
- applies the polymorphic function to a Boolean and to an integer.
- \begin{figure}[tbp]
- \begin{lstlisting}
- (: apply-twice ((All (b) (b -> b)) -> Integer))
- (define (apply-twice f)
- (if (f #t) (f 42) (f 777)))
- (: id (All (a) (a -> a)))
- (define (id x) x)
- (apply-twice id)
- \end{lstlisting}
- \caption{An example illustrating first-class polymorphism.}
- \label{fig:apply-twice}
- \end{figure}
- The type checker for \LangPoly{} in Figure~\ref{fig:type-check-Lvar0} has
- three new responsibilities (compared to \LangLoop{}). The type checking of
- function application is extended to handle the case where the operator
- expression is a polymorphic function. In that case the type arguments
- are deduced by matching the type of the parameters with the types of
- the arguments.
- %
- The \code{match-types} auxiliary function carries out this deduction
- by recursively descending through a parameter type \code{pt} and the
- corresponding argument type \code{at}, making sure that they are equal
- except when there is a type parameter on the left (in the parameter
- type). If it's the first time that the type parameter has been
- encountered, then the algorithm deduces an association of the type
- parameter to the corresponding type on the right (in the argument
- type). If it's not the first time that the type parameter has been
- encountered, the algorithm looks up its deduced type and makes sure
- that it is equal to the type on the right.
- %
- Once the type arguments are deduced, the operator expression is
- wrapped in an \code{Inst} AST node (for instantiate) that records the
- type of the operator, but more importantly, records the deduced type
- arguments. The return type of the application is the return type of
- the polymorphic function, but with the type parameters replaced by the
- deduced type arguments, using the \code{subst-type} function.
- The second responsibility of the type checker is extending the
- function \code{type-equal?} to handle the \code{All} type. This is
- not quite a simple as equal on other types, such as function and
- vector types, because two polymorphic types can be syntactically
- different even though they are equivalent types. For example,
- \code{(All (a) (a -> a))} is equivalent to \code{(All (b) (b -> b))}.
- Two polymorphic types should be considered equal if they differ only
- in the choice of the names of the type parameters. The
- \code{type-equal?} function in Figure~\ref{fig:type-check-Lvar0-aux}
- renames the type parameters of the first type to match the type
- parameters of the second type.
- The third responsibility of the type checker is making sure that only
- defined type variables appear in type annotations. The
- \code{check-well-formed} function defined in
- Figure~\ref{fig:well-formed-types} recursively inspects a type, making
- sure that each type variable has been defined.
- The output language of the type checker is \LangInst{}, defined in
- Figure~\ref{fig:Rpoly-prime-syntax}. The type checker combines the type
- declaration and polymorphic function into a single definition, using
- the \code{Poly} form, to make polymorphic functions more convenient to
- process in next pass of the compiler.
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Type &::=& \ldots \MID \LP\key{All}~\LP\Var\ldots\RP~ \Type\RP \MID \Var \\
- \Exp &::=& \ldots \MID \INST{\Exp}{\Type}{\LP\Type\ldots\RP} \\
- \Def &::=& \gray{ \DEF{\Var}{\LP\LS\Var \key{:} \Type\RS \ldots\RP}{\Type}{\code{'()}}{\Exp} } \\
- &\MID& \LP\key{Poly}~\LP\Var\ldots\RP~ \DEF{\Var}{\LP\LS\Var \key{:} \Type\RS \ldots\RP}{\Type}{\code{'()}}{\Exp}\RP \\
- \LangInst{} &::=& \gray{ \PROGRAMDEFSEXP{\code{'()}}{\LP\Def\ldots\RP}{\Exp} }
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The abstract syntax of \LangInst{}, extending \LangLoop{}
- (Figure~\ref{fig:Rwhile-syntax}).}
- \label{fig:Rpoly-prime-syntax}
- \end{figure}
- The output of the type checker on the polymorphic \code{map-vec}
- example is listed in Figure~\ref{fig:map-vec-type-check}.
- \begin{figure}[tbp]
- % poly_test_2.rkt
- \begin{lstlisting}
- (poly (a) (define (map-vec [f : (a -> a)] [v : (Vector a a)]) : (Vector a a)
- (vector (f (vector-ref v 0)) (f (vector-ref v 1)))))
- (define (add1 [x : Integer]) : Integer (+ x 1))
- (vector-ref ((inst map-vec (All (a) ((a -> a) (Vector a a) -> (Vector a a)))
- (Integer))
- add1 (vector 0 41)) 1)
- \end{lstlisting}
- \caption{Output of the type checker on the \code{map-vec} example.}
- \label{fig:map-vec-type-check}
- \end{figure}
- \begin{figure}[tbp]
- \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
- (define type-check-poly-class
- (class type-check-Rwhile-class
- (super-new)
- (inherit check-type-equal?)
-
- (define/override (type-check-apply env e1 es)
- (define-values (e^ ty) ((type-check-exp env) e1))
- (define-values (es^ ty*) (for/lists (es^ ty*) ([e (in-list es)])
- ((type-check-exp env) e)))
- (match ty
- [`(,ty^* ... -> ,rt)
- (for ([arg-ty ty*] [param-ty ty^*])
- (check-type-equal? arg-ty param-ty (Apply e1 es)))
- (values e^ es^ rt)]
- [`(All ,xs (,tys ... -> ,rt))
- (define env^ (append (for/list ([x xs]) (cons x 'Type)) env))
- (define env^^ (for/fold ([env^^ env^]) ([arg-ty ty*] [param-ty tys])
- (match-types env^^ param-ty arg-ty)))
- (define targs
- (for/list ([x xs])
- (match (dict-ref env^^ x (lambda () #f))
- [#f (error 'type-check "type variable ~a not deduced\nin ~v"
- x (Apply e1 es))]
- [ty ty])))
- (values (Inst e^ ty targs) es^ (subst-type env^^ rt))]
- [else (error 'type-check "expected a function, not ~a" ty)]))
-
- (define/override ((type-check-exp env) e)
- (match e
- [(Lambda `([,xs : ,Ts] ...) rT body)
- (for ([T Ts]) ((check-well-formed env) T))
- ((check-well-formed env) rT)
- ((super type-check-exp env) e)]
- [(HasType e1 ty)
- ((check-well-formed env) ty)
- ((super type-check-exp env) e)]
- [else ((super type-check-exp env) e)]))
- (define/override ((type-check-def env) d)
- (verbose 'type-check "poly/def" d)
- (match d
- [(Generic ts (Def f (and p:t* (list `[,xs : ,ps] ...)) rt info body))
- (define ts-env (for/list ([t ts]) (cons t 'Type)))
- (for ([p ps]) ((check-well-formed ts-env) p))
- ((check-well-formed ts-env) rt)
- (define new-env (append ts-env (map cons xs ps) env))
- (define-values (body^ ty^) ((type-check-exp new-env) body))
- (check-type-equal? ty^ rt body)
- (Generic ts (Def f p:t* rt info body^))]
- [else ((super type-check-def env) d)]))
- (define/override (type-check-program p)
- (match p
- [(Program info body)
- (type-check-program (ProgramDefsExp info '() body))]
- [(ProgramDefsExp info ds body)
- (define ds^ (combine-decls-defs ds))
- (define new-env (for/list ([d ds^])
- (cons (def-name d) (fun-def-type d))))
- (define ds^^ (for/list ([d ds^]) ((type-check-def new-env) d)))
- (define-values (body^ ty) ((type-check-exp new-env) body))
- (check-type-equal? ty 'Integer body)
- (ProgramDefsExp info ds^^ body^)]))
- ))
- \end{lstlisting}
- \caption{Type checker for the \LangPoly{} language.}
- \label{fig:type-check-Lvar0}
- \end{figure}
- \begin{figure}[tbp]
- \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
- (define/override (type-equal? t1 t2)
- (match* (t1 t2)
- [(`(All ,xs ,T1) `(All ,ys ,T2))
- (define env (map cons xs ys))
- (type-equal? (subst-type env T1) T2)]
- [(other wise)
- (super type-equal? t1 t2)]))
- (define/public (match-types env pt at)
- (match* (pt at)
- [('Integer 'Integer) env] [('Boolean 'Boolean) env]
- [('Void 'Void) env] [('Any 'Any) env]
- [(`(Vector ,pts ...) `(Vector ,ats ...))
- (for/fold ([env^ env]) ([pt1 pts] [at1 ats])
- (match-types env^ pt1 at1))]
- [(`(,pts ... -> ,prt) `(,ats ... -> ,art))
- (define env^ (match-types env prt art))
- (for/fold ([env^^ env^]) ([pt1 pts] [at1 ats])
- (match-types env^^ pt1 at1))]
- [(`(All ,pxs ,pt1) `(All ,axs ,at1))
- (define env^ (append (map cons pxs axs) env))
- (match-types env^ pt1 at1)]
- [((? symbol? x) at)
- (match (dict-ref env x (lambda () #f))
- [#f (error 'type-check "undefined type variable ~a" x)]
- ['Type (cons (cons x at) env)]
- [t^ (check-type-equal? at t^ 'matching) env])]
- [(other wise) (error 'type-check "mismatch ~a != a" pt at)]))
- (define/public (subst-type env pt)
- (match pt
- ['Integer 'Integer] ['Boolean 'Boolean]
- ['Void 'Void] ['Any 'Any]
- [`(Vector ,ts ...)
- `(Vector ,@(for/list ([t ts]) (subst-type env t)))]
- [`(,ts ... -> ,rt)
- `(,@(for/list ([t ts]) (subst-type env t)) -> ,(subst-type env rt))]
- [`(All ,xs ,t)
- `(All ,xs ,(subst-type (append (map cons xs xs) env) t))]
- [(? symbol? x) (dict-ref env x)]
- [else (error 'type-check "expected a type not ~a" pt)]))
- (define/public (combine-decls-defs ds)
- (match ds
- ['() '()]
- [`(,(Decl name type) . (,(Def f params _ info body) . ,ds^))
- (unless (equal? name f)
- (error 'type-check "name mismatch, ~a != ~a" name f))
- (match type
- [`(All ,xs (,ps ... -> ,rt))
- (define params^ (for/list ([x params] [T ps]) `[,x : ,T]))
- (cons (Generic xs (Def name params^ rt info body))
- (combine-decls-defs ds^))]
- [`(,ps ... -> ,rt)
- (define params^ (for/list ([x params] [T ps]) `[,x : ,T]))
- (cons (Def name params^ rt info body) (combine-decls-defs ds^))]
- [else (error 'type-check "expected a function type, not ~a" type) ])]
- [`(,(Def f params rt info body) . ,ds^)
- (cons (Def f params rt info body) (combine-decls-defs ds^))]))
- \end{lstlisting}
- \caption{Auxiliary functions for type checking \LangPoly{}.}
- \label{fig:type-check-Lvar0-aux}
- \end{figure}
- \begin{figure}[tbp]
- \begin{lstlisting}%[basicstyle=\ttfamily\scriptsize]
- (define/public ((check-well-formed env) ty)
- (match ty
- ['Integer (void)]
- ['Boolean (void)]
- ['Void (void)]
- [(? symbol? a)
- (match (dict-ref env a (lambda () #f))
- ['Type (void)]
- [else (error 'type-check "undefined type variable ~a" a)])]
- [`(Vector ,ts ...)
- (for ([t ts]) ((check-well-formed env) t))]
- [`(,ts ... -> ,t)
- (for ([t ts]) ((check-well-formed env) t))
- ((check-well-formed env) t)]
- [`(All ,xs ,t)
- (define env^ (append (for/list ([x xs]) (cons x 'Type)) env))
- ((check-well-formed env^) t)]
- [else (error 'type-check "unrecognized type ~a" ty)]))
- \end{lstlisting}
- \caption{Well-formed types.}
- \label{fig:well-formed-types}
- \end{figure}
- % TODO: interpreter for R'_10
- \section{Compiling Polymorphism}
- \label{sec:compiling-poly}
- Broadly speaking, there are four approaches to compiling parametric
- polymorphism, which we describe below.
- \begin{description}
- \item[Monomorphization] generates a different version of a polymorphic
- function for each set of type arguments that it is used with,
- producing type-specialized code. This approach results in the most
- efficient code but requires whole-program compilation (no separate
- compilation) and increases code size. For our current purposes
- monomorphization is a non-starter because, with first-class
- polymorphism, it is sometimes not possible to determine which
- generic functions are used with which type arguments during
- compilation. (It can be done at runtime, with just-in-time
- compilation.) This approach is used to compile C++
- templates~\citep{stroustrup88:_param_types} and polymorphic
- functions in NESL~\citep{Blelloch:1993aa} and
- ML~\citep{Weeks:2006aa}.
-
- \item[Uniform representation] generates one version of each
- polymorphic function but requires all values have a common ``boxed''
- format, such as the tagged values of type \code{Any} in
- \LangAny{}. Non-polymorphic code (i.e. monomorphic code) is compiled
- similarly to code in a dynamically typed language (like \LangDyn{}),
- in which primitive operators require their arguments to be projected
- from \code{Any} and their results are injected into \code{Any}. (In
- object-oriented languages, the projection is accomplished via
- virtual method dispatch.) The uniform representation approach is
- compatible with separate compilation and with first-class
- polymorphism. However, it produces the least-efficient code because
- it introduces overhead in the entire program, including
- non-polymorphic code. This approach is used in implementations of
- CLU~\cite{liskov79:_clu_ref,Liskov:1993dk},
- ML~\citep{Cardelli:1984aa,Appel:1987aa}, and
- Java~\citep{Bracha:1998fk}.
-
- \item[Mixed representation] generates one version of each polymorphic
- function, using a boxed representation for type
- variables. Monomorphic code is compiled as usual (as in \LangLoop{})
- and conversions are performed at the boundaries between monomorphic
- and polymorphic (e.g. when a polymorphic function is instantiated
- and called). This approach is compatible with separate compilation
- and first-class polymorphism and maintains the efficiency of
- monomorphic code. The tradeoff is increased overhead at the boundary
- between monomorphic and polymorphic code. This approach is used in
- implementations of ML~\citep{Leroy:1992qb} and Java, starting in
- Java 5 with the addition of autoboxing.
-
- \item[Type passing] uses the unboxed representation in both
- monomorphic and polymorphic code. Each polymorphic function is
- compiled to a single function with extra parameters that describe
- the type arguments. The type information is used by the generated
- code to know how to access the unboxed values at runtime. This
- approach is used in implementation of the Napier88
- language~\citep{Morrison:1991aa} and ML~\citep{Harper:1995um}. Type
- passing is compatible with separate compilation and first-class
- polymorphism and maintains the efficiency for monomorphic
- code. There is runtime overhead in polymorphic code from dispatching
- on type information.
- \end{description}
- In this chapter we use the mixed representation approach, partly
- because of its favorable attributes, and partly because it is
- straightforward to implement using the tools that we have already
- built to support gradual typing. To compile polymorphic functions, we
- add just one new pass, \code{erase-types}, to compile \LangInst{} to
- \LangCast{}.
- \section{Erase Types}
- \label{sec:erase-types}
- We use the \code{Any} type from Chapter~\ref{ch:Rdyn} to
- represent type variables. For example, Figure~\ref{fig:map-vec-erase}
- shows the output of the \code{erase-types} pass on the polymorphic
- \code{map-vec} (Figure~\ref{fig:map-vec-poly}). The occurrences of
- type parameter \code{a} are replaced by \code{Any} and the polymorphic
- \code{All} types are removed from the type of \code{map-vec}.
- \begin{figure}[tbp]
- \begin{lstlisting}
- (define (map-vec [f : (Any -> Any)] [v : (Vector Any Any)])
- : (Vector Any Any)
- (vector (f (vector-ref v 0)) (f (vector-ref v 1))))
- (define (add1 [x : Integer]) : Integer (+ x 1))
- (vector-ref ((cast map-vec
- ((Any -> Any) (Vector Any Any) -> (Vector Any Any))
- ((Integer -> Integer) (Vector Integer Integer)
- -> (Vector Integer Integer)))
- add1 (vector 0 41)) 1)
- \end{lstlisting}
- \caption{The polymorphic \code{map-vec} example after type erasure.}
- \label{fig:map-vec-erase}
- \end{figure}
- This process of type erasure creates a challenge at points of
- instantiation. For example, consider the instantiation of
- \code{map-vec} in Figure~\ref{fig:map-vec-type-check}.
- The type of \code{map-vec} is
- \begin{lstlisting}
- (All (a) ((a -> a) (Vector a a) -> (Vector a a)))
- \end{lstlisting}
- and it is instantiated to
- \begin{lstlisting}
- ((Integer -> Integer) (Vector Integer Integer)
- -> (Vector Integer Integer))
- \end{lstlisting}
- After erasure, the type of \code{map-vec} is
- \begin{lstlisting}
- ((Any -> Any) (Vector Any Any) -> (Vector Any Any))
- \end{lstlisting}
- but we need to convert it to the instantiated type. This is easy to
- do in the target language \LangCast{} with a single \code{cast}. In
- Figure~\ref{fig:map-vec-erase}, the instantiation of \code{map-vec}
- has been compiled to a \code{cast} from the type of \code{map-vec} to
- the instantiated type. The source and target type of a cast must be
- consistent (Figure~\ref{fig:consistent}), which indeed is the case
- because both the source and target are obtained from the same
- polymorphic type of \code{map-vec}, replacing the type parameters with
- \code{Any} in the former and with the deduced type arguments in the
- later. (Recall that the \code{Any} type is consistent with any type.)
- To implement the \code{erase-types} pass, we recommend defining a
- recursive auxiliary function named \code{erase-type} that applies the
- following two transformations. It replaces type variables with
- \code{Any}
- \begin{lstlisting}
- |$x$|
- |$\Rightarrow$|
- Any
- \end{lstlisting}
- and it removes the polymorphic \code{All} types.
- \begin{lstlisting}
- (All |$xs$| |$T_1$|)
- |$\Rightarrow$|
- |$T'_1$|
- \end{lstlisting}
- Apply the \code{erase-type} function to all of the type annotations in
- the program.
- Regarding the translation of expressions, the case for \code{Inst} is
- the interesting one. We translate it into a \code{Cast}, as shown
- below. The type of the subexpression $e$ is the polymorphic type
- $\LP\key{All} xs T\RP$. The source type of the cast is the erasure of
- $T$, the type $T'$. The target type $T''$ is the result of
- substituting the arguments types $ts$ for the type parameters $xs$ in
- $T$ followed by doing type erasure.
- \begin{lstlisting}
- (Inst |$e$| (All |$xs$| |$T$|) |$ts$|)
- |$\Rightarrow$|
- (Cast |$e'$| |$T'$| |$T''$|)
- \end{lstlisting}
- where $T'' = \LP\code{erase-type}~\LP\code{subst-type}~s~T\RP\RP$
- and $s = \LP\code{map}~\code{cons}~xs~ts\RP$.
- Finally, each polymorphic function is translated to a regular
- functions in which type erasure has been applied to all the type
- annotations and the body.
- \begin{lstlisting}
- (Poly |$ts$| (Def |$f$| ([|$x_1$| : |$T_1$|] |$\ldots$|) |$T_r$| |$\itm{info}$| |$e$|))
- |$\Rightarrow$|
- (Def |$f$| ([|$x_1$| : |$T'_1$|] |$\ldots$|) |$T'_r$| |$\itm{info}$| |$e'$|)
- \end{lstlisting}
- \begin{exercise}\normalfont
- Implement a compiler for the polymorphic language \LangPoly{} by
- extending and adapting your compiler for \LangGrad{}. Create 6 new test
- programs that use polymorphic functions. Some of them should make
- use of first-class polymorphism.
- \end{exercise}
- \begin{figure}[p]
- \begin{tikzpicture}[baseline=(current bounding box.center)]
- \node (Rpoly) at (9,4) {\large \LangPoly{}};
- \node (Rpolyp) at (6,4) {\large \LangInst{}};
- \node (Rgradualp) at (3,4) {\large \LangCast{}};
- \node (Rwhilepp) at (0,4) {\large \LangProxy{}};
- \node (Rwhileproxy) at (0,2) {\large \LangPVec{}};
- \node (Rwhileproxy-2) at (3,2) {\large \LangPVec{}};
- \node (Rwhileproxy-3) at (6,2) {\large \LangPVec{}};
- \node (Rwhileproxy-4) at (9,2) {\large \LangPVecFunRef{}};
- \node (Rwhileproxy-5) at (12,2) {\large \LangPVecFunRef{}};
- \node (F1-1) at (12,0) {\large \LangPVecFunRef{}};
- \node (F1-2) at (9,0) {\large \LangPVecFunRef{}};
- \node (F1-3) at (6,0) {\large \LangPVecFunRef{}};
- \node (F1-4) at (3,0) {\large \LangPVecAlloc{}};
- \node (F1-5) at (0,0) {\large \LangPVecAlloc{}};
- \node (C3-2) at (3,-2) {\large \LangCLoopPVec{}};
- \node (x86-2) at (3,-4) {\large \LangXIndCallVar{}};
- \node (x86-2-1) at (3,-6) {\large \LangXIndCallVar{}};
- \node (x86-2-2) at (6,-6) {\large \LangXIndCallVar{}};
- \node (x86-3) at (6,-4) {\large \LangXIndCallVar{}};
- \node (x86-4) at (9,-4) {\large \LangXIndCall{}};
- \node (x86-5) at (9,-6) {\large \LangXIndCall{}};
- \path[->,bend right=15] (Rpoly) edge [above] node
- {\ttfamily\footnotesize type\_check} (Rpolyp);
- \path[->,bend right=15] (Rpolyp) edge [above] node
- {\ttfamily\footnotesize erase\_types} (Rgradualp);
- \path[->,bend right=15] (Rgradualp) edge [above] node
- {\ttfamily\footnotesize lower\_casts} (Rwhilepp);
- \path[->,bend right=15] (Rwhilepp) edge [right] node
- {\ttfamily\footnotesize differentiate\_proxies} (Rwhileproxy);
- \path[->,bend left=15] (Rwhileproxy) edge [above] node
- {\ttfamily\footnotesize shrink} (Rwhileproxy-2);
- \path[->,bend left=15] (Rwhileproxy-2) edge [above] node
- {\ttfamily\footnotesize uniquify} (Rwhileproxy-3);
- \path[->,bend left=15] (Rwhileproxy-3) edge [above] node
- {\ttfamily\footnotesize reveal\_functions} (Rwhileproxy-4);
- \path[->,bend left=15] (Rwhileproxy-4) edge [above] node
- {\ttfamily\footnotesize reveal\_casts} (Rwhileproxy-5);
- \path[->,bend left=15] (Rwhileproxy-5) edge [left] node
- {\ttfamily\footnotesize convert\_assignments} (F1-1);
- \path[->,bend left=15] (F1-1) edge [below] node
- {\ttfamily\footnotesize convert\_to\_clos.} (F1-2);
- \path[->,bend right=15] (F1-2) edge [above] node
- {\ttfamily\footnotesize limit\_fun.} (F1-3);
- \path[->,bend right=15] (F1-3) edge [above] node
- {\ttfamily\footnotesize expose\_alloc.} (F1-4);
- \path[->,bend right=15] (F1-4) edge [above] node
- {\ttfamily\footnotesize remove\_complex.} (F1-5);
- \path[->,bend right=15] (F1-5) edge [right] node
- {\ttfamily\footnotesize explicate\_control} (C3-2);
- \path[->,bend left=15] (C3-2) edge [left] node
- {\ttfamily\footnotesize select\_instr.} (x86-2);
- \path[->,bend right=15] (x86-2) edge [left] node
- {\ttfamily\footnotesize uncover\_live} (x86-2-1);
- \path[->,bend right=15] (x86-2-1) edge [below] node
- {\ttfamily\footnotesize build\_inter.} (x86-2-2);
- \path[->,bend right=15] (x86-2-2) edge [left] node
- {\ttfamily\footnotesize allocate\_reg.} (x86-3);
- \path[->,bend left=15] (x86-3) edge [above] node
- {\ttfamily\footnotesize patch\_instr.} (x86-4);
- \path[->,bend left=15] (x86-4) edge [right] node {\ttfamily\footnotesize print\_x86} (x86-5);
- \end{tikzpicture}
- \caption{Diagram of the passes for \LangPoly{} (parametric polymorphism).}
- \label{fig:Rpoly-passes}
- \end{figure}
- Figure~\ref{fig:Rpoly-passes} provides an overview of all the passes needed
- for the compilation of \LangPoly{}.
- % TODO: challenge problem: specialization of instantiations
- % Further Reading
- \fi
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- \clearpage
- \appendix
- \chapter{Appendix}
- \if\edition\racketEd
- \section{Interpreters}
- \label{appendix:interp}
- \index{subject}{interpreter}
- We provide interpreters for each of the source languages \LangInt{},
- \LangVar{}, $\ldots$ in the files \code{interp\_Lint.rkt},
- \code{interp-Lvar.rkt}, etc. The interpreters for the intermediate
- languages \LangCVar{} and \LangCIf{} are in \code{interp-Cvar.rkt} and
- \code{interp-C1.rkt}. The interpreters for \LangCVec{}, \LangCFun{}, pseudo-x86,
- and x86 are in the \key{interp.rkt} file.
- \section{Utility Functions}
- \label{appendix:utilities}
- The utility functions described in this section are in the
- \key{utilities.rkt} file of the support code.
- \paragraph{\code{interp-tests}}
- The \key{interp-tests} function runs the compiler passes and the
- interpreters on each of the specified tests to check whether each pass
- is correct. The \key{interp-tests} function has the following
- parameters:
- \begin{description}
- \item[name (a string)] a name to identify the compiler,
- \item[typechecker] a function of exactly one argument that either
- raises an error using the \code{error} function when it encounters a
- type error, or returns \code{\#f} when it encounters a type
- error. If there is no type error, the type checker returns the
- program.
- \item[passes] a list with one entry per pass. An entry is a list with
- four things:
- \begin{enumerate}
- \item a string giving the name of the pass,
- \item the function that implements the pass (a translator from AST
- to AST),
- \item a function that implements the interpreter (a function from
- AST to result value) for the output language,
- \item and a type checker for the output language. Type checkers for
- the $R$ and $C$ languages are provided in the support code. For
- example, the type checkers for \LangVar{} and \LangCVar{} are in
- \code{type-check-Lvar.rkt} and \code{type-check-Cvar.rkt}. The
- type checker entry is optional. The support code does not provide
- type checkers for the x86 languages.
- \end{enumerate}
- \item[source-interp] an interpreter for the source language. The
- interpreters from Appendix~\ref{appendix:interp} make a good choice.
-
- \item[test-family (a string)] for example, \code{"r1"}, \code{"r2"}, etc.
- \item[tests] a list of test numbers that specifies which tests to
- run. (see below)
- \end{description}
- %
- The \key{interp-tests} function assumes that the subdirectory
- \key{tests} has a collection of Racket programs whose names all start
- with the family name, followed by an underscore and then the test
- number, ending with the file extension \key{.rkt}. Also, for each test
- program that calls \code{read} one or more times, there is a file with
- the same name except that the file extension is \key{.in} that
- provides the input for the Racket program. If the test program is
- expected to fail type checking, then there should be an empty file of
- the same name but with extension \key{.tyerr}.
- \paragraph{\code{compiler-tests}}
- runs the compiler passes to generate x86 (a \key{.s} file) and then
- runs the GNU C compiler (gcc) to generate machine code. It runs the
- machine code and checks that the output is $42$. The parameters to the
- \code{compiler-tests} function are similar to those of the
- \code{interp-tests} function, and consist of
- \begin{itemize}
- \item a compiler name (a string),
- \item a type checker,
- \item description of the passes,
- \item name of a test-family, and
- \item a list of test numbers.
- \end{itemize}
- \paragraph{\code{compile-file}}
- takes a description of the compiler passes (see the comment for
- \key{interp-tests}) and returns a function that, given a program file
- name (a string ending in \key{.rkt}), applies all of the passes and
- writes the output to a file whose name is the same as the program file
- name but with \key{.rkt} replaced with \key{.s}.
- \paragraph{\code{read-program}}
- takes a file path and parses that file (it must be a Racket program)
- into an abstract syntax tree.
- \paragraph{\code{parse-program}}
- takes an S-expression representation of an abstract syntax tree and converts it into
- the struct-based representation.
- \paragraph{\code{assert}}
- takes two parameters, a string (\code{msg}) and Boolean (\code{bool}),
- and displays the message \key{msg} if the Boolean \key{bool} is false.
- \paragraph{\code{lookup}}
- % remove discussion of lookup? -Jeremy
- takes a key and an alist, and returns the first value that is
- associated with the given key, if there is one. If not, an error is
- triggered. The alist may contain both immutable pairs (built with
- \key{cons}) and mutable pairs (built with \key{mcons}).
- %The \key{map2} function ...
- \fi %\racketEd
- \section{x86 Instruction Set Quick-Reference}
- \label{sec:x86-quick-reference}
- \index{subject}{x86}
- Table~\ref{tab:x86-instr} lists some x86 instructions and what they
- do. We write $A \to B$ to mean that the value of $A$ is written into
- location $B$. Address offsets are given in bytes. The instruction
- arguments $A, B, C$ can be immediate constants (such as \code{\$4}),
- registers (such as \code{\%rax}), or memory references (such as
- \code{-4(\%ebp)}). Most x86 instructions only allow at most one memory
- reference per instruction. Other operands must be immediates or
- registers.
- \begin{table}[tbp]
- \centering
- \begin{tabular}{l|l}
- \textbf{Instruction} & \textbf{Operation} \\ \hline
- \texttt{addq} $A$, $B$ & $A + B \to B$\\
- \texttt{negq} $A$ & $- A \to A$ \\
- \texttt{subq} $A$, $B$ & $B - A \to B$\\
- \texttt{imulq} $A$, $B$ & $A \times B \to B$\\
- \texttt{callq} $L$ & Pushes the return address and jumps to label $L$ \\
- \texttt{callq} \texttt{*}$A$ & Calls the function at the address $A$. \\
- %\texttt{leave} & $\texttt{ebp} \to \texttt{esp};$ \texttt{popl \%ebp} \\
- \texttt{retq} & Pops the return address and jumps to it \\
- \texttt{popq} $A$ & $*\mathtt{rsp} \to A; \mathtt{rsp} + 8 \to \mathtt{rsp}$ \\
- \texttt{pushq} $A$ & $\texttt{rsp} - 8 \to \texttt{rsp}; A \to *\texttt{rsp}$\\
- \texttt{leaq} $A$,$B$ & $A \to B$ ($B$ must be a register) \\
- \texttt{cmpq} $A$, $B$ & compare $A$ and $B$ and set the flag register ($B$ must not
- be an immediate) \\
- \texttt{je} $L$ & \multirow{5}{3.7in}{Jump to label $L$ if the flag register
- matches the condition code of the instruction, otherwise go to the
- next instructions. The condition codes are \key{e} for ``equal'',
- \key{l} for ``less'', \key{le} for ``less or equal'', \key{g}
- for ``greater'', and \key{ge} for ``greater or equal''.} \\
- \texttt{jl} $L$ & \\
- \texttt{jle} $L$ & \\
- \texttt{jg} $L$ & \\
- \texttt{jge} $L$ & \\
- \texttt{jmp} $L$ & Jump to label $L$ \\
- \texttt{movq} $A$, $B$ & $A \to B$ \\
- \texttt{movzbq} $A$, $B$ &
- \multirow{3}{3.7in}{$A \to B$, \text{where } $A$ is a single-byte register
- (e.g., \texttt{al} or \texttt{cl}), $B$ is a 8-byte register,
- and the extra bytes of $B$ are set to zero.} \\
- & \\
- & \\
- \texttt{notq} $A$ & $\sim A \to A$ \qquad (bitwise complement)\\
- \texttt{orq} $A$, $B$ & $A | B \to B$ \qquad (bitwise-or)\\
- \texttt{andq} $A$, $B$ & $A \& B \to B$ \qquad (bitwise-and)\\
- \texttt{salq} $A$, $B$ & $B$ \texttt{<<} $A \to B$ (arithmetic shift left, where $A$ is a constant)\\
- \texttt{sarq} $A$, $B$ & $B$ \texttt{>>} $A \to B$ (arithmetic shift right, where $A$ is a constant)\\
- \texttt{sete} $A$ & \multirow{5}{3.7in}{If the flag matches the condition code,
- then $1 \to A$, else $0 \to A$. Refer to \texttt{je} above for the
- description of the condition codes. $A$ must be a single byte register
- (e.g., \texttt{al} or \texttt{cl}).} \\
- \texttt{setl} $A$ & \\
- \texttt{setle} $A$ & \\
- \texttt{setg} $A$ & \\
- \texttt{setge} $A$ &
- \end{tabular}
- \vspace{5pt}
- \caption{Quick-reference for the x86 instructions used in this book.}
- \label{tab:x86-instr}
- \end{table}
- \if\edition\racketEd
- \cleardoublepage
- \section{Concrete Syntax for Intermediate Languages}
- The concrete syntax of \LangAny{} is defined in
- Figure~\ref{fig:Rany-concrete-syntax}.
- \begin{figure}[tp]
- \centering
- \fbox{
- \begin{minipage}{0.97\textwidth}\small
- \[
- \begin{array}{lcl}
- \Type &::=& \gray{\key{Integer} \MID \key{Boolean}
- \MID \LP\key{Vector}\;\Type\ldots\RP \MID \key{Void}} \\
- &\MID& \gray{\LP\Type\ldots \; \key{->}\; \Type\RP} \MID \key{Any} \\
- \FType &::=& \key{Integer} \MID \key{Boolean} \MID \key{Void}
- \MID \LP\key{Vector}\; \key{Any}\ldots\RP \\
- &\MID& \LP\key{Any}\ldots \; \key{->}\; \key{Any}\RP\\
- \Exp &::=& \ldots \CINJECT{\Exp}{\FType}\RP \MID \CPROJECT{\Exp}{\FType}\\
- &\MID& \LP\key{any-vector-length}\;\Exp\RP
- \MID \LP\key{any-vector-ref}\;\Exp\;\Exp\RP \\
- &\MID& \LP\key{any-vector-set!}\;\Exp\;\Exp\;\Exp\RP\\
- &\MID& \LP\key{boolean?}\;\Exp\RP \MID \LP\key{integer?}\;\Exp\RP
- \MID \LP\key{void?}\;\Exp\RP \\
- &\MID& \LP\key{vector?}\;\Exp\RP \MID \LP\key{procedure?}\;\Exp\RP \\
- \Def &::=& \gray{ \CDEF{\Var}{\LS\Var \key{:} \Type\RS\ldots}{\Type}{\Exp} } \\
- \LangAnyM{} &::=& \gray{\Def\ldots \; \Exp}
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The concrete syntax of \LangAny{}, extending \LangLam{}
- (Figure~\ref{fig:Rlam-syntax}).}
- \label{fig:Rany-concrete-syntax}
- \end{figure}
- The concrete syntax for \LangCVar{}, \LangCIf{}, \LangCVec{} and \LangCFun{} is
- defined in Figures~\ref{fig:c0-concrete-syntax},
- \ref{fig:c1-concrete-syntax}, \ref{fig:c2-concrete-syntax},
- and \ref{fig:c3-concrete-syntax}, respectively.
- \begin{figure}[tbp]
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Atm &::=& \gray{ \Int \MID \Var \MID \itm{bool} } \\
- \itm{cmp} &::= & \gray{ \key{eq?} \MID \key{<} } \\
- \Exp &::=& \gray{ \Atm \MID \key{(read)} \MID \key{(-}~\Atm\key{)} \MID \key{(+}~\Atm~\Atm\key{)} } \\
- &\MID& \gray{ \LP \key{not}~\Atm \RP \MID \LP \itm{cmp}~\Atm~\Atm\RP } \\
- &\MID& \LP \key{allocate}~\Int~\Type \RP \\
- &\MID& (\key{vector-ref}\;\Atm\;\Int) \MID (\key{vector-set!}\;\Atm\;\Int\;\Atm)\\
- &\MID& \LP \key{global-value}~\Var \RP \MID \LP \key{void} \RP \\
- \Stmt &::=& \gray{ \Var~\key{=}~\Exp\key{;} } \MID \LP\key{collect}~\Int \RP\\
- \Tail &::= & \gray{ \key{return}~\Exp\key{;} \MID \Stmt~\Tail }
- \MID \gray{ \key{goto}~\itm{label}\key{;} }\\
- &\MID& \gray{ \key{if}~\LP \itm{cmp}~\Atm~\Atm \RP~ \key{goto}~\itm{label}\key{;} ~\key{else}~\key{goto}~\itm{label}\key{;} } \\
- \LangCVecM{} & ::= & \gray{ (\itm{label}\key{:}~ \Tail)\ldots }
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The concrete syntax of the \LangCVec{} intermediate language.}
- \label{fig:c2-concrete-syntax}
- \end{figure}
- \begin{figure}[tp]
- \fbox{
- \begin{minipage}{0.96\textwidth}
- \small
- \[
- \begin{array}{lcl}
- \Atm &::=& \gray{ \Int \MID \Var \MID \key{\#t} \MID \key{\#f} }
- \\
- \itm{cmp} &::= & \gray{ \key{eq?} \MID \key{<} } \\
- \Exp &::= & \gray{ \Atm \MID \LP\key{read}\RP \MID \LP\key{-}\;\Atm\RP \MID \LP\key{+} \; \Atm\;\Atm\RP
- \MID \LP\key{not}\;\Atm\RP \MID \LP\itm{cmp}\;\Atm\;\Atm\RP } \\
- &\MID& \gray{ \LP\key{allocate}\,\Int\,\Type\RP
- \MID \LP\key{vector-ref}\, \Atm\, \Int\RP } \\
- &\MID& \gray{ \LP\key{vector-set!}\,\Atm\,\Int\,\Atm\RP \MID \LP\key{global-value} \,\itm{name}\RP \MID \LP\key{void}\RP } \\
- &\MID& \LP\key{fun-ref}~\itm{label}\RP \MID \LP\key{call} \,\Atm\,\Atm\ldots\RP \\
- \Stmt &::=& \gray{ \ASSIGN{\Var}{\Exp} \MID \RETURN{\Exp}
- \MID \LP\key{collect} \,\itm{int}\RP }\\
- \Tail &::= & \gray{\RETURN{\Exp} \MID \LP\key{seq}\;\Stmt\;\Tail\RP} \\
- &\MID& \gray{\LP\key{goto}\,\itm{label}\RP
- \MID \IF{\LP\itm{cmp}\, \Atm\,\Atm\RP}{\LP\key{goto}\,\itm{label}\RP}{\LP\key{goto}\,\itm{label}\RP}} \\
- &\MID& \LP\key{tail-call}\,\Atm\,\Atm\ldots\RP \\
- \Def &::=& \LP\key{define}\; \LP\itm{label} \; [\Var \key{:} \Type]\ldots\RP \key{:} \Type \; \LP\LP\itm{label}\,\key{.}\,\Tail\RP\ldots\RP\RP \\
- \LangCFunM{} & ::= & \Def\ldots
- \end{array}
- \]
- \end{minipage}
- }
- \caption{The \LangCFun{} language, extending \LangCVec{} (Figure~\ref{fig:c2-concrete-syntax}) with functions.}
- \label{fig:c3-concrete-syntax}
- \end{figure}
- \fi % racketEd
- \backmatter
- \addtocontents{toc}{\vspace{11pt}}
- %% \addtocontents{toc}{\vspace{11pt}}
- %% \nocite{*} is a way to get all the entries in the .bib file to print in the bibliography:
- \nocite{*}\let\bibname\refname
- \addcontentsline{toc}{fmbm}{\refname}
- \printbibliography
- \printindex{authors}{Author Index}
- \printindex{subject}{Subject Index}
- \end{document}
- % LocalWords: Nano Siek CC NC ISBN wonks wizardry Backus nanopasses
- % LocalWords: dataflow nx generics autoboxing Hulman Ch CO Dybvig aa
- % LocalWords: Abelson uq Felleisen Flatt Lutz vp vj Sweigart vn Matz
- % LocalWords: Matthes github gcc MacOS Chez Friedman's Dipanwita fk
- % LocalWords: Sarkar Dybvig's Abdulaziz Ghuloum bh IU Factora Bor qf
- % LocalWords: Cameron Kuhlenschmidt Vollmer Vitousek Yuh Nystrom AST
- % LocalWords: Tolmach Wollowski ASTs Aho ast struct int backquote op
- % LocalWords: args neg def init UnaryOp USub func BinOp Naur BNF rkt
- % LocalWords: fixnum datatype structure's arith exp stmt Num Expr tr
- % LocalWords: plt PSF ref CPython cpython reynolds interp cond fx pe
- % LocalWords: arg Hitchhiker's TODO nullary Lvar Lif cnd thn var sam
- % LocalWords: IfExp Bool InterpLvar InterpLif InterpRVar alist jane
- % LocalWords: basicstyle kate dict alists env stmts ss len lhs globl
- % LocalWords: rsp rbp rax rbx rcx rdx rsi rdi movq retq callq jmp es
- % LocalWords: pushq subq popq negq addq arity uniquify Cvar instr cg
- % LocalWords: Seq CProgram gensym lib Fprivate Flist tmp ANF Danvy
- % LocalWords: rco Flists py rhs unhandled cont immediates lstlisting
- % LocalWords: numberstyle Cormen Sudoku Balakrishnan ve aka DSATUR
- % LocalWords: Brelaz eu Gebremedhin Omari deletekeywords min JGS
- % LocalWords: morekeywords fullflexible
|