i86comp.red 159 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695
  1. % "i86comp.red" Copyright 1991-1997, Codemist Ltd
  2. %
  3. % Compiler that turns Lisp code into Intel 80x86 32-bit assembler in a way
  4. % that fits in with the conventions used with CSL/CCL
  5. %
  6. % It is hoped that parts of this compoiler will form a framework upon
  7. % which native compilers for other architectures can be built. Even with
  8. % just the Intel one there are three different sets of register and calling
  9. % conventions I would like to support (!), viz
  10. % Watcom C 11.0 register based calling
  11. % Microsoft Visual C++ 5.0 fast calling
  12. % Linux/GCC for Intel architectures
  13. % This incoherence is amazing and horrid!
  14. %
  15. % The rules for these configurations appear to be as follows, but
  16. % astonishing though it may seem I have found it amazingly difficult to
  17. % find these rules documented. Certainly Microsoft explicitly indicate
  18. % that the register-usage for their __fastcall linkage may vary between
  19. % releases of their C compiler. Explanations of where to place arguments
  20. % are tolerably well explained, but the statement of what registers may be
  21. % corrupted and which must be preserved is buried somewhere...
  22. %
  23. %
  24. % register (a) (b) (c)
  25. %
  26. % EAX result arg1/result result
  27. % EBX preserved arg3 or preserved preserved
  28. % ECX scratch arg4 or preserved arg1 or scratch
  29. % EDX scratch arg2 or preserved arg2 or scratch
  30. % EBP preserved preserved preserved
  31. % ESI preserved preserved preserved
  32. % EDI preserved preserved preserved
  33. % ESP stack stack stack
  34. %
  35. % (a) Linux/GCC all functions, Watcom and MSVC __cdecl and va_args cases
  36. % (b) Watcom "/r5" register-based calling
  37. % (c) MSVC __fastcall
  38. %
  39. %
  40. % M A Dmitriev
  41. % A C Norman
  42. global '(i_machine);
  43. i_machine := cdr assoc('native, lispsystem!*);
  44. % i_machine = 2 Watcom 11.0
  45. % = 3 MS VC++ 5.0
  46. % = 4 Linux
  47. % otherwise something not supported here.
  48. if not (i_machine=2 or i_machine=3 or i_machine=4) then
  49. error(0, "Unsupported architecture for this compiler");
  50. %
  51. % Assembler for use when generating native code within CSL/CCL. The
  52. % overall structure of this code is intende to be fairly independent of
  53. % the actual machine architecture supported, and there will be call-backs
  54. % into particular code-generators when system sensitive operations have
  55. % to be performed.
  56. %
  57. %
  58. % This low-level assembler is activated using a procedural interface.
  59. % To create some native code the correct sequence to use is:
  60. % i_startproc(); set things going
  61. % for each basic block do
  62. % i_putlabel lab;
  63. % for each instruction in the block do
  64. % i_putcomment '(disassembly of the instrn);
  65. % mixture of
  66. % i_putbyte 8-bits
  67. % i_put32 32-bits Intel byte-order
  68. % i_extern <data> 32-bit ref to external symbol
  69. % i_putjump(data, lab) variable length jump instruction
  70. % i_resolve(); resolve labels
  71. %
  72. % There is a put32r to insert bytes in Sun rather than Intel byte order,
  73. % and put16, put16r calls for 16-bit values.
  74. %
  75. % To go with this assembler there must be machine-specific procedures
  76. % to decode the jump stuff:
  77. % i_jumpsize(pc, target, data)
  78. % i_jumpbytes(pc, target, data)
  79. % where i_jumpsize MUST return a list whose length is the same as
  80. % the value of i_jumpsize. The data handed down is whatever was passed to
  81. % i_putjump, and it can be as complicated a structure as the architecture
  82. % needs.
  83. %
  84. % put_extern takes an argument that one of the following, the meaning of
  85. % which are explained later:
  86. % (absolute xxx)
  87. % (relative xxx)
  88. % (rel_plus_4 xxx)
  89. % (rel_minus_2 xxx)
  90. % (rel_minus_4 xxx)
  91. % (rel_offset xxx n)
  92. %
  93. % where xxx can be one of the following possibilities:
  94. % a negative integer -(n+1) n is used to look up in a useful_functions
  95. % table (in file fns3.c of the CSL sources)
  96. % a positive integer n address_of_variable (from fns3.c) will be
  97. % called with n as an argument
  98. % (n 0) entry n from zero_arg_functions (eval4.c)
  99. % (n 1) entry n from one_arg_functions
  100. % (n 2) entry n from two_arg_functions
  101. % (n 3) entry n from three_arg_functions
  102. % and the code in restart.c will need to agree with the layout created
  103. % here for relocation modes that link to these entities.
  104. %
  105. % All the addressing modes (at present) generate a 32 bit reference. The
  106. % simplest one is ABSOLUTE which just puts the address of the target
  107. % in the 32 bit location. The other modes all insert an adddress of the
  108. % target relative to the current location. The complication is that some
  109. % computers want this to be relative to the start of the 32-bit address,
  110. % some relative to the start of the instruction containing that address and
  111. % some use the start of the NEXT instruction as the base. I use plain
  112. % RELATIVE for relocation from the start address of the value being
  113. % stored. REL_PLUS_4 is relative to the word after this (ie +4). REL_MINUS_2
  114. % and REL_MINUS_4 are expected to be useful if you need to be relative to the
  115. % start of an instruction which has 2 or 4 bytes before the 32-bit offset.
  116. % Finally REL_OFFSET is a catch-all that puts an extra signed byte in the
  117. % relocation table to show the offset from the effect of just RELATIVE.
  118. % In general I expect any particular computer to use just one of these,
  119. % for instance Intel use REL_PLUS_4, but the others are there to make it
  120. % easy to implement many different compiler back-ends. I have room in the
  121. % encoding to add several more modes if and when necessary!
  122. %
  123. %
  124. % Of course for any particular computer architecture I will have a
  125. % higher level assembler that accepts input in a fairly symbolic form
  126. % and converts it into the bit-patterns required here.
  127. %
  128. % A procedure is accumulated as a sequence of blocks. Each of these
  129. % has an associated label, which will be a gensym if no user label was
  130. % provided. Jump instructions only occur at the end of one of these
  131. % blocks. When a block is complete it sits in the list of blocks in
  132. % the form
  133. % (label location size b<n> b<n-1> ... b<0>)
  134. % where size is the size in bytes represented by the sequence of bytes
  135. % b<i>, except that the size of any final JUMP is not included. The
  136. % items in the list may be
  137. % an integer just that byte
  138. % (JUMP shortform longform label) short/long are lists of bytes
  139. % (EXTERN something) 4 bytes external reference
  140. % (COMMENT c1 c2 ...) to display in listing
  141. %
  142. fluid '(i_procedure i_block i_blocksize i_label i_pc i_externs);
  143. global '(!*genlisting);
  144. !*genlisting := nil;
  145. switch genlisting; % For the benefit of RLISP/Reduce users
  146. symbolic procedure i_startproc();
  147. << i_label := list nil;
  148. i_procedure := nil;
  149. i_externs := nil;
  150. i_block := nil;
  151. i_blocksize := 0;
  152. i_pc := 0;
  153. nil
  154. >>;
  155. symbolic procedure i_putlabel l;
  156. begin
  157. % car i_label can be nil at the start of a procedure or just after a jump
  158. % has been issued. If a label is set in such a case and any instructions
  159. % have been set in the dummy block then I invent a gensym-label for it,
  160. % but if a real label gets set soon enough I can avoid introducing any
  161. % sort of dummy mess.
  162. if car i_label = nil then <<
  163. if i_block = nil then <<
  164. rplaca(i_label, l);
  165. return >>
  166. else rplaca(i_label, gensym()) >>;
  167. %
  168. rplacd(i_label, i_pc . i_blocksize . i_block);
  169. i_procedure := i_label . i_procedure;
  170. put(car i_label, 'i_label, i_label);
  171. % When I first create a procedure I suppose (optimistically) that all
  172. % jumps can be rendered in short form.
  173. i_pc := i_pc + i_blocksize;
  174. if i_block and eqcar(car i_block, 'jump) then
  175. i_pc := i_pc + length cadar i_block + 1;
  176. i_label := list l;
  177. i_block := nil;
  178. i_blocksize := 0;
  179. nil
  180. end;
  181. % The user MUST put a comment just before each instruction if
  182. % disassembly is to behave properly. However if the assembly code
  183. % is not going to be displayed I can avoid storing the extra rubbish.
  184. symbolic procedure i_putcomment n;
  185. << if !*genlisting then i_block := ('comment . n) . i_block;
  186. nil
  187. >>;
  188. symbolic procedure i_putbyte n;
  189. << i_block := n . i_block;
  190. i_blocksize := i_blocksize + 1;
  191. nil
  192. >>;
  193. symbolic procedure i_put32 n;
  194. << i_putbyte logand(n, 0xff);
  195. n := logand(n, 0xffffffff) / 0x100;
  196. i_putbyte logand(n, 0xff);
  197. n := irightshift(n, 8);
  198. i_putbyte logand(n, 0xff);
  199. n := irightshift(n, 8);
  200. i_putbyte logand(n, 0xff);
  201. nil
  202. >>;
  203. % Codegenerators will need to use whether i_put32 or i_put32r
  204. % depending on the byte ordering used by the architecture that they support.
  205. symbolic procedure i_put32r n;
  206. << n := logand(n, 0xffffffff);
  207. i_putbyte logand(n / 0x01000000, 0xff);
  208. i_putbyte logand(n / 0x00010000, 0xff);
  209. i_putbyte logand(n / 0x00000100, 0xff);
  210. i_putbyte logand(n, 0xff);
  211. nil
  212. >>;
  213. %
  214. % i_put16 and i_put16r dump 16 bit values.
  215. %
  216. symbolic procedure i_put16 n;
  217. << i_putbyte logand(n, 0xff);
  218. n := irightshift(ilogand(n, 0xffff), 8);
  219. i_putbyte logand(n, 0xff);
  220. nil
  221. >>;
  222. symbolic procedure i_put16r n;
  223. << n := logand(n, 0xffff);
  224. i_putbyte irightshift(n, 8);
  225. i_putbyte logand(n, 0xff);
  226. nil
  227. >>;
  228. % In order to be able to optimise short jumps I will arrange to start a
  229. % fresh basic block after every jump instruction. I also store two
  230. % possible byte sequences for use in the final code, one for when the
  231. % target address is close by and the other for when it is further away.
  232. %
  233. symbolic procedure i_putjump(data, lab);
  234. << i_block := list('jump, data, lab) . i_block;
  235. if car i_label = nil then rplaca(i_label, gensym());
  236. rplacd(i_label, i_pc . i_blocksize . i_block);
  237. i_procedure := i_label . i_procedure;
  238. put(car i_label, 'i_label, i_label);
  239. % When a jump is first issued I will assemble it as a jump-to-self
  240. % which I expect to use the shortest form of jump available. Later on
  241. % and only if necessary I will expand it to a longer variant of the
  242. % instruction.
  243. i_pc := i_pc + i_blocksize + i_jumpsize(i_pc, i_pc, data);
  244. i_label := list nil; % leave in pending state
  245. i_block := nil;
  246. i_blocksize := 0;
  247. flag(list lab, 'i_used); % To get it displayed in listing
  248. nil
  249. >>;
  250. % References to "external" symbols will be used to call functions in the
  251. % Lisp kernel and to reference key variables there. At present I assume that
  252. % all such references will require a 32-bit field. This will get filled in by
  253. % load-time relocation code.
  254. symbolic procedure i_putextern a;
  255. << i_block := list('extern, a) . i_block;
  256. i_externs := list(i_label, i_blocksize, a) . i_externs;
  257. i_blocksize := i_blocksize + 4;
  258. nil
  259. >>;
  260. % prinhexb displays a hex number and then a blank, but only
  261. % if !*genlisting is true.
  262. symbolic procedure prinhexb(n, w);
  263. if !*genlisting then <<
  264. prinhex(n, w);
  265. princ " " >>;
  266. % i_resolve() iterates over the code re-calculating the length of
  267. % each basic block and hence deducing how long each jump instruction
  268. % has to be. When it has done that it scans the code to make a map
  269. % showing what external symbols will need relocating, and it builds
  270. % the relevant tables. Finally it allocates space for the assembled
  271. % code and puts the bytes where they need to be, optionally printing
  272. % a nice neat version for the user to admire.
  273. symbolic procedure i_resolve();
  274. begin
  275. scalar changed, pc, hardcode_handle, c, c1, c2, c3, gap, oll;
  276. oll := linelength 80;
  277. i_putlabel nil; % Flushes last block into data structures
  278. % The blocks had been collected in reverse order since that is how Lisp
  279. % finds it easiest to build up lists.
  280. i_procedure := reversip i_procedure;
  281. % Iterate until position of all blocks stabilises. In the very worst case
  282. % this could take a number of passes proportional to the length of the
  283. % code being assembled, but I do not expect that to happen often enough
  284. % to worry about it.
  285. repeat <<
  286. changed := nil;
  287. pc := 0;
  288. for each b in i_procedure do begin
  289. scalar loc, len, j;
  290. loc := cadr b; % estimated location
  291. len := caddr b; % length of block (excluding jump)
  292. j := cdddr b;
  293. if j then j := car j;
  294. if eqcar(j, 'jump) then j := cdr j else j := nil;
  295. if loc neq pc then <<
  296. changed := t; % will need to go around again.
  297. rplaca(cdr b, pc) >>;
  298. pc := pc + len;
  299. % The next bit evaluates the size of a jump instruction.
  300. if j then begin
  301. scalar target, offset;
  302. target := cadr get(cadr j, 'i_label);
  303. pc := pc + i_jumpsize(pc, target, car j) end
  304. end
  305. >> until not changed;
  306. % When I get to here pc shows the total size of the compiled code, and
  307. % all labels have been resolved with jumps able to be in their shortest
  308. % valid forms. The next thing to do is to sort out external references.
  309. i_pc := pc;
  310. i_externs := reversip i_externs;
  311. for each r in i_externs do rplaca(r, cadar r);
  312. c := i_externs;
  313. pc := 0;
  314. i_externs := nil;
  315. while c do begin
  316. scalar data, address, offset, addressmode, target, op;
  317. c1 := car c;
  318. data := caddr c1; % The "data" passed to i_putextern
  319. address := car c1 + cadr c1; % word to relocate
  320. offset := address - pc; % distance from previous relocation
  321. pc := address; % store loc to calculate next offset
  322. addressmode := car data; % data = {addressmode,target}
  323. target := cadr data;
  324. % The variable op will accumulate the first byte of the relocation information
  325. % which packs an address mode and a target catagory into 169 possibilities
  326. % as 13*13.
  327. op := 13*get(addressmode, 'i_addressmode);
  328. % The target is coded in a slighly (!) ugly way here. I decode it and
  329. % merge part of the information into the opcode byte, leaving the variable
  330. % "target" holding an 8-bit specification of just what to address.
  331. if numberp target then <<
  332. if target < 0 then <<
  333. op := op + 4; % RELOC_DIRECT_ENTRY
  334. target := -(target+1) >>
  335. else op := op + 5 >> % RELOC_VAR
  336. else <<
  337. op := op + cadr target; % RELOC_0_ARGS to RELOC_3_ARGS
  338. target := car target >>;
  339. % Now things are a bit messy. If the next relocation is close to the
  340. % current one (which it almost always will be) I use a single byte offset
  341. % to indicate where it is.
  342. if offset < 256 then % can use one-byte offset
  343. i_externs := offset . (op+1) . i_externs
  344. % If the next relocation is 256 or more bytes away I have to use an extended
  345. % form of relocation record. This spreads the opcode across two bytes and
  346. % that give space for 15 bits of genuine offset. If the gap was over
  347. % 0x7fff then even this is not enough, and in that case I use multiple
  348. % instances of the biggest offset I do support and do null relocations
  349. % at the intermediate places.
  350. else <<
  351. while offset > 0x7fff do <<
  352. % The sequence 0xff 0xff 0xff will be treated as NOP with offset 0x7fff
  353. % and thus provides for arbitrary expansion of the range of offsets.
  354. i_externs := 0xff . 0xff . 0xff . i_externs;
  355. offset := offset - 0x7fff >>;
  356. % NB (obviously?) the coding use here must agree with the corresponding
  357. % stuff in source file "restart.c" that unpicks stuff.
  358. i_externs := logand(offset, 0xff) . (171 + op/2) . i_externs;
  359. i_externs := (128*remainder(op, 2) + (offset/256)) . i_externs >>;
  360. i_externs := target . i_externs;
  361. % Here when I support RELOC_SELF_2 I will need to insert a target extension
  362. % byte into the code-stream here.
  363. %
  364. % Add an extra byte if the relocation needed patching with a further offset,
  365. % if we had address mode REL_OFFSET.
  366. if eqcar(gap, 'rel_offset) then
  367. i_externs := logand(caddr data, 0xff) . i_externs;
  368. % I put a "comment" into the list so that I can display a nice
  369. % or at least fairly symbolic indication of the relocation information
  370. % when the user has !*genlisting switched on.
  371. i_externs := list(pc, data) . i_externs;
  372. c := cdr c end;
  373. i_externs := '(termination) . 0 . i_externs; % Terminate the list
  374. % The first 4 bytes of some BPS give its length, and then the
  375. % next 4 bytes give the offset of the start of the actual code in it.
  376. % thuse there are 8 bytes of stuff to allow for.
  377. gap := 8;
  378. for each r in i_externs do if numberp r then gap := gap+1;
  379. % I will ensure that the compiled code itself starts at a word boundary. I
  380. % could make it start at a doubleword boundary easily enough if that made
  381. % a real difference to performance.
  382. c := logand(gap, 3);
  383. if c neq 0 then <<
  384. while c neq 4 do <<
  385. i_externs := 0 . i_externs;
  386. c := c + 1;
  387. gap := gap + 1 >>; % Word align
  388. i_externs := '(alignment) . i_externs >>;
  389. i_externs := reversip i_externs; % Back in the tidy order;
  390. % Insert the data that gives the offset to the start of real compiled code
  391. i_externs := list('start, compress
  392. ('!! . '!0 . '!x . explodehex gap)) . i_externs;
  393. i_externs := logand(gap / 0x01000000, 0xff) . i_externs;
  394. i_externs := logand(gap / 0x00010000, 0xff) . i_externs;
  395. i_externs := logand(gap / 0x00000100, 0xff) . i_externs;
  396. i_externs := logand(gap, 0xff) . i_externs;
  397. % Create space for the assembled code.
  398. i_pc := i_pc + gap;
  399. hardcode_handle := make!-native(i_pc);
  400. pc := 4;
  401. while i_externs do <<
  402. prinhexb(pc, 4);
  403. if !*genlisting then princ ": ";
  404. while i_externs and numberp car i_externs do <<
  405. prinhexb(car i_externs, 2);
  406. native!-putv(hardcode_handle, pc, car i_externs);
  407. pc := pc + 1;
  408. i_externs := cdr i_externs >>;
  409. if not atom i_externs then <<
  410. if !*genlisting then <<
  411. ttab 35;
  412. if numberp caar i_externs then <<
  413. princ "@";
  414. prinhex(gap+caar i_externs, 4);
  415. princ ": " >>
  416. else <<
  417. princ caar i_externs;
  418. princ " " >>;
  419. if cdar i_externs then printc cadar i_externs
  420. else terpri() >>;
  421. i_externs := cdr i_externs >> >>;
  422. if !*genlisting then terpri(); % between relocation table & code
  423. pc := gap;
  424. for each b in i_procedure do <<
  425. % I display labels unless they are never referenced.
  426. if !*genlisting and flagp(car b, 'i_used) then <<
  427. ttab 30; prin car b; printc ":" >>;
  428. % The instructions within a basic block had been accumulated in a list
  429. % that is reversed, so put it right here.
  430. c := reverse cdddr b; % Code list
  431. % I expect the first item in the list to be a comment, but if it is not
  432. % I will annotate things with a "?" rather than crashing.
  433. if c and eqcar(car c, 'comment) then <<
  434. c1 := cdar c; c := cdr c >>
  435. else c1 := '(!?);
  436. while c do <<
  437. prinhexb(pc, 4); princ ": "; % Address to put things at.
  438. % Since I really wanted comments before each instruction I will scan
  439. % forwrad until I either find the next comment or I hit the end of the list.
  440. while c and not eqcar(c2 := car c, 'comment) do <<
  441. if numberp c2 then <<
  442. prinhexb(c2, 2);
  443. native!-putv(hardcode_handle, pc, c2);
  444. pc := pc + 1 >>
  445. else if eqcar(c2, 'extern) then <<
  446. if !*genlisting then princ "xx xx xx xx ";
  447. native!-putv(hardcode_handle, pc, 0); pc := pc + 1;
  448. native!-putv(hardcode_handle, pc, 0); pc := pc + 1;
  449. native!-putv(hardcode_handle, pc, 0); pc := pc + 1;
  450. native!-putv(hardcode_handle, pc, 0); pc := pc + 1 >>
  451. else if eqcar(c2, 'jump) then <<
  452. for each j in i_jumpbytes(pc-gap,
  453. cadr get(caddr c2, 'i_label),
  454. cadr c2) do <<
  455. prinhexb(j, 2);
  456. native!-putv(hardcode_handle, pc, j); pc := pc + 1 >> >>;
  457. c := cdr c >>;
  458. if !*genlisting then << % Now display the comment
  459. ttab 34;
  460. for each w in c1 do <<
  461. if w = '!; then ttab 55 else princ " ";
  462. princ w >>;
  463. terpri() >>;
  464. if c and eqcar(c2, 'comment) then <<
  465. c1 := cdr c2; c := cdr c >> >> >>;
  466. % At the end of dealing with a procedure I will clean up the property lists
  467. % of all the symbols that were used as labels in it.
  468. for each b in i_procedure do <<
  469. remflag(list car b, 'i_used);
  470. remprop(car b, 'i_label) >>;
  471. linelength oll;
  472. return (hardcode_handle . gap)
  473. end;
  474. put('absolute, 'i_addressmode, 0); % Absolute address of target
  475. put('relative, 'i_addressmode, 1); % relative to start of reference
  476. put('rel_plus_4, 'i_addressmode, 2); % relative to end of reference
  477. put('rel_minus_2, 'i_addressmode, 3);% relative to 2 before item
  478. put('rel_minus_4, 'i_addressmode, 4);% relative to 4 before item
  479. put('rel_offset, 'i_addressmode, 5); % generic offset relative address
  480. %============================================================================
  481. % Now some Intel versions of jump support. This supposes that the "jump data"
  482. % passed down to i_putjump was just the one-byte opcode for the short
  483. % form of a relative jump.
  484. symbolic procedure i_jumpsize(pc, target, data);
  485. begin
  486. scalar offset;
  487. offset := target - (pc + 2); % Suppose short here
  488. if offset >= -128 and offset <= 127 then return 2 % short jump
  489. else if data = 0xeb then return 5 % unconditional
  490. else return 6 % conditional
  491. end;
  492. symbolic procedure i_jumpbytes(pc, target, data);
  493. begin
  494. scalar r, offset;
  495. offset := target - (pc + 2); % Suppose short for the moment
  496. if offset >= -128 and offset <= 127 then
  497. return list(data, logand(offset, 0xff));
  498. % An unconditional jump grows by 3 bytes while a conditional one
  499. % needs an extra 4. And on this architecture the offset is taken from the
  500. % end of the jump instruction, and so I need to adjust it a bit here.
  501. if data = 0xeb then << % 0xeb = short unconditional jump
  502. offset := offset - 3;
  503. r := list 0xe9 >> % 0xe9 = long unconditional jump
  504. else <<
  505. offset := offset - 4;
  506. r := list(data+0x10, 0x0f) >>; % +0x10 turns short to long jump
  507. offset := logand(offset, 0xffffffff);
  508. r := logand(offset, 0xff) . r;
  509. offset := offset / 0x100;
  510. r := ilogand(offset, 0xff) . r;
  511. offset := irightshift(offset, 8);
  512. r := ilogand(offset, 0xff) . r;
  513. offset := irightshift(offset, 8);
  514. r := ilogand(offset, 0xff) . r;
  515. return reversip r
  516. end;
  517. %
  518. % Next the code that transforms symbolically represented i80x86 instructions
  519. % into native machine code.
  520. %
  521. % The main macro of the code generator. Generates opcodes for a sequence of
  522. % i80x86 instructions represented in symbolic form. A macro is used just to
  523. % make the calling form perhaps more natural. The sequence supplied to this
  524. % macro looks as a list of parameters of arbitary length, not as a Lisp list
  525. % (into which the macro transforms this sequence). Things that are names
  526. % of Intel opcodes or registers do not need to be quoted... I detect them
  527. % and insert a quote during macro expansion.
  528. symbolic macro procedure i!:gopcode u;
  529. list('i!:genopcode, 'list .
  530. for each v in cdr u collect
  531. if atom v then
  532. (if get(v, 'i!:regcode) or get(v, 'i!:nargs) then mkquote v
  533. else v)
  534. else if eqcar(v, 'list) then for each v1 in v collect
  535. (if atom v1 and get(v1, 'i!:regcode) then mkquote v1
  536. else v1)
  537. else v);
  538. % Now the procedure which actually gets called. It looks for items that
  539. % are flagged as being opcodes, and for each such it knows how many
  540. % operands to expect. It can then call lower level routines to collect and
  541. % process those operands. Some amount of peephole optimisation is done on
  542. % the way, which is probably not where I want it to be done, but it can
  543. % remain here until I have re-worked the higher level compiler.
  544. symbolic procedure i!:genopcode u;
  545. begin
  546. scalar c, nargs;
  547. while u do <<
  548. c := car u;
  549. nargs := get(c, 'i!:nargs);
  550. if nargs then << % It is an opcode...
  551. u := cdr u;
  552. if nargs = 2 then <<
  553. i!:2arginstr(c, car u, cadr u);
  554. u := cddr u >>
  555. else if nargs = 1 then <<
  556. i!:1arginstr(c, car u);
  557. u := cdr u >>
  558. else i!:noarginstr c >>
  559. else if c = '!: then << % label
  560. i!:proc_label cadr u;
  561. u := cddr u >>
  562. else u := cdr u >> % Ignore anything that is not understood!
  563. end;
  564. <<
  565. % Codes of the processor registers
  566. put('eax, 'i!:regcode, 0);
  567. put('ecx, 'i!:regcode, 1);
  568. put('edx, 'i!:regcode, 2);
  569. put('ebx, 'i!:regcode, 3);
  570. put('esp, 'i!:regcode, 4);
  571. put('ebp, 'i!:regcode, 5);
  572. put('esi, 'i!:regcode, 6);
  573. put('edi, 'i!:regcode, 7);
  574. % ds and ebp have the same code, but instructions which contain memory
  575. % references of the form {ds,...} have a special prefix. However, this
  576. % code generator will produce wrong output for "mov ds,const" instruction.
  577. % But I can't imagine what it can be needed for and I am not sure it is
  578. % legal in the user mode.
  579. put('ds, 'i!:regcode, 5);
  580. % Irregular table of instructions opcodes. Values associated with the
  581. % properties are either main or secondary opcodes for different formats
  582. % of the instructions.
  583. put('add, 'i!:nargs, 2); put('add, 'i!:rm!-reg, 0x01);
  584. put('add, 'i!:immed!-rm, 0x81); put('add, 'i!:immed!-rm!-secopcode, 0);
  585. put('add, 'i!:immed!-eax, 0x05);
  586. put('and, 'i!:nargs, 2); put('and, 'i!:rm!-reg, 0x21);
  587. put('and, 'i!:immed!-rm, 0x81); put('and, 'i!:immed!-rm!-secopcode, 4);
  588. put('and, 'i!:immed!-eax, 0x25);
  589. put('call, 'i!:nargs, 1);
  590. put('call, 'i!:reg, 0xff); put('call, 'i!:reg!-secopcode, 0xd0);
  591. put('call, 'i!:jump, 0xe8);
  592. put('cmp, 'i!:nargs, 2); put('cmp, 'i!:rm!-reg, 0x39);
  593. put('cmp, 'i!:immed!-rm, 0x81); put('cmp, 'i!:immed!-rm!-secopcode, 7);
  594. put('cmp, 'i!:immed!-eax, 0x3d);
  595. put('dec, 'i!:nargs, 1);
  596. put('dec, 'i!:reg, 0x48);
  597. put('mul, 'i!:nargs, 2);
  598. put('mul, 'i!:rm!-reg!-prefix, 0x0f);
  599. put('mul, 'i!:rm!-reg, 0xaf); put('mul, 'i!:rm!-reg!-dbit_preset, 1);
  600. put('mul, 'i!:immed!-rm, 0x69);
  601. put('inc, 'i!:nargs, 1);
  602. put('inc, 'i!:reg, 0x40);
  603. put('je, 'i!:nargs, 1); put('je, 'i!:jump, 0x74);
  604. put('jne, 'i!:nargs, 1); put('jne, 'i!:jump, 0x75);
  605. put('jg, 'i!:nargs, 1); put('jg, 'i!:jump, 0x7f);
  606. put('jge, 'i!:nargs, 1); put('jge, 'i!:jump, 0x7d);
  607. put('jl, 'i!:nargs, 1); put('jl, 'i!:jump, 0x7c);
  608. put('jle, 'i!:nargs, 1); put('jle, 'i!:jump, 0x7e);
  609. put('ja, 'i!:nargs, 1); put('ja, 'i!:jump, 0x77);
  610. put('jae, 'i!:nargs, 1); put('jae, 'i!:jump, 0x73);
  611. put('jb, 'i!:nargs, 1); put('jb, 'i!:jump, 0x72);
  612. put('jbe, 'i!:nargs, 1); put('jbe, 'i!:jump, 0x76);
  613. put('jmp, 'i!:nargs, 1); put('jmp, 'i!:jump, 0xeb);
  614. put('mov, 'i!:nargs, 2); put('mov, 'i!:rm!-reg, 0x89);
  615. put('mov, 'i!:immed!-rm, 0xc7); put('mov, 'i!:immed!-rm!-secopcode, 0);
  616. flag('(mov), 'i!:immed!-rm!-noshortform);
  617. put('mov, 'i!:immed!-reg, 0xb8);
  618. put('neg, 'i!:nargs, 1);
  619. put('neg, 'i!:rm, 0xf5); put('neg, 'i!:rm!-secopcode, 3);
  620. put('or, 'i!:nargs, 2); put('or, 'i!:rm!-reg, 0x09);
  621. put('or, 'i!:immed!-rm, 0x81); put('or, 'i!:immed!-rm!-secopcode, 1);
  622. put('or, 'i!:immed!-eax, 0x0d);
  623. put('pop, 'i!:nargs, 1);
  624. put('pop, 'i!:reg, 0x58);
  625. put('pop, 'i!:mem, 0x8f); put('pop, 'i!:mem!-secopcode, 0x00);
  626. put('push, 'i!:nargs, 1);
  627. put('push, 'i!:reg, 0x50);
  628. put('push, 'i!:mem, 0xff); put('push, 'i!:mem!-secopcode, 0x06);
  629. put('push, 'i!:immed8, 0x6a); put('push, 'i!:immed32, 0x68);
  630. put('ret, 'i!:nargs, 0); put('ret, 'i!:code, 0xc3);
  631. put('shl, 'i!:nargs, 2);
  632. put('shl, 'i!:immed!-rm, 0xc1); put('shl, 'i!:immed!-rm!-secopcode, 4);
  633. flag('(shl), 'i!:immed!-rm!-shortformonly);
  634. put('shr, 'i!:nargs, 2);
  635. put('shr, 'i!:immed!-rm, 0xc1); put('shr, 'i!:immed!-rm!-secopcode, 5);
  636. flag('(shr), 'i!:immed!-rm!-shortformonly);
  637. put('sub, 'i!:nargs, 2); put('sub, 'i!:rm!-reg, 0x29);
  638. put('sub, 'i!:immed!-rm, 0x81); put('sub, 'i!:immed!-rm!-secopcode, 5);
  639. put('sub, 'i!:immed!-eax, 0x2d);
  640. put('test, 'i!:nargs, 2);
  641. put('test, 'i!:rm!-reg, 0x85); put('test, 'i!:rm!-reg!-dbit_preset, 0);
  642. put('test, 'i!:immed!-rm, 0xf7); put('test, 'i!:immed!-rm!-secopcode, 0);
  643. flag('(test), 'i!:immed!-rm!-noshortform);
  644. put('test, 'i!:immed!-eax, 0xa9);
  645. put('xor, 'i!:nargs, 2); put('xor, 'i!:rm!-reg, 0x31);
  646. put('xor, 'i!:immed!-rm, 0x81); put('xor, 'i!:immed!-rm!-secopcode, 6);
  647. put('xor, 'i!:immed!-eax, 0x35);
  648. % These instructions necessarily change registers when they are executed.
  649. % Hence we should keep track of them to get peephole optimisation right.
  650. flag('(add and dec mul inc neg or shl shr sub xor), 'i!:changes_reg)
  651. >>;
  652. fluid '(i!:reg_vec);
  653. % Addresses of some internal CSL variables and functions.
  654. % This table is needed by code compiled from Lisp which necessarily uses
  655. % Lisp run-time library and internal variables
  656. % Of course a worry here is that these addresses potentially change each
  657. % time Lisp is re-loaded into memory, and so I need to be a little
  658. % careful about their treatment.
  659. global '(OFS_NIL OFS_STACK OFS_LISP_TRUE OFS_CURRENT_MODULUS OFS_STACKLIMIT);
  660. <<
  661. OFS_NIL := 0; % Arg to give to native!-address
  662. OFS_STACK := 1;
  663. OFS_LISP_TRUE := 98;
  664. OFS_CURRENT_MODULUS := 29;
  665. !#if common!-lisp!-mode
  666. OFS_STACKLIMIT := 16;
  667. !#else
  668. OFS_STACKLIMIT := 15;
  669. !#endif
  670. % What follows will allow me to patch up direct calls to Lisp kernel
  671. % functions. The (negative) integers are codes to pass to native!-address
  672. % at the Lisp level and are then slightly adjusted to go in the relocation
  673. % tables that are generated here.
  674. put('cons, 'c!:direct_call_func, -1);
  675. put('ncons, 'c!:direct_call_func, -2);
  676. put('list2, 'c!:direct_call_func, -3);
  677. put('list2!*, 'c!:direct_call_func, -4);
  678. put('acons, 'c!:direct_call_func, -5);
  679. put('list3, 'c!:direct_call_func, -6);
  680. put('plus2, 'c!:direct_call_func, -7);
  681. put('difference, 'c!:direct_call_func, -8);
  682. put('add1, 'c!:direct_call_func, -9);
  683. put('sub1, 'c!:direct_call_func, -10);
  684. put('get, 'c!:direct_call_func, -11);
  685. put('lognot, 'c!:direct_call_func, -12);
  686. put('ash, 'c!:direct_call_func, -13);
  687. put('quotient, 'c!:direct_call_func, -14);
  688. put('remainder, 'c!:direct_call_func, -15);
  689. put('times2, 'c!:direct_call_func, -16);
  690. put('minus, 'c!:direct_call_func, -17);
  691. put('rational, 'c!:direct_call_func, -18);
  692. put('lessp, 'c!:direct_call_func, -19);
  693. put('leq, 'c!:direct_call_func, -20);
  694. put('greaterp, 'c!:direct_call_func, -21);
  695. put('geq, 'c!:direct_call_func, -22);
  696. put('zerop, 'c!:direct_call_func, -23);
  697. put('reclaim, 'c!:direct_call_func, -24);
  698. put('error, 'c!:direct_call_func, -25);
  699. put('equal_fn, 'c!:direct_call_func, -26);
  700. put('cl_equal_fn, 'c!:direct_call_func, -27);
  701. put('aerror, 'c!:direct_call_func, -28);
  702. put('integerp, 'c!:direct_call_func, -29);
  703. put('apply, 'c!:direct_call_func, -30);
  704. >>;
  705. fluid '(off_env off_nargs);
  706. off_nargs := 12; % off_env is set dynamically in cg_fndef
  707. symbolic procedure i!:translate_memref(a);
  708. % Check if an atomic symbol is a variable of the program being compiled, and
  709. % if so, return its assembler representation (memory address in a suitable
  710. % form). The first line implements the general mechanism of translating
  711. % references for local variables kept in stack. For such a symbolic variable
  712. % the 'i!:locoffs property should contain its offset in stack. The rest deals
  713. % with the translation of symbolic representations of CSL internal variables.
  714. %
  715. % ACN dislikes the use of the STRING "nil" here. Also resolution of the
  716. % addresses of C_nil, stack etc should be deferred to load time. But leave
  717. % it as it is for now since it works!
  718. %
  719. if (get(a, 'i!:locoffs)) then {'ebp, get(a, 'i!:locoffs)}
  720. else if a = "nil" then {'ebp,-4}
  721. else if a = 'env or a = '!.env then {'ebp,off_env}
  722. else if a = 'C_nil then {'ds,OFS_NIL}
  723. else if a = 'stack then {'ds,OFS_STACK}
  724. else if a = 'lisp_true then {'ds,OFS_LISP_TRUE}
  725. else if a = 'current_modulus then {'ds,OFS_CURRENT_MODULUS}
  726. else if a = 'stacklimit then {'ds,OFS_STACKLIMIT}
  727. else if flagp(a, 'c!:live_across_call) then {'ebx,-get(a, 'c!:location)*4}
  728. else a; % Otherwise we hope that this is a symbolic label - a call
  729. % or jump operand.
  730. symbolic procedure i!:outmemfield(reg, mem);
  731. % Generate the second and further bytes of the instruction whose operand is
  732. % memory. For 2-arg instructions reg means code of the register operand,
  733. % for 1-arg instructions it is a secondary opcode
  734. % Examples of the forms of memory references accepted are given below:
  735. % {ds,1234}, {ebx,-16}, {eax,2,ebx}, {ecx,4,edx,32}
  736. begin
  737. scalar secbyte, thirdbyte, constofs, constofslong, reg1name,
  738. reg1, reg2, mul;
  739. reg1name := car mem;
  740. reg1 := get(reg1name, 'i!:regcode);
  741. if length mem = 1 or
  742. ((length mem = 2) and numberp cadr mem) then <<
  743. % [reg1] or [reg1 + ofs]
  744. secbyte := reg*8 + reg1;
  745. mem := cdr mem;
  746. % Curious peculiarities of constant offset length field behaviour
  747. % when ebp (or ds) is an operand force me to do this weird thing.
  748. if (not mem) and (reg1name = 'ebp) then mem := cons(0, nil);
  749. if mem then <<
  750. constofs := car mem;
  751. if (constofs > 127) or (constofs < -128) or (reg1name = 'ds) then <<
  752. if reg1name neq 'ds then secbyte := secbyte + 0x80;
  753. constofslong := t >>
  754. else <<
  755. secbyte := secbyte + 0x40;
  756. constofslong := nil >>
  757. >>;
  758. i_putbyte secbyte
  759. >>
  760. else << % [reg + reg] or [reg + const*reg] or [reg + const*reg + ofs]
  761. secbyte := 0x04 + reg*8; % 0x04 is a magic number, imho
  762. thirdbyte := reg1;
  763. mem := cdr mem;
  764. if numberp car mem then <<
  765. mul := car mem;
  766. if mul = 8 then thirdbyte := thirdbyte + 0xc0
  767. else if mul = 4 then thirdbyte := thirdbyte + 0x80
  768. else if mul = 2 then thirdbyte := thirdbyte + 0x40;
  769. mem := cdr mem >>;
  770. reg2 := get(car mem, 'i!:regcode);
  771. thirdbyte := thirdbyte + reg2*8;
  772. mem := cdr mem;
  773. if (not mem) and (reg1name = 'ebp) then mem := 0 . nil;
  774. if mem then <<
  775. constofs := car mem;
  776. if (constofs > 127) or (constofs < -128) then <<
  777. % Weird thing with ebp again - only for it in this case we should
  778. % put 00 in two bits representing the offset length
  779. if reg1name neq 'ebp then secbyte := secbyte + 0x80;
  780. constofslong := t >>
  781. else <<
  782. secbyte := secbyte + 0x40;
  783. constofslong := nil >>
  784. >>
  785. else constofs := nil;
  786. i_putbyte secbyte;
  787. i_putbyte thirdbyte
  788. >>;
  789. if constofs then
  790. if constofslong then <<
  791. if reg1name='ds then i_putextern list('absolute, constofs)
  792. else i_put32 constofs >>
  793. else i_putbyte ilogand(constofs, 0xff)
  794. end;
  795. symbolic procedure i!:remove_reg_memrefs(reg);
  796. % A part of peephole optimisation. We maintain the table which has an entry
  797. % per register. An entry for register reg contains registers and memory
  798. % references whose contents are equal to reg. When reg is changed, we
  799. % must flush its entry. This is already done when this procedure called.
  800. % But what we should also do (here) is to check if the buffer for any
  801. % register other than reg contains reg or a memory reference which includes
  802. % reg, such as {reg,1000}, and remove all such references.
  803. begin
  804. scalar regi, regi1, memref;
  805. for i := 0:2 do <<
  806. regi := getv(i!:reg_vec, i);
  807. regi1 := nil;
  808. while regi neq nil do <<
  809. memref := car regi;
  810. regi := cdr regi;
  811. if (atom memref) and (memref neq reg) then regi1 := memref . regi1
  812. else if not member(reg, memref) then regi1 := memref . regi1;
  813. >>;
  814. putv(i!:reg_vec, i, regi1)
  815. >>
  816. end;
  817. symbolic procedure i!:eq_to_reg(mem);
  818. % Check if a memory variable is equal to some register at the current moment
  819. begin
  820. scalar i,res;
  821. res := nil;
  822. for i := 0:2 do
  823. if member(mem, getv(i!:reg_vec, i)) then res := i;
  824. return res;
  825. end;
  826. symbolic procedure i!:regname(code);
  827. % Return register symbolic name for its code
  828. if code = 0 then 'eax
  829. else if code = 1 then 'ecx
  830. else if code = 2 then 'edx
  831. else error1 "bad regname";
  832. symbolic procedure encomment(reg1, a1);
  833. if reg1 then list a1
  834. else begin
  835. scalar x;
  836. x := i!:translate_memref a1;
  837. if a1 = x then return list a1
  838. else return list(x, '!;, list a1) end;
  839. symbolic procedure i!:2arginstr(instr, a1, a2);
  840. % Process an instruction with two arguments
  841. begin
  842. scalar reg1, reg2, isnuma2, longnuma2, code, secopcode,
  843. tmp, dbit, pref, c1, c2;
  844. reg1 := get(a1, 'i!:regcode);
  845. reg2 := get(a2, 'i!:regcode);
  846. isnuma2 := numberp a2;
  847. if isnuma2 then longnuma2 := not zerop irightshift(a2,8);
  848. % Peephole optimisation - replace "instr d,mem" with
  849. % "instr d,reg" if reg = mem
  850. if (not reg2) and (not isnuma2) then <<
  851. reg2 := i!:eq_to_reg(a2);
  852. if reg2 and not ((instr = 'mov) and (reg1 = reg2)) then
  853. a2 := i!:regname(reg2)
  854. else reg2 := nil;
  855. >>;
  856. % Peephole optimisation - redundant memory-register transfers suppression
  857. if (reg1) and (reg1 <= 2) then <<
  858. if flagp(instr, 'i!:changes_reg) then <<
  859. putv(i!:reg_vec, reg1, nil);
  860. i!:remove_reg_memrefs(a1);
  861. >>
  862. else if (instr = 'mov) then << % mov reg1, a2(which is mem or reg)
  863. if member(a2, getv(i!:reg_vec, reg1)) then % Suppress MOV
  864. return nil
  865. else <<
  866. i!:remove_reg_memrefs(a1);
  867. if not reg2 then << % a2 is a memory location
  868. if (not atom a2) and (member(a1,a2)) then
  869. putv(i!:reg_vec, reg1, nil)
  870. else putv(i!:reg_vec, reg1, a2 . nil) >>
  871. else << % a2 is a register
  872. putv(i!:reg_vec, reg1, a2 . getv(i!:reg_vec, reg2));
  873. putv(i!:reg_vec, reg2, a1 . getv(i!:reg_vec, reg2));
  874. >>
  875. >>
  876. >>
  877. >>
  878. else if (instr = 'mov) and reg2 and (reg2 <= 2) then <<
  879. if member(a1, getv(i!:reg_vec, reg2)) then % Suppress MOV
  880. return nil
  881. else <<
  882. for i := 0:2 do
  883. putv(i!:reg_vec, i, delete(a1, getv(i!:reg_vec,i)));
  884. putv(i!:reg_vec, reg2, a1 . getv(i!:reg_vec, reg2))
  885. >>
  886. >>;
  887. c1 := encomment(reg1, a1); c2 := encomment(reg2, a2);
  888. if null cdr c1 then c1 := append(c1, c2)
  889. else c1 := car c1 . append(c2, cdr c1);
  890. i_putcomment (instr . c1);
  891. if reg1 then % Immediate/register/memory to register variant
  892. if isnuma2 then << % Immediate to register variants
  893. if longnuma2 and (a1 = 'eax) then code := get(instr, 'i!:immed!-eax)
  894. else code := nil;
  895. if code then << % "Immediate to eax" version of instruction
  896. i_putbyte code;
  897. i_put32 a2;
  898. >>
  899. else << % "Immediate to register" version of
  900. % instruction (MOV,?..)
  901. code := get(instr, 'i!:immed!-reg);
  902. if code then <<
  903. i_putbyte(code + reg1);
  904. i_put32 a2;
  905. >>
  906. else << % General "immediate to register/memory" version
  907. code := get(instr, 'i!:immed!-rm);
  908. if code then <<
  909. secopcode := get(instr, 'i!:immed!-rm!-secopcode);
  910. if not secopcode then secopcode := reg1;
  911. if longnuma2 then << % Long immediate constant
  912. if flagp(instr, 'i!:immed!-rm!-shortformonly) then <<
  913. error1 "Long constant is invalid here" >>;
  914. i_putbyte code; i_putbyte(0xc0 + secopcode*8 + reg1);
  915. i_put32 a2
  916. >>
  917. else << % Short immediate constant
  918. if flagp(instr, 'i!:immed!-rm!-noshortform) then <<
  919. i_putbyte code; i_putbyte(0xc0 + secopcode*8 + reg1);
  920. i_put32 a2 >>
  921. else if flagp(instr, 'i!:immed!-rm!-shortformonly) then <<
  922. i_putbyte code; i_putbyte(0xc0 + secopcode*8 + reg1);
  923. i_putbyte a2 >>
  924. else <<
  925. i_putbyte(code+2);
  926. i_putbyte(0xc0 + secopcode*8 + reg1);
  927. i_putbyte a2 >>
  928. >>
  929. >>
  930. else error1 "Invalid combination of opcode and operands 1"
  931. >>
  932. >>
  933. >>
  934. else << % Register/memory to register
  935. code := get(instr, 'i!:rm!-reg);
  936. if not code then
  937. error1 "Invalid combination of opcode and operands 2";
  938. if reg2 then << % Register to register
  939. if (pref := get(instr, 'i!:rm!-reg!-prefix)) then i_putbyte pref;
  940. if (dbit := get(instr, 'i!:rm!-reg!-dbit_preset)) then <<
  941. % Special case when changing d bit changes the whole instruction
  942. i_putbyte code;
  943. if dbit = 0 then <<
  944. tmp := reg1; reg1 := reg2; reg2 := tmp >>
  945. >>
  946. else i_putbyte(code + 2);
  947. i_putbyte(0xc0 + reg1*8 + reg2)
  948. >>
  949. else << % Memory to register
  950. if atom a2 then a2 := i!:translate_memref(a2);
  951. if car a2 = 'ds then <<
  952. i_putbyte 0x3E;
  953. if (instr = 'mov) and (reg1 = 0) then << % mov eax,ds:[...]
  954. i_putbyte 0xa1;
  955. i_putextern list('absolute, cadr a2);
  956. % More complicated ds addressing is not implemented yet!
  957. return nil
  958. >>
  959. >>;
  960. i_putbyte(code + 2);
  961. i!:outmemfield(reg1, a2)
  962. >>
  963. >>
  964. else if reg2 then << % Register to memory
  965. code := get(instr, 'i!:rm!-reg);
  966. if not code then
  967. error1 "Invalid combination of opcode and operands 3";
  968. if atom a1 then a1 := i!:translate_memref(a1);
  969. if car a1 = 'ds then <<
  970. i_putbyte 0x3E;
  971. if (instr = 'mov) and (reg2 = 0) then << % mov ds:[...],eax
  972. i_putbyte 0xa3;
  973. i_putextern list('absolute, cadr a1);
  974. % More complicated ds addressing is not implemented yet!
  975. return nil
  976. >>
  977. >>;
  978. i_putbyte code;
  979. i!:outmemfield(reg2, a1)
  980. >>
  981. else error1 "Invalid combination of opcode and operands 4"
  982. end;
  983. symbolic procedure i!:1arginstr(instr, a1);
  984. % Process an instruction with one argument
  985. begin
  986. scalar reg1, code, secopcode, labrec, curpos, dist;
  987. reg1 := get(a1, 'i!:regcode);
  988. % Peephole optimisation - replace push mem with push reg if mem = reg
  989. if (not reg1) and (instr = 'push) then <<
  990. reg1 := i!:eq_to_reg(a1);
  991. if reg1 then a1 := i!:regname(reg1)
  992. >>;
  993. if not reg1 and atom a1 then a1 := i!:translate_memref(a1);
  994. % Part of peephole optimisation - control of changing register contents
  995. if flagp(instr, 'i!:changes_reg) and reg1 and (reg1 <= 2) then <<
  996. putv(i!:reg_vec, reg1, nil);
  997. i!:remove_reg_memrefs(a1)
  998. >>;
  999. i_putcomment (instr . encomment(reg1, a1));
  1000. if atom a1 then << % Register or label operand
  1001. if reg1 then << % Register operand
  1002. code := get(instr, 'i!:reg);
  1003. if code then << % "Register" version of instruction
  1004. secopcode := get(instr, 'i!:reg!-secopcode);
  1005. if not secopcode then i_putbyte(code + reg1)
  1006. else <<
  1007. i_putbyte code;
  1008. i_putbyte(secopcode + reg1) >>
  1009. >>
  1010. else << % "Register/memory" version of instruction
  1011. code := get(instr, 'i!:rm);
  1012. secopcode := get(instr, 'i!:rm!-secopcode);
  1013. i_putbyte(code+2);
  1014. i_putbyte(0xc0 + secopcode*8 + reg1)
  1015. >>
  1016. >>
  1017. else if numberp a1 then << % Immediate operand
  1018. if (a1 > 127) or (a1 < -128) then <<
  1019. code := get(instr, 'i!:immed32);
  1020. i_putbyte code;
  1021. i_put32 a1 >>
  1022. else <<
  1023. code := get(instr, 'i!:immed8);
  1024. i_putbyte code;
  1025. i_putbyte a1 >>
  1026. >>
  1027. else << % Jumps and call remain, thus label operand
  1028. code := get(instr, 'i!:jump);
  1029. if not code then
  1030. error1 "Invalid combination of opcode and operands 1";
  1031. if instr = 'call then <<
  1032. printc("##### CALL ", a1);
  1033. i_putbyte code;
  1034. i_putextern list('rel_plus_4, 99); % What am I calling????
  1035. % Part of peephole optimisation
  1036. for i := 0:2 do putv(i!:reg_vec, i, nil)
  1037. >>
  1038. else i_putjump(code, a1);
  1039. >>
  1040. >>
  1041. else << % Memory operand
  1042. code := get(instr, 'i!:mem);
  1043. secopcode := get(instr, 'i!:mem!-secopcode);
  1044. if not secopcode then secopcode := 0;
  1045. if car a1 = 'ds then i_putbyte 0x3E;
  1046. i_putbyte code;
  1047. i!:outmemfield(secopcode, a1);
  1048. >>
  1049. end;
  1050. symbolic procedure i!:noarginstr instr;
  1051. % Process an instruction with no arguments
  1052. << i_putcomment list instr;
  1053. i_putbyte get(instr,'i!:code) >>;
  1054. symbolic procedure i!:proc_label lab;
  1055. % Process a label
  1056. begin
  1057. i_putlabel lab;
  1058. % Part of peephole optimisation
  1059. for i := 0:2 do putv(i!:reg_vec, i, nil)
  1060. end;
  1061. %
  1062. % Now the higher level parts of the compiler.
  1063. %
  1064. global '(!*fastvector !*unsafecar);
  1065. flag('(fastvector unsafecar), 'switch);
  1066. % Some internal CSL constants
  1067. global '(TAG_BITS TAG_CONS TAG_FIXNUM TAG_ODDS TAG_SYMBOL TAG_NUMBERS
  1068. TAG_VECTOR GC_STACK SPID_NOPROP);
  1069. TAG_BITS := 7;
  1070. TAG_CONS := 0;
  1071. TAG_FIXNUM := 1;
  1072. TAG_ODDS := 2;
  1073. TAG_SYMBOL := 4;
  1074. TAG_NUMBERS := 5;
  1075. TAG_VECTOR := 6;
  1076. GC_STACK := 2;
  1077. SPID_NOPROP := 0xc2 + 0x0b00;
  1078. %
  1079. % I start with some utility functions that provide something
  1080. % related to a FORMAT or PRINTF facility
  1081. %
  1082. % This establishes a default handler for each special form so that
  1083. % any that I forget to treat more directly will cause a tidy error
  1084. % if found in compiled code.
  1085. symbolic procedure c!:cspecform(x, env);
  1086. error(0, list("special form", x));
  1087. << put('and, 'c!:code, function c!:cspecform);
  1088. !#if common!-lisp!-mode
  1089. put('block, 'c!:code, function c!:cspecform);
  1090. !#endif
  1091. put('catch, 'c!:code, function c!:cspecform);
  1092. put('compiler!-let, 'c!:code, function c!:cspecform);
  1093. put('cond, 'c!:code, function c!:cspecform);
  1094. put('declare, 'c!:code, function c!:cspecform);
  1095. put('de, 'c!:code, function c!:cspecform);
  1096. !#if common!-lisp!-mode
  1097. put('defun, 'c!:code, function c!:cspecform);
  1098. !#endif
  1099. put('eval!-when, 'c!:code, function c!:cspecform);
  1100. put('flet, 'c!:code, function c!:cspecform);
  1101. put('function, 'c!:code, function c!:cspecform);
  1102. put('go, 'c!:code, function c!:cspecform);
  1103. put('if, 'c!:code, function c!:cspecform);
  1104. put('labels, 'c!:code, function c!:cspecform);
  1105. !#if common!-lisp!-mode
  1106. put('let, 'c!:code, function c!:cspecform);
  1107. !#else
  1108. put('!~let, 'c!:code, function c!:cspecform);
  1109. !#endif
  1110. put('let!*, 'c!:code, function c!:cspecform);
  1111. put('list, 'c!:code, function c!:cspecform);
  1112. put('list!*, 'c!:code, function c!:cspecform);
  1113. put('macrolet, 'c!:code, function c!:cspecform);
  1114. put('multiple!-value!-call, 'c!:code, function c!:cspecform);
  1115. put('multiple!-value!-prog1, 'c!:code, function c!:cspecform);
  1116. put('or, 'c!:code, function c!:cspecform);
  1117. put('prog, 'c!:code, function c!:cspecform);
  1118. put('prog!*, 'c!:code, function c!:cspecform);
  1119. put('prog1, 'c!:code, function c!:cspecform);
  1120. put('prog2, 'c!:code, function c!:cspecform);
  1121. put('progn, 'c!:code, function c!:cspecform);
  1122. put('progv, 'c!:code, function c!:cspecform);
  1123. put('quote, 'c!:code, function c!:cspecform);
  1124. put('return, 'c!:code, function c!:cspecform);
  1125. put('return!-from, 'c!:code, function c!:cspecform);
  1126. put('setq, 'c!:code, function c!:cspecform);
  1127. put('tagbody, 'c!:code, function c!:cspecform);
  1128. put('the, 'c!:code, function c!:cspecform);
  1129. put('throw, 'c!:code, function c!:cspecform);
  1130. put('unless, 'c!:code, function c!:cspecform);
  1131. put('unwind!-protect, 'c!:code, function c!:cspecform);
  1132. put('when, 'c!:code, function c!:cspecform) >>;
  1133. fluid '(current_procedure current_args current_block current_contents
  1134. all_blocks registers stacklocs);
  1135. fluid '(available used);
  1136. available := used := nil;
  1137. fluid '(lab_end_proc);
  1138. symbolic procedure c!:reset_gensyms();
  1139. << remflag(used, 'c!:live_across_call);
  1140. remflag(used, 'c!:visited);
  1141. while used do <<
  1142. remprop(car used, 'c!:contents);
  1143. remprop(car used, 'c!:why);
  1144. remprop(car used, 'c!:where_to);
  1145. remprop(car used, 'c!:count);
  1146. remprop(car used, 'c!:live);
  1147. remprop(car used, 'c!:clash);
  1148. remprop(car used, 'c!:chosen);
  1149. remprop(car used, 'c!:location);
  1150. remprop(car used, 'i!:locoffs);
  1151. if plist car used then begin
  1152. scalar o; o := wrs nil;
  1153. princ "+++++ "; prin car used; princ " ";
  1154. prin plist car used; terpri();
  1155. wrs o end;
  1156. available := car used . available;
  1157. used := cdr used >> >>;
  1158. !#if common!-lisp!-mode
  1159. fluid '(my_gensym_counter);
  1160. my_gensym_counter := 0;
  1161. !#endif
  1162. symbolic procedure c!:my_gensym();
  1163. begin
  1164. scalar w;
  1165. if available then << w := car available; available := cdr available >>
  1166. !#if common!-lisp!-mode
  1167. else w := compress1
  1168. ('!v . explodec (my_gensym_counter := my_gensym_counter + 1));
  1169. !#else
  1170. else w := gensym1 "v";
  1171. !#endif
  1172. used := w . used;
  1173. if plist w then << princ "????? "; prin w; princ " => "; prin plist w; terpri() >>;
  1174. return w
  1175. end;
  1176. symbolic procedure c!:newreg();
  1177. begin
  1178. scalar r;
  1179. r := c!:my_gensym();
  1180. registers := r . registers;
  1181. return r
  1182. end;
  1183. symbolic procedure c!:startblock s;
  1184. << current_block := s;
  1185. current_contents := nil
  1186. >>;
  1187. symbolic procedure c!:outop(a,b,c,d);
  1188. if current_block then
  1189. current_contents := list(a,b,c,d) . current_contents;
  1190. symbolic procedure c!:endblock(why, where_to);
  1191. if current_block then <<
  1192. % Note that the operations within a block are in reversed order.
  1193. put(current_block, 'c!:contents, current_contents);
  1194. put(current_block, 'c!:why, why);
  1195. put(current_block, 'c!:where_to, where_to);
  1196. all_blocks := current_block . all_blocks;
  1197. current_contents := nil;
  1198. current_block := nil >>;
  1199. %
  1200. % Now for a general driver for compilation
  1201. %
  1202. symbolic procedure c!:cval_inner(x, env);
  1203. begin
  1204. scalar helper;
  1205. % NB use the "improve" function from the regular compiler here...
  1206. x := s!:improve x;
  1207. % atoms and embedded lambda expressions need their own treatment.
  1208. if atom x then return c!:catom(x, env)
  1209. else if eqcar(car x, 'lambda) then
  1210. return c!:clambda(cadar x, 'progn . cddar x, cdr x, env)
  1211. % a c!:code property gives direct control over compilation
  1212. else if helper := get(car x, 'c!:code) then
  1213. return funcall(helper, x, env)
  1214. % compiler-macros take precedence over regular macros, so that I can
  1215. % make special expansions in the context of compilation. Only used if the
  1216. % expansion is non-nil
  1217. else if (helper := get(car x, 'c!:compile_macro)) and
  1218. (helper := funcall(helper, x)) then
  1219. return c!:cval(helper, env)
  1220. % regular Lisp macros get expanded
  1221. else if idp car x and (helper := macro!-function car x) then
  1222. return c!:cval(funcall(helper, x), env)
  1223. % anything not recognised as special will be turned into a
  1224. % function call, but there will still be special cases, such as
  1225. % calls to the current function, calls into the C-coded kernel, etc.
  1226. else return c!:ccall(car x, cdr x, env)
  1227. end;
  1228. symbolic procedure c!:cval(x, env);
  1229. begin
  1230. scalar r;
  1231. r := c!:cval_inner(x, env);
  1232. if r and not member!*!*(r, registers) then
  1233. error(0, list(r, "not a register", x));
  1234. return r
  1235. end;
  1236. symbolic procedure c!:clambda(bvl, body, args, env);
  1237. begin
  1238. scalar w, fluids, env1;
  1239. env1 := car env;
  1240. w := for each a in args collect c!:cval(a, env);
  1241. for each v in bvl do <<
  1242. if globalp v then begin scalar oo;
  1243. oo := wrs nil;
  1244. princ "+++++ "; prin v;
  1245. princ " converted from GLOBAL to FLUID"; terpri();
  1246. wrs oo;
  1247. unglobal list v;
  1248. fluid list v end;
  1249. if fluidp v then <<
  1250. fluids := (v . c!:newreg()) . fluids;
  1251. flag(list cdar fluids, 'c!:live_across_call); % silly if not
  1252. env1 := ('c!:dummy!:name . cdar fluids) . env1;
  1253. c!:outop('ldrglob, cdar fluids, v, c!:find_literal v);
  1254. c!:outop('strglob, car w, v, c!:find_literal v) >>
  1255. else <<
  1256. env1 := (v . c!:newreg()) . env1;
  1257. c!:outop('movr, cdar env1, nil, car w) >>;
  1258. w := cdr w >>;
  1259. if fluids then c!:outop('fluidbind, nil, nil, fluids);
  1260. env := env1 . append(fluids, cdr env);
  1261. w := c!:cval(body, env);
  1262. for each v in fluids do
  1263. c!:outop('strglob, cdr v, car v, c!:find_literal car v);
  1264. return w
  1265. end;
  1266. symbolic procedure c!:locally_bound(x, env);
  1267. atsoc(x, car env);
  1268. flag('(nil t), 'c!:constant);
  1269. fluid '(literal_vector);
  1270. symbolic procedure c!:find_literal x;
  1271. begin
  1272. scalar n, w;
  1273. w := literal_vector;
  1274. n := 0;
  1275. while w and not (car w = x) do <<
  1276. n := n + 1;
  1277. w := cdr w >>;
  1278. if null w then literal_vector := append(literal_vector, list x);
  1279. return n
  1280. end;
  1281. symbolic procedure c!:catom(x, env);
  1282. begin
  1283. scalar v, w;
  1284. v := c!:newreg();
  1285. if idp x and (w := c!:locally_bound(x, env)) then
  1286. c!:outop('movr, v, nil, cdr w)
  1287. else if null x or x = 't or c!:small_number x then
  1288. c!:outop('movk1, v, nil, x)
  1289. else if not idp x or flagp(x, 'c!:constant) then
  1290. c!:outop('movk, v, x, c!:find_literal x)
  1291. else c!:outop('ldrglob, v, x, c!:find_literal x);
  1292. return v
  1293. end;
  1294. symbolic procedure c!:cjumpif(x, env, d1, d2);
  1295. begin
  1296. scalar helper, r;
  1297. x := s!:improve x;
  1298. if atom x and (not idp x or
  1299. (flagp(x, 'c!:constant) and not c!:locally_bound(x, env))) then
  1300. c!:endblock('goto, list (if x then d1 else d2))
  1301. else if not atom x and (helper := get(car x, 'c!:ctest)) then
  1302. return funcall(helper, x, env, d1, d2)
  1303. else <<
  1304. r := c!:cval(x, env);
  1305. c!:endblock(list('ifnull, r), list(d2, d1)) >>
  1306. end;
  1307. fluid '(current);
  1308. symbolic procedure c!:ccall(fn, args, env);
  1309. c!:ccall1(fn, args, env);
  1310. fluid '(visited);
  1311. symbolic procedure c!:has_calls(a, b);
  1312. begin
  1313. scalar visited;
  1314. return c!:has_calls_1(a, b)
  1315. end;
  1316. symbolic procedure c!:has_calls_1(a, b);
  1317. % true if there is a path from node a to node b that has a call instruction
  1318. % on the way.
  1319. if a = b or not atom a or memq(a, visited) then nil
  1320. else begin
  1321. scalar has_call;
  1322. visited := a . visited;
  1323. for each z in get(a, 'c!:contents) do
  1324. if eqcar(z, 'call) then has_call := t;
  1325. if has_call then return
  1326. begin scalar visited;
  1327. return c!:can_reach(a, b) end;
  1328. for each d in get(a, 'c!:where_to) do
  1329. if c!:has_calls_1(d, b) then has_call := t;
  1330. return has_call
  1331. end;
  1332. symbolic procedure c!:can_reach(a, b);
  1333. if a = b then t
  1334. else if not atom a or memq(a, visited) then nil
  1335. else <<
  1336. visited := a . visited;
  1337. c!:any_can_reach(get(a, 'c!:where_to), b) >>;
  1338. symbolic procedure c!:any_can_reach(l, b);
  1339. if null l then nil
  1340. else if c!:can_reach(car l, b) then t
  1341. else c!:any_can_reach(cdr l, b);
  1342. symbolic procedure c!:pareval(args, env);
  1343. begin
  1344. scalar tasks, tasks1, merge, split, r;
  1345. tasks := for each a in args collect (c!:my_gensym() . c!:my_gensym());
  1346. split := c!:my_gensym();
  1347. c!:endblock('goto, list split);
  1348. for each a in args do begin
  1349. scalar s;
  1350. % I evaluate each arg as what is (at this stage) a separate task
  1351. s := car tasks;
  1352. tasks := cdr tasks;
  1353. c!:startblock car s;
  1354. r := c!:cval(a, env) . r;
  1355. c!:endblock('goto, list cdr s);
  1356. % If the task did no procedure calls (or only tail calls) then it can be
  1357. % executed sequentially with the other args without need for stacking
  1358. % anything. Otherwise it more care will be needed. Put the hard
  1359. % cases onto tasks1.
  1360. !#if common!-lisp!-mode
  1361. tasks1 := s . tasks1
  1362. !#else
  1363. if c!:has_calls(car s, cdr s) then tasks1 := s . tasks1
  1364. else merge := s . merge
  1365. !#endif
  1366. end;
  1367. %-- % if there are zero or one items in tasks1 then again it is easy -
  1368. %-- % otherwise I flag the problem with a notionally parallel construction.
  1369. %-- if tasks1 then <<
  1370. %-- if null cdr tasks1 then merge := car tasks1 . merge
  1371. %-- else <<
  1372. %-- c!:startblock split;
  1373. %-- printc "***** ParEval needed parallel block here...";
  1374. %-- c!:endblock('par, for each v in tasks1 collect car v);
  1375. %-- split := c!:my_gensym();
  1376. %-- for each v in tasks1 do <<
  1377. %-- c!:startblock cdr v;
  1378. %-- c!:endblock('goto, list split) >> >> >>;
  1379. for each z in tasks1 do merge := z . merge; % do sequentially
  1380. %--
  1381. %--
  1382. % Finally string end-to-end all the bits of sequential code I have left over.
  1383. for each v in merge do <<
  1384. c!:startblock split;
  1385. c!:endblock('goto, list car v);
  1386. split := cdr v >>;
  1387. c!:startblock split;
  1388. return reversip r
  1389. end;
  1390. symbolic procedure c!:ccall1(fn, args, env);
  1391. begin
  1392. scalar tasks, merge, r, val;
  1393. fn := list(fn, cdr env);
  1394. val := c!:newreg();
  1395. if null args then c!:outop('call, val, nil, fn)
  1396. else if null cdr args then
  1397. c!:outop('call, val, list c!:cval(car args, env), fn)
  1398. else <<
  1399. r := c!:pareval(args, env);
  1400. c!:outop('call, val, r, fn) >>;
  1401. c!:outop('reloadenv, 'env, nil, nil);
  1402. return val
  1403. end;
  1404. fluid '(restart_label reloadenv does_call current_c_name);
  1405. %
  1406. % The "proper" recipe here arranges that functions that expect over 2 args use
  1407. % the "va_arg" mechanism to pick up ALL their args. This would be pretty
  1408. % heavy-handed, and at least on a lot of machines it does not seem to
  1409. % be necessary. I will duck it for a while more at least.
  1410. %
  1411. fluid '(proglabs blockstack retloc);
  1412. symbolic procedure c!:cfndef(current_procedure, current_c_name, args, body);
  1413. begin
  1414. scalar env, n, w, current_args, current_block, restart_label,
  1415. current_contents, all_blocks, entrypoint, exitpoint, args1,
  1416. registers, stacklocs, literal_vector, reloadenv, does_call,
  1417. blockstack, proglabs, stackoffs, env_vec, i, retloc;
  1418. c!:reset_gensyms();
  1419. i_startproc();
  1420. i!:reg_vec := mkvect 2;
  1421. c!:find_literal current_procedure; % For benefit of backtraces
  1422. %
  1423. % cope with fluid vars in an argument list by mapping the definition
  1424. % (de f (a B C d) body) B and C fluid
  1425. % onto
  1426. % (de f (a x y c) (prog (B C) (setq B x) (setq C y) (return body)))
  1427. % so that the fluids get bound by PROG.
  1428. %
  1429. current_args := args;
  1430. for each v in args do
  1431. if v = '!&optional or v = '!&rest then
  1432. error(0, "&optional and &rest not supported by this compiler (yet)")
  1433. else if globalp v then begin scalar oo;
  1434. oo := wrs nil;
  1435. princ "+++++ "; prin v;
  1436. princ " converted from GLOBAL to FLUID"; terpri();
  1437. wrs oo;
  1438. unglobal list v;
  1439. fluid list v;
  1440. n := (v . c!:my_gensym()) . n end
  1441. else if fluidp v then n := (v . c!:my_gensym()) . n;
  1442. restart_label := c!:my_gensym();
  1443. body := list('c!:private_tagbody, restart_label, body);
  1444. if n then <<
  1445. body := list list('return, body);
  1446. args := subla(n, args);
  1447. for each v in n do
  1448. body := list('setq, car v, cdr v) . body;
  1449. body := 'prog . (for each v in reverse n collect car v) . body >>;
  1450. n := length args;
  1451. if n = 0 or n >= 3 then w := t else w := nil;
  1452. if w or i_machine = 4 then off_env := 8 else off_env := 4;
  1453. % Here I FUDDGE the issue of args passed in registers by flushing them
  1454. % back to the stack. I guess I will need to repair the stack to
  1455. % compensate somewhere too...
  1456. retloc := 0;
  1457. if i_machine = 2 then <<
  1458. if n = 1 then << i!:gopcode(push,edx, push,eax); retloc := 2 >>
  1459. else if n = 2 then << i!:gopcode(push,ebx, push,edx, push,eax); retloc := 3 >> >>
  1460. else if i_machine = 3 then <<
  1461. if n = 1 or n = 2 then i!:gopcode(push, edx, push, ecx);
  1462. retloc := 2 >>;
  1463. if i_machine = 4 then <<
  1464. if w then stackoffs := 16 else stackoffs := 12 >>
  1465. else if i_machine = 3 then <<
  1466. if w then stackoffs := 16 else stackoffs := 8 >>
  1467. else if i_machine = 2 then <<
  1468. if w then stackoffs := 12 else stackoffs := 8 >>
  1469. else error(0, "unknown machine");
  1470. n := 0;
  1471. env := nil;
  1472. for each x in args do begin
  1473. scalar aa;
  1474. n := n+1;
  1475. if n = retloc then stackoffs := stackoffs+4;
  1476. aa := c!:my_gensym();
  1477. env := (x . aa) . env;
  1478. registers := aa . registers;
  1479. args1 := aa . args1;
  1480. put(aa, 'i!:locoffs, stackoffs);
  1481. stackoffs := stackoffs + 4
  1482. end;
  1483. c!:startblock (entrypoint := c!:my_gensym());
  1484. exitpoint := current_block;
  1485. c!:endblock('goto, list list c!:cval(body, env . nil));
  1486. c!:optimise_flowgraph(entrypoint, all_blocks, env,
  1487. length args . current_procedure, args1);
  1488. env_vec := mkvect(length literal_vector - 1);
  1489. i := 0;
  1490. for each v in literal_vector do <<
  1491. putv(env_vec, i, v);
  1492. i := i + 1 >>;
  1493. if !*genlisting then <<
  1494. terpri();
  1495. ttab 28;
  1496. princ "+++ Native code for ";
  1497. prin current_procedure;
  1498. printc " +++" >>;
  1499. i := i_resolve();
  1500. symbol!-set!-native(current_procedure, length args,
  1501. car i, cdr i,
  1502. env_vec);
  1503. return nil
  1504. end;
  1505. % c!:ccompile1 directs the compilation of a single function, and bind all the
  1506. % major fluids used by the compilation process
  1507. flag('(rds deflist flag fluid global
  1508. remprop remflag unfluid
  1509. unglobal dm carcheck i86!-end), 'eval);
  1510. flag('(rds), 'ignore);
  1511. fluid '(!*backtrace);
  1512. symbolic procedure c!:ccompilesupervisor;
  1513. begin
  1514. scalar u, w;
  1515. top:u := errorset('(read), t, !*backtrace);
  1516. if atom u then return; % failed, or maybe EOF
  1517. u := car u;
  1518. if u = !$eof!$ then return; % end of file
  1519. if atom u then go to top
  1520. % the apply('i86!-end, nil) is here because i86!-end has a "stat"
  1521. % property and so it will mis-parse if I just write "i86!-end()". Yuk.
  1522. else if eqcar(u, 'i86!-end) then return apply('i86!-end, nil)
  1523. else if eqcar(u, 'rdf) then <<
  1524. !#if common!-lisp!-mode
  1525. w := open(u := eval cadr u, !:direction, !:input,
  1526. !:if!-does!-not!-exist, nil);
  1527. !#else
  1528. w := open(u := eval cadr u, 'input);
  1529. !#endif
  1530. if w then <<
  1531. terpri();
  1532. princ "Reading file "; print u;
  1533. w := rds w;
  1534. c!:ccompilesupervisor();
  1535. princ "End of file "; print u;
  1536. close rds w >>
  1537. else << princ "Failed to open file "; print u >> >>
  1538. else c!:ccmpout1 u;
  1539. go to top
  1540. end;
  1541. global '(c!:char_mappings);
  1542. c!:char_mappings := '(
  1543. (! . !A) (!! . !B) (!# . !C) (!$ . !D)
  1544. (!% . !E) (!^ . !F) (!& . !G) (!* . !H)
  1545. (!( . !I) (!) . !J) (!- . !K) (!+ . !L)
  1546. (!= . !M) (!\ . !N) (!| . !O) (!, . !P)
  1547. (!. . !Q) (!< . !R) (!> . !S) (!: . !T)
  1548. (!; . !U) (!/ . !V) (!? . !W) (!~ . !X)
  1549. (!` . !Y));
  1550. symbolic procedure c!:inv_name n;
  1551. begin
  1552. scalar r, w;
  1553. r := '(_ !C !C !");
  1554. !#if common!-lisp!-mode
  1555. for each c in explode2 package!-name symbol!-package n do <<
  1556. if c = '_ then r := '_ . r
  1557. else if alpha!-char!-p c or digit c then r := c . r
  1558. else if w := atsoc(c, c!:char_mappings) then r := cdr w . r
  1559. else r := '!Z . r >>;
  1560. r := '!_ . '!_ . r;
  1561. !#endif
  1562. for each c in explode2 n do <<
  1563. if c = '_ then r := '_ . r
  1564. !#if common!-lisp!-mode
  1565. else if alpha!-char!-p c or digit c then r := c . r
  1566. !#else
  1567. else if liter c or digit c then r := c . r
  1568. !#endif
  1569. else if w := atsoc(c, c!:char_mappings) then r := cdr w . r
  1570. else r := '!Z . r >>;
  1571. r := '!" . r;
  1572. !#if common!-lisp!-mode
  1573. return compress1 reverse r
  1574. !#else
  1575. return compress reverse r
  1576. !#endif
  1577. end;
  1578. fluid '(defnames);
  1579. symbolic procedure c!:ccmpout1 u;
  1580. begin
  1581. scalar w;
  1582. if atom u then return nil
  1583. else if eqcar(u, 'progn) then <<
  1584. for each v in cdr u do codesize := codesize + c!:ccmpout1 v;
  1585. return nil >>
  1586. else if eqcar(u, 'i86!-end) then nil
  1587. else if flagp(car u, 'eval) or
  1588. (car u = 'setq and not atom caddr u and flagp(caaddr u, 'eval)) then
  1589. errorset(u, t, !*backtrace);
  1590. if eqcar(u, 'rdf) then begin
  1591. !#if common!-lisp!-mode
  1592. w := open(u := eval cadr u, !:direction, !:input,
  1593. !:if!-does!_not!-exist, nil);
  1594. !#else
  1595. w := open(u := eval cadr u, 'input);
  1596. !#endif
  1597. if w then <<
  1598. princ "Reading file "; print u;
  1599. w := rds w;
  1600. c!:ccompilesupervisor();
  1601. princ "End of file "; print u;
  1602. close rds w >>
  1603. else << princ "Failed to open file "; print u >> end
  1604. !#if common!-lisp!-mode
  1605. else if eqcar(u, 'defun) then return c!:ccmpout1 macroexpand u
  1606. !#endif
  1607. else if eqcar(u, 'de) then <<
  1608. u := cdr u;
  1609. !#if common!-lisp!-mode
  1610. w := compress1 ('!" . append(explodec package!-name
  1611. symbol!-package car u,
  1612. '!@ . '!@ . append(explodec symbol!-name car u,
  1613. append(explodec "@@Builtin", '(!")))));
  1614. w := intern w;
  1615. defnames := list(car u, c!:inv_name car u, length cadr u, w) . defnames;
  1616. !#else
  1617. defnames := list(car u, c!:inv_name car u, length cadr u) . defnames;
  1618. !#endif
  1619. if posn() neq 0 then terpri();
  1620. princ "Compiling "; prin caar defnames; princ " ... ";
  1621. c!:cfndef(caar defnames, cadar defnames, cadr u, 'progn . cddr u);
  1622. terpri() >>;
  1623. return nil;
  1624. end;
  1625. fluid '(!*defn dfprint!* dfprintsave);
  1626. !#if common!-lisp!-mode
  1627. symbolic procedure c!:concat(a, b);
  1628. compress1('!" . append(explode2 a, append(explode2 b, '(!"))));
  1629. !#else
  1630. symbolic procedure c!:concat(a, b);
  1631. compress('!" . append(explode2 a, append(explode2 b, '(!"))));
  1632. !#endif
  1633. symbolic procedure c!:ccompilestart name;
  1634. defnames := nil;
  1635. symbolic procedure i86!-end;
  1636. <<
  1637. !*defn := nil;
  1638. dfprint!* := dfprintsave
  1639. >>;
  1640. put('i86!-end, 'stat, 'endstat);
  1641. symbolic procedure i86!-begin u;
  1642. begin
  1643. terpri();
  1644. princ "IN files; or type in expressions"; terpri();
  1645. princ "When all done, execute i86!-END;"; terpri();
  1646. verbos nil;
  1647. defnames := nil;
  1648. dfprintsave := dfprint!*;
  1649. dfprint!* := 'c!:ccmpout1;
  1650. !*defn := t;
  1651. if getd 'begin then return nil;
  1652. return c!:ccompilesupervisor()
  1653. % There is a problem with compilesupervisor at the moment, so this way the
  1654. % function does not return code size.
  1655. end;
  1656. put('i86!-begin, 'stat, 'rlis);
  1657. symbolic procedure i86!-compile u;
  1658. begin
  1659. defnames := nil; % but subsequently ignored!
  1660. c!:ccmpout1 u;
  1661. end;
  1662. %
  1663. % Global treatment of a flow-graph...
  1664. %
  1665. symbolic procedure c!:print_opcode(s, depth);
  1666. begin
  1667. scalar op, r1, r2, r3, helper;
  1668. op := car s; r1 := cadr s; r2 := caddr s; r3 := cadddr s;
  1669. helper := get(op, 'c!:opcode_printer);
  1670. if helper then funcall(helper, op, r1, r2, r3, depth)
  1671. else << prin s; terpri() >>
  1672. end;
  1673. symbolic procedure c!:print_exit_condition(why, where_to, depth);
  1674. begin
  1675. scalar helper, lab1, drop1, lab2, drop2, negate, jmptype, args,
  1676. nargs, iflab1, iflab2, lab_end, pops;
  1677. % An exit condition is one of
  1678. % goto (lab)
  1679. % goto ((return-register))
  1680. % (ifnull v) (lab1 lab2) ) etc, where v is a register and
  1681. % (ifatom v) (lab1 lab2) ) lab1, lab2 are labels for true & false
  1682. % (ifeq v1 v2) (lab1 lab2) ) and various predicates are supported
  1683. % ((call fn) a1 a2) () tail-call to given function
  1684. %
  1685. if why = 'goto then <<
  1686. where_to := car where_to;
  1687. if atom where_to then <<
  1688. i!:gopcode(jmp, where_to);
  1689. c!:display_flowgraph(where_to, depth, t) >>
  1690. else <<
  1691. c!:pgoto(nil, where_to, depth) >>;
  1692. return nil >>
  1693. else if eqcar(car why, 'call) then return begin
  1694. scalar locs, g, w;
  1695. nargs := length cdr why;
  1696. <<
  1697. for each a in cdr why do
  1698. if flagp(a, 'c!:live_across_call) then <<
  1699. g := c!:my_gensym();
  1700. args := g . args >>
  1701. else args := a . args;
  1702. i!:gopcode(push, esi);
  1703. % The next line is a HORRID fudge to keep ebx safe when it was going to be
  1704. % used by the calling standard. Ugh
  1705. if i_machine = 2 and length cdr why = 2 then i!:gopcode(push,ebx);
  1706. for each a in reverse(cdr why) do
  1707. if flagp(a, 'c!:live_across_call) then
  1708. i!:gopcode(push,{ebx,-get(a, 'c!:location)*4})
  1709. else i!:gopcode(push, a);
  1710. c!:pld_eltenv(c!:find_literal cadar why);
  1711. % Compute qenv(fn) and put into edx
  1712. i!:gopcode(mov,edx,{eax,4});
  1713. % See further comments for the similar construction in c!:pcall
  1714. if nargs = 1 then i!:gopcode(mov,esi,{eax,8})
  1715. else if nargs = 2 then i!:gopcode(mov,esi,{eax,12})
  1716. else <<
  1717. i!:gopcode(mov,esi,{eax,16});
  1718. i!:gopcode(push, nargs);
  1719. nargs := nargs + 1
  1720. >>;
  1721. i!:gopcode(push,edx);
  1722. % Here I adapt (CRUDELY) for possibly different calling machanisms
  1723. pops := 4*(nargs+1);
  1724. print list(i_machine, nargs, pops, 'tailcall);
  1725. if i_machine = 2 and (pops = 8 or pops = 12) then <<
  1726. i!:gopcode(pop,eax, pop,edx); pops := pops-8;
  1727. if pops = 4 then << i!:gopcode(pop,ebx); pops := pops-4 >> >>
  1728. else if i_machine = 3 and (pops = 8 or pops = 12) then <<
  1729. i!:gopcode(pop,ecx, pop,edx); pops := pops-8 >>;
  1730. i!:gopcode(call,esi);
  1731. if pops neq 0 then i!:gopcode(add,esp,pops);
  1732. % The next line is a HORRID fudge to keep ebx safe when it was going to be
  1733. % used by the calling standard. Ugh
  1734. if i_machine = 2 and length cdr why = 2 then i!:gopcode(pop,ebx);
  1735. i!:gopcode(pop, esi);
  1736. if depth neq 0 then c!:ppopv(depth);
  1737. i!:gopcode(jmp,lab_end_proc)
  1738. >>;
  1739. return nil end;
  1740. lab1 := car where_to;
  1741. drop1 := atom lab1 and not flagp(lab1, 'c!:visited);
  1742. lab2 := cadr where_to;
  1743. drop2 := atom lab2 and not flagp(drop2, 'c!:visited);
  1744. if drop2 and get(lab2, 'c!:count) = 1 then <<
  1745. where_to := list(lab2, lab1);
  1746. drop1 := t >>
  1747. else if drop1 then negate := t;
  1748. helper := get(car why, 'c!:exit_helper);
  1749. if null helper then error(0, list("Bad exit condition", why));
  1750. %! Left for testing purposes and should be removed later ------
  1751. if not atom(car where_to) then
  1752. % In this case it is implied that we should generate not just a jump, but
  1753. % a piece of code which is executed if the condition is satisfied.
  1754. iflab1 := c!:my_gensym();
  1755. if not atom(cadr where_to) then iflab2 := c!:my_gensym();
  1756. jmptype := funcall(helper, cdr why, negate);
  1757. if not drop1 then <<
  1758. if not iflab1 then c!:pgoto(jmptype, car where_to, depth)
  1759. else i!:gopcode(jmptype, iflab1);
  1760. if not iflab2 then c!:pgoto('jmp, cadr where_to, depth)
  1761. else i!:gopcode(jmp, iflab2)
  1762. >>
  1763. else
  1764. if not iflab2 then c!:pgoto(jmptype, cadr where_to, depth)
  1765. else <<
  1766. i!:gopcode(jmptype,iflab2);
  1767. lab_end := c!:my_gensym();
  1768. i!:gopcode(jmp,lab_end) >>;
  1769. if iflab1 then <<
  1770. i!:gopcode('!:,iflab1);
  1771. c!:pgoto(jmptype, car where_to, depth) >>;
  1772. if iflab2 then <<
  1773. i!:gopcode('!:,iflab2);
  1774. c!:pgoto(jmptype, cadr where_to, depth) >>;
  1775. if lab_end then i!:gopcode('!:,lab_end);
  1776. if atom car where_to then c!:display_flowgraph(car where_to, depth, drop1);
  1777. if atom cadr where_to then c!:display_flowgraph(cadr where_to, depth, nil)
  1778. end;
  1779. %-----------------------------------------------------------------------------
  1780. % There are certain conventions about locations of some variables:
  1781. % 1. I assume the address of current stack top is residing in ebx permanently;
  1782. % *OOGGGUMPHHH*. On Linux ebx is perserved across procedure calls and so
  1783. % this use of it as a "register variable" is OK, but on Watcom it gets
  1784. % used in some procedure calls and potentially clobbered on any. Oh dear!
  1785. % 2. nil is always the first local variable of any function, thus it is referred
  1786. % everywhere as [ebp-4]
  1787. % 3. env is always the first formal parameter of any function, thus it is
  1788. % referred everywhere as [ebp+off_env]
  1789. % 4. nargs (if exists at all) is always the second formal parameter of any
  1790. % function, thus it is referred everywhere as [ebp+off_nargs]
  1791. symbolic procedure c!:pmovr(op, r1, r2, r3, depth);
  1792. <<
  1793. if flagp(r3, 'c!:live_across_call) then
  1794. i!:gopcode(mov, eax, {ebx,-4*get(r3, 'c!:location)})
  1795. else i!:gopcode(mov, eax, r3);
  1796. if flagp(r1, 'c!:live_across_call) then
  1797. i!:gopcode(mov, {ebx,-4*get(r1, 'c!:location)},eax)
  1798. else i!:gopcode(mov, r1, eax)
  1799. >>;
  1800. put('movr, ' c!:opcode_printer, function c!:pmovr);
  1801. symbolic procedure c!:pld_eltenv(elno);
  1802. <<
  1803. % #define elt(v, n) (*(Lisp_Object *)((char *)(v)-2+(((int32)(n))<<2)))
  1804. i!:gopcode(mov, edx,{ebp,off_env});
  1805. i!:gopcode(mov, eax,{edx,4*elno-2})
  1806. >>;
  1807. symbolic procedure c!:pst_eltenv(elno);
  1808. <<
  1809. i!:gopcode(mov, edx,{ebp,off_env});
  1810. i!:gopcode(mov, {edx,4*elno-2},eax)
  1811. >>;
  1812. symbolic procedure c!:pld_qvaleltenv(elno);
  1813. <<
  1814. % #define qvalue(p) (*(Lisp_Object *)(p))
  1815. c!:pld_eltenv(elno);
  1816. i!:gopcode(mov, eax, {eax});
  1817. >>;
  1818. symbolic procedure c!:pst_qvaleltenv(elno);
  1819. <<
  1820. i!:gopcode(mov, edx,{ebp,off_env});
  1821. i!:gopcode(mov, ecx,{edx,4*elno-2});
  1822. i!:gopcode(mov, {ecx},eax);
  1823. >>;
  1824. symbolic procedure c!:pmovk(op, r1, r2, r3, depth);
  1825. <<
  1826. c!:pld_eltenv(r3);
  1827. i!:gopcode(mov, r1,eax)
  1828. >>;
  1829. put('movk, 'c!:opcode_printer, function c!:pmovk);
  1830. symbolic procedure c!:pmovk1(op, r1, r2, r3, depth);
  1831. if null r3 then <<
  1832. i!:gopcode(mov, eax, {ebp,-4});
  1833. i!:gopcode(mov, r1, eax)
  1834. >>
  1835. else if r3 = 't then <<
  1836. i!:gopcode(mov, eax, 'lisp_true);
  1837. i!:gopcode(mov, r1, eax)
  1838. >>
  1839. else <<
  1840. i!:gopcode(mov, eax, 16*r3+1);
  1841. i!:gopcode(mov, r1, eax)
  1842. >>;
  1843. put('movk1, 'c!:opcode_printer, function c!:pmovk1);
  1844. procedure c!:preloadenv(op, r1, r2, r3, depth);
  1845. % will not be encountered unless reloadenv variable has been set up.
  1846. <<
  1847. i!:gopcode(mov, ecx,{ebx,-reloadenv*4});
  1848. i!:gopcode(mov, {ebp,off_env},ecx)
  1849. >>;
  1850. put('reloadenv, 'c!:opcode_printer, function c!:preloadenv);
  1851. symbolic procedure c!:pldrglob(op, r1, r2, r3, depth);
  1852. <<
  1853. c!:pld_qvaleltenv(r3);
  1854. i!:gopcode(mov, r1,eax)
  1855. >>;
  1856. put('ldrglob, 'c!:opcode_printer, function c!:pldrglob);
  1857. symbolic procedure c!:pstrglob(op, r1, r2, r3, depth);
  1858. <<
  1859. i!:gopcode(mov, eax,r1);
  1860. c!:pst_qvaleltenv(r3)
  1861. >>;
  1862. put('strglob, 'c!:opcode_printer, function c!:pstrglob);
  1863. symbolic procedure c!:pnilglob(op, r1, r2, r3, depth);
  1864. <<
  1865. i!:gopcode(mov, eax, {ebp,-4});
  1866. c!:pst_qvaleltenv(r3)
  1867. >>;
  1868. put('nilglob, 'c!:opcode_printer, function c!:pnilglob);
  1869. symbolic procedure c!:pgentornil(condtype, dest);
  1870. begin
  1871. scalar condjmp, lab1, lab2;
  1872. if condtype = 'eq then condjmp := 'jne
  1873. else if condtype = 'neq then condjmp := 'je
  1874. else if condtype = '< then condjmp := 'jge
  1875. else if condtype = '> then condjmp := 'jle;
  1876. lab1 := c!:my_gensym();
  1877. lab2 := c!:my_gensym();
  1878. i!:gopcode(condjmp, lab1);
  1879. i!:gopcode(mov,eax,'lisp_true, jmp,lab2);
  1880. i!:gopcode('!:,lab1, mov,eax,{ebp,-4});
  1881. i!:gopcode('!:,lab2, mov,dest,eax)
  1882. end;
  1883. symbolic procedure c!:pnull(op, r1, r2, r3, depth);
  1884. <<
  1885. i!:gopcode(mov,eax,r3);
  1886. i!:gopcode(cmp,eax,{ebp,-4});
  1887. c!:pgentornil('eq, r1)
  1888. >>;
  1889. put('null, 'c!:opcode_printer, function c!:pnull);
  1890. put('not, 'c!:opcode_printer, function c!:pnull);
  1891. symbolic procedure c!:pfastget(op, r1, r2, r3, depth);
  1892. begin
  1893. scalar lab1,lab_end;
  1894. lab1 := c!:my_gensym(); lab_end := c!:my_gensym();
  1895. i!:gopcode(mov,eax,r2);
  1896. i!:gopcode(and,eax,TAG_BITS, cmp,eax,TAG_SYMBOL, je,lab1);
  1897. i!:gopcode(mov,eax,{ebp,-4}, jmp,lab_end);
  1898. i!:gopcode('!:,lab1);
  1899. i!:gopcode(mov,eax,r2, mov,eax,{eax,28}, cmp,eax,{ebp,-4}, je,lab_end);
  1900. i!:gopcode(mov,eax,{eax,4*(car r3)-2});
  1901. i!:gopcode(cmp,eax,SPID_NOPROP, jne,lab_end, mov,eax,{ebp,-4});
  1902. i!:gopcode('!:,lab_end, mov,r1,eax)
  1903. end;
  1904. put('fastget, 'c!:opcode_printer, function c!:pfastget);
  1905. flag('(fastget), 'c!:uses_nil);
  1906. symbolic procedure c!:pfastflag(op, r1, r2, r3, depth);
  1907. begin
  1908. scalar lab1, lab2, lab_end;
  1909. lab1 := c!:my_gensym(); lab2 := c!:my_gensym(); lab_end := c!:my_gensym();
  1910. i!:gopcode(mov,eax,r2);
  1911. i!:gopcode(and,eax,TAG_BITS, cmp,eax,TAG_SYMBOL, je,lab1);
  1912. i!:gopcode(mov,eax,{ebp,-4}, jmp,lab_end);
  1913. i!:gopcode('!:,lab1);
  1914. i!:gopcode(mov,eax,r2, mov,eax,{eax,28}, cmp,eax,{ebp,-4}, je,lab_end);
  1915. i!:gopcode(mov,eax,{eax,4*(car r3)-2});
  1916. i!:gopcode(cmp,eax,SPID_NOPROP, je,lab2, mov,eax,'lisp_true, jmp,lab_end);
  1917. i!:gopcode('!:,lab2, mov,eax,{ebp,-4});
  1918. i!:gopcode('!:,lab_end, mov,r1,eax)
  1919. end;
  1920. put('fastflag, 'c!:opcode_printer, function c!:pfastflag);
  1921. flag('(fastflag), 'c!:uses_nil);
  1922. symbolic procedure c!:pcar(op, r1, r2, r3, depth);
  1923. begin
  1924. if not !*unsafecar then <<
  1925. c!:pgoto(nil, c!:find_error_label(list('car, r3), r2, depth), depth);
  1926. % #define car_legal(p) is_cons(p)
  1927. % #define is_cons(p) ((((int)(p)) & TAG_BITS) == TAG_CONS)
  1928. % TAG_CONS = 0
  1929. i!:gopcode(mov,eax,r3, test,eax,TAG_BITS);
  1930. c!:pgoto('jne, c!:find_error_label(list('car, r3), r2, depth), depth)
  1931. >>;
  1932. c!:pqcar(op, r1, r2, r3, depth)
  1933. end;
  1934. put('car, 'c!:opcode_printer, function c!:pcar);
  1935. symbolic procedure c!:pcdr(op, r1, r2, r3, depth);
  1936. begin
  1937. if not !*unsafecar then <<
  1938. c!:pgoto(nil, c!:find_error_label(list('cdr, r3), r2, depth), depth);
  1939. i!:gopcode(mov,eax,r3, test,eax,TAG_BITS);
  1940. c!:pgoto('jne, c!:find_error_label(list('cdr, r3), r2, depth), depth)
  1941. >>;
  1942. c!:pqcdr(op, r1, r2, r3, depth)
  1943. end;
  1944. put('cdr, 'c!:opcode_printer, function c!:pcdr);
  1945. symbolic procedure c!:pqcar(op, r1, r2, r3, depth);
  1946. <<
  1947. i!:gopcode(mov,eax,r3);
  1948. i!:gopcode(mov,eax,{eax}, mov,r1,eax)
  1949. >>;
  1950. put('qcar, 'c!:opcode_printer, function c!:pqcar);
  1951. symbolic procedure c!:pqcdr(op, r1, r2, r3, depth);
  1952. <<
  1953. i!:gopcode(mov,eax,r3);
  1954. i!:gopcode(mov,eax,{eax,4}, mov,r1,eax)
  1955. >>;
  1956. put('qcdr, 'c!:opcode_printer, function c!:pqcdr);
  1957. symbolic procedure c!:patom(op, r1, r2, r3, depth);
  1958. <<
  1959. i!:gopcode(mov,eax,r3, test,eax,TAG_BITS);
  1960. c!:pgentornil('neq, r1);
  1961. >>;
  1962. put('atom, 'c!:opcode_printer, function c!:patom);
  1963. symbolic procedure c!:pnumberp(op, r1, r2, r3, depth);
  1964. <<
  1965. i!:gopcode(mov,eax,r3, test,eax,1);
  1966. c!:pgentornil('neq, r1)
  1967. >>;
  1968. put('numberp, 'c!:opcode_printer, function c!:pnumberp);
  1969. symbolic procedure c!:pfixp(op, r1, r2, r3, depth);
  1970. <<
  1971. c!:pgencall('integerp, {"nil",r3}, r1)
  1972. >>;
  1973. put('fixp, 'c!:opcode_printer, function c!:pfixp);
  1974. symbolic procedure c!:piminusp(op, r1, r2, r3, depth);
  1975. <<
  1976. i!:gopcode(mov,eax,r3, test,eax,eax);
  1977. c!:pgentornil('<, r1)
  1978. >>;
  1979. put('iminusp, 'c!:opcode_printer, function c!:piminusp);
  1980. symbolic procedure c!:pilessp(op, r1, r2, r3, depth);
  1981. <<
  1982. i!:gopcode(mov,eax,r2, cmp,eax,r3);
  1983. c!:pgentornil('<, r1)
  1984. >>;
  1985. put('ilessp, 'c!:opcode_printer, function c!:pilessp);
  1986. symbolic procedure c!:pigreaterp(op, r1, r2, r3, depth);
  1987. <<
  1988. i!:gopcode(mov,eax,r2, cmp,eax,r3);
  1989. c!:pgentornil('>, r1)
  1990. >>;
  1991. put('igreaterp, 'c!:opcode_printer, function c!:pigreaterp);
  1992. symbolic procedure c!:piminus(op, r1, r2, r3, depth);
  1993. <<
  1994. i!:gopcode(mov,eax,2, sub,eax,r3);
  1995. i!:gopcode(mov, r1, eax)
  1996. >>;
  1997. put('iminus, 'c!:opcode_printer, function c!:piminus);
  1998. symbolic procedure c!:piadd1(op, r1, r2, r3, depth);
  1999. <<
  2000. i!:gopcode(mov, eax, r3);
  2001. i!:gopcode(add,eax,0x10, mov,r1,eax)
  2002. >>;
  2003. put('iadd1, 'c!:opcode_printer, function c!:piadd1);
  2004. symbolic procedure c!:pisub1(op, r1, r2, r3, depth);
  2005. <<
  2006. i!:gopcode(mov, eax, r3);
  2007. i!:gopcode(sub,eax,0x10, mov,r1,eax)
  2008. >>;
  2009. put('isub1, 'c!:opcode_printer, function c!:pisub1);
  2010. symbolic procedure c!:piplus2(op, r1, r2, r3, depth);
  2011. <<
  2012. i!:gopcode(mov,eax,r2, add,eax,r3);
  2013. i!:gopcode(sub,eax,TAG_FIXNUM, mov,r1,eax)
  2014. >>;
  2015. put('iplus2, 'c!:opcode_printer, function c!:piplus2);
  2016. symbolic procedure c!:pidifference(op, r1, r2, r3, depth);
  2017. <<
  2018. i!:gopcode(mov,eax,r2, sub,eax,r3);
  2019. i!:gopcode(add,eax,TAG_FIXNUM, mov,r1,eax)
  2020. >>;
  2021. put('idifference, 'c!:opcode_printer, function c!:pidifference);
  2022. symbolic procedure c!:pitimes2(op, r1, r2, r3, depth);
  2023. <<
  2024. i!:gopcode(mov,eax,r2, shr,eax,4);
  2025. i!:gopcode(mov,edx,r3, shr,edx,4);
  2026. i!:gopcode(mul,eax,edx, shl,eax,4, add,eax,TAG_FIXNUM);
  2027. i!:gopcode(mov, r1, eax);
  2028. >>;
  2029. put('itimes2, 'c!:opcode_printer, function c!:pitimes2);
  2030. symbolic procedure c!:pmodular_plus(op, r1, r2, r3, depth);
  2031. begin
  2032. scalar lab1;
  2033. lab1 := c!:my_gensym();
  2034. i!:gopcode(mov,eax,r2, shr,eax,4);
  2035. i!:gopcode(mov,edx,r3, shr,edx,4);
  2036. i!:gopcode(add,eax,edx, cmp,eax,'current_modulus, jl,lab1);
  2037. i!:gopcode(sub, eax, 'current_modulus);
  2038. i!:gopcode('!:,lab1, shl,eax,4, add,eax,TAG_FIXNUM, mov,r1,eax)
  2039. end;
  2040. put('modular!-plus, 'c!:opcode_printer, function c!:pmodular_plus);
  2041. symbolic procedure c!:pmodular_difference(op, r1, r2, r3, depth);
  2042. begin
  2043. scalar lab1;
  2044. lab1 := c!:my_gensym();
  2045. i!:gopcode(mov,eax,r2, shr,eax,4);
  2046. i!:gopcode(mov,edx,r3, shr,edx,4);
  2047. i!:gopcode(sub,eax,edx, test,eax,eax, jge,lab1);
  2048. i!:gopcode(add,eax,'current_modulus);
  2049. i!:gopcode('!:,lab1, shl,eax,4, add,eax,TAG_FIXNUM, mov,r1,eax)
  2050. end;
  2051. put('modular!-difference, 'c!:opcode_printer, function c!:pmodular_difference);
  2052. symbolic procedure c!:pmodular_minus(op, r1, r2, r3, depth);
  2053. begin
  2054. scalar lab1;
  2055. lab1 := c!:my_gensym();
  2056. i!:gopcode(mov,eax,r3, shr,eax,4);
  2057. i!:gopcode(test,eax,eax, je,lab1);
  2058. i!:gopcode(sub,eax,'current_modulus, neg,eax);
  2059. i!:gopcode('!:,lab1, shl,eax,4, add,eax,TAG_FIXNUM, mov,r1,eax)
  2060. end;
  2061. put('modular!-minus, 'c!:opcode_printer, function c!:pmodular_minus);
  2062. !#if (not common!-lisp!-mode)
  2063. symbolic procedure c!:passoc(op, r1, r2, r3, depth);
  2064. <<
  2065. c!:pgencall('assoc, list("nil", r2, r3), r1)
  2066. >>;
  2067. put('assoc, 'c!:opcode_printer, function c!:passoc);
  2068. flag('(assoc), 'c!:uses_nil);
  2069. !#endif
  2070. symbolic procedure c!:patsoc(op, r1, r2, r3, depth);
  2071. <<
  2072. c!:pgencall('atsoc, list("nil", r2, r3), r1)
  2073. >>;
  2074. put('atsoc, 'c!:opcode_printer, function c!:patsoc);
  2075. flag('(atsoc), 'c!:uses_nil);
  2076. !#if (not common!-lisp!-mode)
  2077. symbolic procedure c!:pmember(op, r1, r2, r3, depth);
  2078. <<
  2079. c!:pgencall('member, {"nil", r2, r3}, r1)
  2080. >>;
  2081. put('member, 'c!:opcode_printer, function c!:pmember);
  2082. flag('(member), 'c!:uses_nil);
  2083. !#endif
  2084. symbolic procedure c!:pmemq(op, r1, r2, r3, depth);
  2085. <<
  2086. c!:pgencall('memq, {"nil", r2, r3}, r1)
  2087. >>;
  2088. put('memq, 'c!:opcode_printer, function c!:pmemq);
  2089. flag('(memq), 'c!:uses_nil);
  2090. !#if common!-lisp!-mode
  2091. symbolic procedure c!:pget(op, r1, r2, r3, depth);
  2092. <<
  2093. c!:pgencall('get, {r2, r3, "nil"}, r1);
  2094. >>;
  2095. flag('(get), 'c!:uses_nil);
  2096. !#else
  2097. symbolic procedure c!:pget(op, r1, r2, r3, depth);
  2098. <<
  2099. c!:pgencall('get, list(r2, r3), r1);
  2100. >>;
  2101. !#endif
  2102. put('get, 'c!:opcode_printer, function c!:pget);
  2103. symbolic procedure c!:pgetv(op, r1, r2, r3, depth);
  2104. <<
  2105. i!:gopcode(mov,eax,r2, sub,eax,2);
  2106. i!:gopcode(mov,edx,r3, shr,edx,2, add,eax,edx);
  2107. i!:gopcode(mov,eax,{eax}, mov,r1,eax)
  2108. >>;
  2109. put('getv, 'c!:opcode_printer, function c!:pgetv);
  2110. symbolic procedure c!:pqputv(op, r1, r2, r3, depth);
  2111. <<
  2112. i!:gopcode(mov,eax,r2, sub,eax,2);
  2113. i!:gopcode(mov,edx,r3, shr,edx,2, add,edx,eax);
  2114. i!:gopcode(mov,eax,r1, mov,{edx},eax)
  2115. >>;
  2116. put('qputv, 'c!:opcode_printer, function c!:pqputv);
  2117. symbolic procedure c!:peq(op, r1, r2, r3, depth);
  2118. <<
  2119. i!:gopcode(mov,eax,r2, cmp,eax,r3);
  2120. c!:pgentornil('eq, r1)
  2121. >>;
  2122. put('eq, 'c!:opcode_printer, function c!:peq);
  2123. flag('(eq), 'c!:uses_nil);
  2124. symbolic procedure c!:pgenpequal(fname, args, res);
  2125. begin
  2126. scalar jmpinstr, lab1, lab2;
  2127. jmpinstr := c!:pgenequal(fname, args, nil);
  2128. % Jump instruction is issued for the case the condition is true
  2129. lab1 := c!:my_gensym();
  2130. lab2 := c!:my_gensym();
  2131. i!:gopcode(jmpinstr, lab1);
  2132. i!:gopcode(mov,eax,{ebp,-4}, jmp,lab2);
  2133. i!:gopcode('!:,lab1, mov,eax,'lisp_true);
  2134. i!:gopcode('!:,lab2, mov,res,eax)
  2135. end;
  2136. !#if common!-lisp!-mode
  2137. symbolic procedure c!:pequal(op, r1, r2, r3, depth);
  2138. <<
  2139. c!:pgenpequal('cl_equal_fn, list(r2, r3), r1);
  2140. >>;
  2141. !#else
  2142. symbolic procedure c!:pequal(op, r1, r2, r3, depth);
  2143. begin
  2144. c!:pgenpequal('equal_fn, list(r2, r3), r1)
  2145. end;
  2146. !#endif
  2147. put('equal, 'c!:opcode_printer, function c!:pequal);
  2148. flag('(equal), 'c!:uses_nil);
  2149. symbolic procedure c!:pfluidbind(op, r1, r2, r3, depth);
  2150. nil;
  2151. put('fluidbind, 'c!:opcode_printer, function c!:pfluidbind);
  2152. symbolic procedure c!:pgencall(addr, arglist, dest);
  2153. % Generate a call sequence.
  2154. begin
  2155. scalar reg, nargs, c_dir, pops;
  2156. if not (reg := get(addr,'i!:regcode)) then <<
  2157. nargs := length arglist;
  2158. if not atom car arglist then <<
  2159. % We encode (nil, actual no of args) or (env, actual no of args) this way
  2160. nargs := cadar arglist;
  2161. car arglist := caar arglist;
  2162. >>
  2163. else if (car arglist = 'env) or (car arglist = "nil") then
  2164. nargs := nargs - 1
  2165. else <<
  2166. % This is a direct C entrypoint or direct C predicate or one of special
  2167. % functions: reclaim, error, equal_fn, aerror which behave the same
  2168. % and for which we don't need to pass the number of args.
  2169. if (c_dir := get(addr, 'c!:direct_call_func)) then nargs := nil >>
  2170. >>;
  2171. % The next line is a HORRID fudge to keep ebx safe when it was going to be
  2172. % used by the calling standard. Ugh
  2173. if i_machine = 2 and length arglist = 3 then i!:gopcode(push,ebx);
  2174. % I have to reverse the order of parameters, since we use C call model
  2175. for each a in reverse arglist do i!:gopcode(push, a);
  2176. pops := 4*length arglist;
  2177. % Here I adapt (CRUDELY) for possibly different calling mechanisms
  2178. print list(i_machine, pops, 'call);
  2179. if i_machine = 2 and (pops = 8 or nargs = 12) then <<
  2180. i!:gopcode(pop,eax, pop,edx); pops := pops-8;
  2181. if pops = 4 then << i!:gopcode(pop,ebx); pops := pops-4 >> >>
  2182. else if i_machine = 3 and (pops = 8 or pops = 12) then <<
  2183. i!:gopcode(pop,ecx, pop,edx); pops := pops-8 >>;
  2184. if reg then i!:gopcode(call, addr)
  2185. else <<
  2186. i_putcomment list('call, addr, list nargs, c_dir);
  2187. i_putbyte 0xe8;
  2188. if c_dir then i_putextern list('rel_plus_4, c_dir)
  2189. else i_putextern list('rel_plus_4, list(addr, nargs)) >>;
  2190. if pops neq 0 then i!:gopcode(add, esp, pops);
  2191. % The next line is a HORRID fudge to keep ebx safe when it was going to be
  2192. % used by the calling standard. Ugh
  2193. if i_machine = 2 and length arglist = 3 then i!:gopcode(pop,ebx);
  2194. if dest neq nil then i!:gopcode(mov,dest,eax);
  2195. end;
  2196. symbolic procedure c!:pcall(op, r1, r2, r3, depth);
  2197. begin
  2198. % r3 is (name <fluids to unbind on error>)
  2199. scalar w, boolfn, nargs, lab1;
  2200. %-- if car r3 = current_procedure then <<
  2201. %-- nargs := length r2;
  2202. %-- if null r2 or nargs >= 3 then <<
  2203. %-- r2 := cons(nargs, r2);
  2204. %-- r2 := cons({'env, nargs}, r2) >>
  2205. %-- else r2 := cons('env, r2);
  2206. %-- c!:pgencall(car r3, r2, r1)
  2207. %-- >>
  2208. begin
  2209. nargs := length r2;
  2210. c!:pld_eltenv(c!:find_literal car r3);
  2211. % Compute qenv(fn) and put into edx
  2212. i!:gopcode(mov,edx,{eax,4});
  2213. r2 := cons('edx, r2);
  2214. if nargs = 1 then i!:gopcode(mov,ecx,{eax,8})
  2215. else if nargs = 2 then i!:gopcode(mov,ecx,{eax,12})
  2216. else <<
  2217. i!:gopcode(mov,ecx,{eax,16});
  2218. r2 := car r2 . nargs . cdr r2
  2219. >>;
  2220. c!:pgencall('ecx, r2, r1)
  2221. end;
  2222. if not flagp(car r3, 'c!:no_errors) then <<
  2223. if null cadr r3 and depth = 0 then <<
  2224. lab1 := c!:my_gensym();
  2225. i!:gopcode(mov,eax,'C_nil, mov,{ebp,-4},eax);
  2226. i!:gopcode(and,eax,1, je,lab1);
  2227. i!:gopcode(mov,eax,{ebp,-4}, jmp,lab_end_proc);
  2228. i!:gopcode('!:,lab1)
  2229. >>
  2230. else <<
  2231. i!:gopcode(mov,eax,'C_nil, mov,{ebp,-4},eax);
  2232. c!:pgoto(nil, c!:find_error_label(nil, cadr r3, depth), depth);
  2233. i!:gopcode(and,eax,1);
  2234. c!:pgoto('jne, c!:find_error_label(nil, cadr r3, depth), depth)
  2235. >>
  2236. >>;
  2237. if boolfn then <<
  2238. i!:gopcode(mov,eax,r1, test,eax,eax);
  2239. c!:pgentornil('neq, r1)
  2240. >>
  2241. end;
  2242. put('call, 'c!:opcode_printer, function c!:pcall);
  2243. symbolic procedure c!:ppopv(depth);
  2244. <<
  2245. i!:gopcode(sub,ebx,depth*4, mov,'stack,ebx)
  2246. >>;
  2247. symbolic procedure c!:pgoto(jmptype, lab, depth);
  2248. begin
  2249. if atom lab then <<
  2250. if jmptype neq nil then %! when test sup removed nil test not required
  2251. return i!:gopcode(jmptype, lab)
  2252. else return nil
  2253. >>;
  2254. lab := get(car lab, 'c!:chosen);
  2255. if zerop depth then <<
  2256. i!:gopcode(mov,eax,lab, jmp,lab_end_proc)
  2257. >>
  2258. else if flagp(lab, 'c!:live_across_call) then <<
  2259. i!:gopcode(mov, eax, {ebx, -get(lab, 'c!:location)*4});
  2260. c!:ppopv(depth);
  2261. i!:gopcode(jmp,lab_end_proc)
  2262. >>
  2263. else <<
  2264. c!:ppopv(depth);
  2265. i!:gopcode(mov,eax,lab, jmp,lab_end_proc)
  2266. >>
  2267. end;
  2268. symbolic procedure c!:pifnull(s, negate);
  2269. <<
  2270. i!:gopcode(mov, eax, car s);
  2271. i!:gopcode(cmp, eax, {ebp,-4});
  2272. if negate then 'jne
  2273. else 'je
  2274. >>;
  2275. put('ifnull, 'c!:exit_helper, function c!:pifnull);
  2276. symbolic procedure c!:pifatom(s, negate);
  2277. <<
  2278. i!:gopcode(mov,eax,car s, test,eax,TAG_BITS);
  2279. if negate then 'je
  2280. else 'jne
  2281. >>;
  2282. put('ifatom, 'c!:exit_helper, function c!:pifatom);
  2283. symbolic procedure c!:pifsymbol(s, negate);
  2284. <<
  2285. i!:gopcode(mov, eax, car s);
  2286. i!:gopcode(and,eax,TAG_BITS, cmp,eax,TAG_SYMBOL);
  2287. if negate then 'jne
  2288. else 'je
  2289. >>;
  2290. put('ifsymbol, 'c!:exit_helper, function c!:pifsymbol);
  2291. symbolic procedure c!:pifnumber(s, negate);
  2292. <<
  2293. i!:gopcode(mov,eax,car s, test,eax,1);
  2294. if negate then 'je
  2295. else 'jne
  2296. >>;
  2297. put('ifnumber, 'c!:exit_helper, function c!:pifnumber);
  2298. symbolic procedure c!:pifizerop(s, negate);
  2299. <<
  2300. i!:gopcode(mov,eax,car s, cmp,eax,1);
  2301. if negate then 'jne
  2302. else 'je
  2303. >>;
  2304. put('ifizerop, 'c!:exit_helper, function c!:pifizerop);
  2305. symbolic procedure c!:pifeq(s, negate);
  2306. <<
  2307. i!:gopcode(mov,eax,car s, cmp,eax,cadr s);
  2308. if negate then 'jne
  2309. else 'je
  2310. >>;
  2311. put('ifeq, 'c!:exit_helper, function c!:pifeq);
  2312. symbolic procedure c!:pgenequal(fname, args, negate);
  2313. % Perform the evaluation of the macro below, and issue a cond jump command so
  2314. % that jump is performed if the condition is satisfied. fname should be
  2315. % either equal_fn or cl_equal_fn, and this parameter is required only
  2316. % because of my desire to support both SL and CL at least here
  2317. begin
  2318. scalar lab_ok, lab_fail, lab_end;
  2319. % #define equal(a, b) \
  2320. % ((a) == (b) || \
  2321. % (((((a) ^ (b)) & TAG_BITS) == 0) && \
  2322. % ((unsigned)(((a) & TAG_BITS) - 1) > 3) && \
  2323. % equal_fn(a, b)))
  2324. lab_ok := c!:my_gensym(); lab_fail := c!:my_gensym(); lab_end := c!:my_gensym();
  2325. i!:gopcode(mov, ecx,car args);
  2326. i!:gopcode(mov, edx,cadr args);
  2327. i!:gopcode(cmp,ecx,edx, je,lab_ok);
  2328. i!:gopcode(mov,eax,ecx, xor,eax,edx, test,eax,7, jne,lab_fail);
  2329. i!:gopcode(mov,eax,ecx, and,eax,7, dec,eax);
  2330. i!:gopcode(cmp,eax,3, jbe,lab_fail);
  2331. c!:pgencall(fname,{'ecx,'edx},nil);
  2332. i!:gopcode(test,eax,eax, jne,lab_ok);
  2333. i!:gopcode('!:,lab_fail, xor,eax,eax, jmp,lab_end);
  2334. i!:gopcode('!:,lab_ok, mov,eax,1);
  2335. i!:gopcode('!:,lab_end, test,eax,eax);
  2336. if negate then return 'je
  2337. else return 'jne
  2338. end;
  2339. !#if common!-lisp!-mode
  2340. symbolic procedure c!:pifequal(s, negate);
  2341. c!:pgenequal('cl_equal_fn, s, negate);
  2342. !#else
  2343. symbolic procedure c!:pifequal(s, negate);
  2344. c!:pgenequal('equal_fn, s, negate);
  2345. !#endif
  2346. put('ifequal, 'c!:exit_helper, function c!:pifequal);
  2347. symbolic procedure c!:pifilessp(s, negate);
  2348. <<
  2349. i!:gopcode(mov,eax,car s, cmp,eax,cadr s);
  2350. if negate then 'jge
  2351. else 'jl >>;
  2352. put('ifilessp, 'c!:exit_helper, function c!:pifilessp);
  2353. symbolic procedure c!:pifigreaterp(s, negate);
  2354. <<
  2355. i!:gopcode(mov,eax,car s, cmp,eax,cadr s);
  2356. if negate then 'jle
  2357. else 'jg >>;
  2358. put('ifigreaterp, 'c!:exit_helper, function c!:pifigreaterp);
  2359. %------------------------------------------------------------------------------
  2360. symbolic procedure c!:display_flowgraph(s, depth, dropping_through);
  2361. if not atom s then <<
  2362. c!:pgoto(nil, s, depth) >>
  2363. else if not flagp(s, 'c!:visited) then begin
  2364. scalar why, where_to;
  2365. flag(list s, 'c!:visited);
  2366. if not dropping_through or not (get(s, 'c!:count) = 1) then
  2367. i!:gopcode('!:, s);
  2368. for each k in reverse get(s, 'c!:contents) do c!:print_opcode(k, depth);
  2369. why := get(s, 'c!:why);
  2370. where_to := get(s, 'c!:where_to);
  2371. if why = 'goto and (not atom car where_to or
  2372. (not flagp(car where_to, 'c!:visited) and
  2373. get(car where_to, 'c!:count) = 1)) then
  2374. c!:display_flowgraph(car where_to, depth, t)
  2375. else c!:print_exit_condition(why, where_to, depth)
  2376. end;
  2377. fluid '(startpoint);
  2378. symbolic procedure c!:branch_chain(s, count);
  2379. begin
  2380. scalar contents, why, where_to, n;
  2381. % do nothing to blocks already visted or return blocks.
  2382. if not atom s then return s
  2383. else if flagp(s, 'c!:visited) then <<
  2384. n := get(s, 'c!:count);
  2385. if null n then n := 1 else n := n + 1;
  2386. put(s, 'c!:count, n);
  2387. return s >>;
  2388. flag(list s, 'c!:visited);
  2389. contents := get(s, 'c!:contents);
  2390. why := get(s, 'c!:why);
  2391. where_to := for each z in get(s, 'c!:where_to) collect
  2392. c!:branch_chain(z, count);
  2393. % Turn movr a,b; return a; into return b;
  2394. while contents and eqcar(car contents, 'movr) and
  2395. why = 'goto and not atom car where_to and
  2396. caar where_to = cadr car contents do <<
  2397. where_to := list list cadddr car contents;
  2398. contents := cdr contents >>;
  2399. put(s, 'c!:contents, contents);
  2400. put(s, 'c!:where_to, where_to);
  2401. % discard empty blocks
  2402. if null contents and why = 'goto then <<
  2403. remflag(list s, 'c!:visited);
  2404. return car where_to >>;
  2405. if count then <<
  2406. n := get(s, 'c!:count);
  2407. if null n then n := 1
  2408. else n := n + 1;
  2409. put(s, 'c!:count, n) >>;
  2410. return s
  2411. end;
  2412. symbolic procedure c!:one_operand op;
  2413. << flag(list op, 'c!:set_r1);
  2414. flag(list op, 'c!:read_r3);
  2415. put(op, 'c!:code, function c!:builtin_one) >>;
  2416. symbolic procedure c!:two_operands op;
  2417. << flag(list op, 'c!:set_r1);
  2418. flag(list op, 'c!:read_r2);
  2419. flag(list op, 'c!:read_r3);
  2420. put(op, 'c!:code, function c!:builtin_two) >>;
  2421. for each n in '(car cdr qcar qcdr null not atom numberp fixp iminusp
  2422. iminus iadd1 isub1 modular!-minus) do c!:one_operand n;
  2423. !#if common!-lisp!-mode
  2424. for each n in '(eq equal atsoc memq iplus2 idifference
  2425. itimes2 ilessp igreaterp getv get
  2426. modular!-plus modular!-difference
  2427. ) do c!:two_operands n;
  2428. !#else
  2429. for each n in '(eq equal atsoc memq iplus2 idifference
  2430. assoc member
  2431. itimes2 ilessp igreaterp getv get
  2432. modular!-plus modular!-difference
  2433. ) do c!:two_operands n;
  2434. !#endif
  2435. flag('(movr movk movk1 ldrglob call reloadenv fastget fastflag), 'c!:set_r1);
  2436. flag('(strglob qputv), 'c!:read_r1);
  2437. flag('(qputv fastget fastflag), 'c!:read_r2);
  2438. flag('(movr qputv), 'c!:read_r3);
  2439. flag('(ldrglob strglob nilglob movk call), 'c!:read_env);
  2440. % special opcodes:
  2441. % call fluidbind
  2442. fluid '(fn_used nil_used nilbase_used);
  2443. symbolic procedure c!:live_variable_analysis all_blocks;
  2444. begin
  2445. scalar changed, z;
  2446. repeat <<
  2447. changed := nil;
  2448. for each b in all_blocks do
  2449. begin
  2450. scalar w, live;
  2451. for each x in get(b, 'c!:where_to) do
  2452. if atom x then live := union(live, get(x, 'c!:live))
  2453. else live := union(live, x);
  2454. w := get(b, 'c!:why);
  2455. if not atom w then <<
  2456. if eqcar(w, 'ifnull) or eqcar(w, 'ifequal) then nil_used := t;
  2457. live := union(live, cdr w);
  2458. if eqcar(car w, 'call) and
  2459. not (cadar w = current_procedure) then <<
  2460. fn_used := t; live := union('(env), live) >> >>;
  2461. for each s in get(b, 'c!:contents) do
  2462. begin % backwards over contents
  2463. scalar op, r1, r2, r3;
  2464. op := car s; r1 := cadr s; r2 := caddr s; r3 := cadddr s;
  2465. if op = 'movk1 then <<
  2466. if r3 = nil then nil_used := t
  2467. else if r3 = 't then nilbase_used := t >>
  2468. else if atom op and flagp(op, 'c!:uses_nil) then nil_used := t;
  2469. if flagp(op, 'c!:set_r1) then
  2470. !#if common!-lisp!-mode
  2471. if memq(r1, live) then live := remove(r1, live)
  2472. !#else
  2473. if memq(r1, live) then live := delete(r1, live)
  2474. !#endif
  2475. else if op = 'call then nil % Always needed
  2476. else op := 'nop;
  2477. if flagp(op, 'c!:read_r1) then live := union(live, list r1);
  2478. if flagp(op, 'c!:read_r2) then live := union(live, list r2);
  2479. if flagp(op, 'c!:read_r3) then live := union(live, list r3);
  2480. if op = 'call then <<
  2481. if not flagp(car r3, 'c!:no_errors) then nil_used := t;
  2482. does_call := t;
  2483. fn_used := t;
  2484. if not flagp(car r3, 'c!:no_errors) then
  2485. flag(live, 'c!:live_across_call);
  2486. live := union(live, r2) >>;
  2487. if flagp(op, 'c!:read_env) then live := union(live, '(env))
  2488. end;
  2489. !#if common!-lisp!-mode
  2490. live := append(live, nil); % because CL sort is destructive!
  2491. !#endif
  2492. live := sort(live, function orderp);
  2493. if not (live = get(b, 'c!:live)) then <<
  2494. put(b, 'c!:live, live);
  2495. changed := t >>
  2496. end
  2497. >> until not changed;
  2498. z := registers;
  2499. registers := stacklocs := nil;
  2500. for each r in z do
  2501. if flagp(r, 'c!:live_across_call) then stacklocs := r . stacklocs
  2502. else registers := r . registers;
  2503. end;
  2504. symbolic procedure c!:insert1(a, b);
  2505. if memq(a, b) then b
  2506. else a . b;
  2507. symbolic procedure c!:clash(a, b);
  2508. if flagp(a, 'c!:live_across_call) = flagp(b, 'c!:live_across_call) then <<
  2509. put(a, 'c!:clash, c!:insert1(b, get(a, 'c!:clash)));
  2510. put(b, 'c!:clash, c!:insert1(a, get(b, 'c!:clash))) >>;
  2511. symbolic procedure c!:build_clash_matrix all_blocks;
  2512. begin
  2513. for each b in all_blocks do
  2514. begin
  2515. scalar live, w;
  2516. for each x in get(b, 'c!:where_to) do
  2517. if atom x then live := union(live, get(x, 'c!:live))
  2518. else live := union(live, x);
  2519. w := get(b, 'c!:why);
  2520. if not atom w then <<
  2521. live := union(live, cdr w);
  2522. if eqcar(car w, 'call) then
  2523. live := union('(env), live) >>;
  2524. for each s in get(b, 'c!:contents) do
  2525. begin
  2526. scalar op, r1, r2, r3;
  2527. op := car s; r1 := cadr s; r2 := caddr s; r3 := cadddr s;
  2528. if flagp(op, 'c!:set_r1) then
  2529. if memq(r1, live) then <<
  2530. !#if common!-lisp!-mode
  2531. live := remove(r1, live);
  2532. !#else
  2533. live := delete(r1, live);
  2534. !#endif
  2535. if op = 'reloadenv then reloadenv := t;
  2536. for each v in live do c!:clash(r1, v) >>
  2537. else if op = 'call then nil
  2538. else <<
  2539. op := 'nop;
  2540. rplacd(s, car s . cdr s); % Leaves original instrn visible
  2541. rplaca(s, op) >>;
  2542. if flagp(op, 'c!:read_r1) then live := union(live, list r1);
  2543. if flagp(op, 'c!:read_r2) then live := union(live, list r2);
  2544. if flagp(op, 'c!:read_r3) then live := union(live, list r3);
  2545. % Maybe CALL should be a little more selective about need for "env"?
  2546. if op = 'call then live := union(live, r2);
  2547. if flagp(op, 'c!:read_env) then live := union(live, '(env))
  2548. end
  2549. end;
  2550. return nil
  2551. end;
  2552. symbolic procedure c!:allocate_registers rl;
  2553. begin
  2554. scalar schedule, neighbours, allocation;
  2555. neighbours := 0;
  2556. while rl do begin
  2557. scalar w, x;
  2558. w := rl;
  2559. while w and length (x := get(car w, 'c!:clash)) > neighbours do
  2560. w := cdr w;
  2561. if w then <<
  2562. schedule := car w . schedule;
  2563. rl := deleq(car w, rl);
  2564. for each r in x do put(r, 'c!:clash, deleq(car w, get(r, 'c!:clash))) >>
  2565. else neighbours := neighbours + 1
  2566. end;
  2567. for each r in schedule do begin
  2568. scalar poss;
  2569. poss := allocation;
  2570. for each x in get(r, 'c!:clash) do
  2571. poss := deleq(get(x, 'c!:chosen), poss);
  2572. if null poss then <<
  2573. poss := c!:my_gensym();
  2574. allocation := append(allocation, list poss) >>
  2575. else poss := car poss;
  2576. put(r, 'c!:chosen, poss)
  2577. end;
  2578. return allocation
  2579. end;
  2580. symbolic procedure c!:remove_nops all_blocks;
  2581. % Remove no-operation instructions, and map registers to reflect allocation
  2582. for each b in all_blocks do
  2583. begin
  2584. scalar r;
  2585. for each s in get(b, 'c!:contents) do
  2586. if not eqcar(s, 'nop) then
  2587. begin
  2588. scalar op, r1, r2, r3;
  2589. op := car s; r1 := cadr s; r2 := caddr s; r3 := cadddr s;
  2590. if flagp(op, 'c!:set_r1) or flagp(op, 'c!:read_r1) then
  2591. r1 := get(r1, 'c!:chosen);
  2592. if flagp(op, 'c!:read_r2) then r2 := get(r2, 'c!:chosen);
  2593. if flagp(op, 'c!:read_r3) then r3 := get(r3, 'c!:chosen);
  2594. if op = 'call then
  2595. r2 := for each v in r2 collect get(v, 'c!:chosen);
  2596. if not (op = 'movr and r1 = r3) then
  2597. r := list(op, r1, r2, r3) . r
  2598. end;
  2599. put(b, 'c!:contents, reversip r);
  2600. r := get(b, 'c!:why);
  2601. if not atom r then
  2602. put(b, 'c!:why,
  2603. car r . for each v in cdr r collect get(v, 'c!:chosen))
  2604. end;
  2605. fluid '(error_labels);
  2606. symbolic procedure c!:find_error_label(why, env, depth);
  2607. begin
  2608. scalar w, z;
  2609. z := list(why, env, depth);
  2610. w := assoc!*!*(z, error_labels);
  2611. if null w then <<
  2612. w := z . c!:my_gensym();
  2613. error_labels := w . error_labels >>;
  2614. return cdr w
  2615. end;
  2616. symbolic procedure c!:assign(u, v, c);
  2617. if flagp(u, 'fluid) then list('strglob, v, u, c!:find_literal u) . c
  2618. else list('movr, u, nil, v) . c;
  2619. symbolic procedure c!:insert_tailcall b;
  2620. begin
  2621. scalar why, dest, contents, fcall, res, w;
  2622. why := get(b, 'c!:why);
  2623. dest := get(b, 'c!:where_to);
  2624. contents := get(b, 'c!:contents);
  2625. while contents and not eqcar(car contents, 'call) do <<
  2626. w := car contents . w;
  2627. contents := cdr contents >>;
  2628. if null contents then return nil;
  2629. fcall := car contents;
  2630. contents := cdr contents;
  2631. res := cadr fcall;
  2632. while w do <<
  2633. if eqcar(car w, 'reloadenv) then w := cdr w
  2634. else if eqcar(car w, 'movr) and cadddr car w = res then <<
  2635. res := cadr car w;
  2636. w := cdr w >>
  2637. else res := w := nil >>;
  2638. if null res then return nil;
  2639. if c!:does_return(res, why, dest) then
  2640. if car cadddr fcall = current_procedure then <<
  2641. for each p in pair(current_args, caddr fcall) do
  2642. contents := c!:assign(car p, cdr p, contents);
  2643. put(b, 'c!:contents, contents);
  2644. put(b, 'c!:why, 'goto);
  2645. put(b, 'c!:where_to, list restart_label) >>
  2646. else <<
  2647. nil_used := t;
  2648. put(b, 'c!:contents, contents);
  2649. put(b, 'c!:why, list('call, car cadddr fcall) . caddr fcall);
  2650. put(b, 'c!:where_to, nil) >>
  2651. end;
  2652. symbolic procedure c!:does_return(res, why, where_to);
  2653. if not (why = 'goto) then nil
  2654. else if not atom car where_to then res = caar where_to
  2655. else begin
  2656. scalar contents;
  2657. where_to := car where_to;
  2658. contents := reverse get(where_to, 'c!:contents);
  2659. why := get(where_to, 'c!:why);
  2660. where_to := get(where_to, 'c!:where_to);
  2661. while contents do
  2662. if eqcar(car contents, 'reloadenv) then contents := cdr contents
  2663. else if eqcar(car contents, 'movr) and cadddr car contents = res then <<
  2664. res := cadr car contents;
  2665. contents := cdr contents >>
  2666. else res := contents := nil;
  2667. if null res then return nil
  2668. else return c!:does_return(res, why, where_to)
  2669. end;
  2670. symbolic procedure c!:pushpop(op, v);
  2671. begin
  2672. scalar n, w, instr, src, dest, addr, v1,n1;
  2673. if null v then return nil;
  2674. n := length v;
  2675. if op = 'push then <<
  2676. instr := 'add;
  2677. src := 'eax >>
  2678. else <<
  2679. instr := 'sub;
  2680. dest := 'eax >>;
  2681. addr := 0;
  2682. for each x in v do <<
  2683. if op = 'push then <<
  2684. addr := addr + 4;
  2685. dest := {'ebx, addr};
  2686. i!:gopcode(mov, eax, x) >>
  2687. else src := {'ebx, addr};
  2688. i!:gopcode(mov, dest, src);
  2689. if op = 'pop then <<
  2690. i!:gopcode(mov, x,eax);
  2691. addr := addr - 4 >>
  2692. >>;
  2693. i!:gopcode(add,ebx,addr, mov,'stack,ebx)
  2694. end;
  2695. symbolic procedure c!:optimise_flowgraph(startpoint, all_blocks,
  2696. env, argch, args);
  2697. begin
  2698. scalar w, n, locs, stacks, error_labels, fn_used, nil_used,
  2699. nilbase_used, locsno, lab1, addr, lab_ok, stackoffs;
  2700. !#if common!-lisp!-mode
  2701. nilbase_used := t; % For onevalue(xxx) at least
  2702. !#endif
  2703. for each b in all_blocks do c!:insert_tailcall b;
  2704. startpoint := c!:branch_chain(startpoint, nil);
  2705. remflag(all_blocks, 'c!:visited);
  2706. c!:live_variable_analysis all_blocks;
  2707. c!:build_clash_matrix all_blocks;
  2708. if error_labels and env then reloadenv := t;
  2709. for each u in env do
  2710. for each v in env do c!:clash(cdr u, cdr v); % keep all args distinct
  2711. locs := c!:allocate_registers registers;
  2712. stacks := c!:allocate_registers stacklocs;
  2713. flag(stacks, 'c!:live_across_call);
  2714. c!:remove_nops all_blocks;
  2715. startpoint := c!:branch_chain(startpoint, nil); % after tailcall insertion
  2716. remflag(all_blocks, 'c!:visited);
  2717. startpoint := c!:branch_chain(startpoint, t); % ... AGAIN to tidy up
  2718. remflag(all_blocks, 'c!:visited);
  2719. if does_call then nil_used := t;
  2720. lab_end_proc := c!:my_gensym();
  2721. locsno := 0;
  2722. if nil_used then <<
  2723. locsno := locsno + 1 >>;
  2724. if locs then <<
  2725. locsno := locsno + length(locs)
  2726. >>;
  2727. % In ASM code I don't use fn since it is well replaced by hardware register
  2728. i!:gopcode(push,ebp, mov,ebp,esp);
  2729. if locsno > 0 then <<
  2730. i!:gopcode(sub,esp,locsno*4);
  2731. stackoffs := 0;
  2732. if nil_used then stackoffs := stackoffs - 4;
  2733. for each v in locs do <<
  2734. stackoffs := stackoffs - 4;
  2735. put(v, 'i!:locoffs, stackoffs) >>
  2736. >>;
  2737. if nil_used then
  2738. i!:gopcode(mov,eax,'C_nil, mov,{ebp,-4},eax);
  2739. i!:gopcode(push,ebx, mov,ebx,'stack);
  2740. %!! Has not been perfectly processed yet due to the string parameter
  2741. % # define argcheck(var, n, msg) if ((var)!=(n)) return aerror(msg);
  2742. if car argch = 0 or car argch >= 3 then <<
  2743. lab_ok := c!:my_gensym();
  2744. i!:gopcode(mov,eax,{ebp,off_nargs}, cmp,eax,car argch, je,lab_ok);
  2745. c!:pgencall('aerror, {999}, nil);
  2746. i!:gopcode(jmp,lab_end_proc);
  2747. i!:gopcode('!:,lab_ok) >>;
  2748. % I will not do a stack check if I have a leaf procedure, and I hope
  2749. % that this policy will speed up code a bit.
  2750. if does_call then <<
  2751. lab1 := c!:my_gensym();
  2752. i!:gopcode(cmp,ebx,'stacklimit, jl,lab1);
  2753. % This is slightly clumsy code to save all args on the stack across the
  2754. % call to reclaim(), but it is not executed often...
  2755. c!:pushpop('push, args);
  2756. %!! Has not been perfectly processed yet due to the string parameter
  2757. c!:pgencall('reclaim, {'!.env,0,GC_STACK,0}, {'ebp,off_env});
  2758. c!:pushpop('pop, reverse args);
  2759. i!:gopcode(mov,eax,'C_nil, mov,{ebp,-4},eax);
  2760. i!:gopcode(and,eax,1, je,lab1);
  2761. i!:gopcode(mov,eax,{ebp,-4}, jmp,lab_end_proc);
  2762. i!:gopcode('!:,lab1) >>;
  2763. if reloadenv then <<
  2764. i!:gopcode(mov,eax,{ebp,off_env}, add,ebx,4,
  2765. mov,{ebx},eax, mov,'stack,ebx) >>;
  2766. n := 0;
  2767. if stacks then <<
  2768. for each v in stacks do <<
  2769. put(v, 'c!:location, n);
  2770. n := n+1 >>;
  2771. stackoffs := 0;
  2772. i!:gopcode(mov, eax,{ebp,-4});
  2773. for each v in stacks do <<
  2774. stackoffs := stackoffs + 4;
  2775. i!:gopcode(mov, {ebx,stackoffs},eax) >>;
  2776. i!:gopcode(add,ebx,stackoffs, mov,'stack,ebx) >>;
  2777. if reloadenv then <<
  2778. reloadenv := n;
  2779. n := n + 1 >>;
  2780. for each v in env do
  2781. if flagp(cdr v, 'c!:live_across_call) then <<
  2782. i!:gopcode(mov, eax,cdr v);
  2783. i!:gopcode(mov, {ebx,-get(get(cdr v, 'c!:chosen), 'c!:location)*4},eax) >>
  2784. else <<
  2785. i!:gopcode(mov, eax,cdr v);
  2786. i!:gopcode(mov, get(cdr v, 'c!:chosen),eax) >>;
  2787. c!:display_flowgraph(startpoint, n, t);
  2788. if error_labels then <<
  2789. for each x in error_labels do <<
  2790. i!:gopcode('!:, cdr x);
  2791. c!:print_error_return(caar x, cadar x, caddar x) >> >>;
  2792. remflag(all_blocks, 'c!:visited);
  2793. i!:gopcode('!:,lab_end_proc);
  2794. i!:gopcode(pop,ebx, mov,esp,ebp, pop,ebp);
  2795. if retloc neq 0 then i!:gopcode(add,esp,4*retloc);
  2796. i!:gopcode(ret);
  2797. end;
  2798. symbolic procedure c!:print_error_return(why, env, depth);
  2799. begin
  2800. scalar args;
  2801. if reloadenv and env then <<
  2802. i!:gopcode(mov,eax,{ebx,-reloadenv*4}, mov,{ebp,off_env},eax)
  2803. >>;
  2804. if null why then <<
  2805. % One could imagine generating backtrace entries here...
  2806. for each v in env do <<
  2807. i!:gopcode(mov, eax,get(cdr v, 'c!:chosen));
  2808. c!:pst_qvaleltenv(c!:find_literal car v) >>;
  2809. if depth neq 0 then c!:ppopv(depth);
  2810. i!:gopcode(mov,eax,{ebp,-4}, jmp,lab_end_proc)
  2811. >>
  2812. else if flagp(cadr why, 'c!:live_across_call) then <<
  2813. i!:gopcode(push, {ebx,-get(cadr why, 'c!:location)*4});
  2814. for each v in env do <<
  2815. i!:gopcode(mov, eax,get(cdr v, 'c!:chosen));
  2816. c!:pst_qvaleltenv(c!:find_literal car v)
  2817. >>;
  2818. if depth neq 0 then c!:ppopv(depth);
  2819. if eqcar(why, 'car) then "err_bad_car"
  2820. else if eqcar(why, 'cdr) then "err_bad_cdr"
  2821. else error(0, list(why, "unknown_error"));
  2822. %!! Has not been properly processed yet because of the string parameter
  2823. args := list(1,
  2824. if eqcar(why, 'car) then 0 % "err_bad_car"
  2825. else if eqcar(why, 'cdr) then 0 % "err_bad_cdr"
  2826. else 0, % error(0, list(why, "unknown_error"));
  2827. cadr why);
  2828. c!:pgencall('error, args, nil);
  2829. i!:gopcode(jmp,lab_end_proc)
  2830. >>
  2831. else <<
  2832. for each v in env do <<
  2833. i!:gopcode(mov, eax, get(cdr v, 'c!:chosen));
  2834. c!:pst_qvaleltenv(c!:find_literal car v)
  2835. >>;
  2836. if depth neq 0 then c!:ppopv(depth);
  2837. %!! Has not been properly processed yet due to the string parameter
  2838. args := list(1,
  2839. if eqcar(why, 'car) then 0 % "err_bad_car"
  2840. else if eqcar(why, 'cdr) then 0 % "err_bad_cdr"
  2841. else 0, % error(0, list(why, "unknown_error"));
  2842. cadr why);
  2843. c!:pgencall('error, args, nil);
  2844. i!:gopcode(jmp,lab_end_proc)
  2845. >>
  2846. end;
  2847. %
  2848. % Now I have a series of separable sections each of which gives a special
  2849. % recipe that implements or optimises compilation of some specific Lisp
  2850. % form.
  2851. %
  2852. symbolic procedure c!:cand(u, env);
  2853. begin
  2854. scalar w, r;
  2855. w := reverse cdr u;
  2856. if null w then return c!:cval(nil, env);
  2857. r := list(list('t, car w));
  2858. w := cdr w;
  2859. for each z in w do
  2860. r := list(list('null, z), nil) . r;
  2861. r := 'cond . r;
  2862. return c!:cval(r, env)
  2863. end;
  2864. %-- scalar next, done, v, r;
  2865. %-- v := c!:newreg();
  2866. %-- done := c!:my_gensym();
  2867. %-- u := cdr u;
  2868. %-- while cdr u do <<
  2869. %-- next := c!:my_gensym();
  2870. %-- c!:outop('movr, v, nil, c!:cval(car u, env));
  2871. %-- u := cdr u;
  2872. %-- c!:endblock(list('ifnull, v), list(done, next));
  2873. %-- c!:startblock next >>;
  2874. %-- c!:outop('movr, v, nil, c!:cval(car u, env));
  2875. %-- c!:endblock('goto, list done);
  2876. %-- c!:startblock done;
  2877. %-- return v
  2878. %-- end;
  2879. put('and, 'c!:code, function c!:cand);
  2880. !#if common!-lisp!-mode
  2881. symbolic procedure c!:cblock(u, env);
  2882. begin
  2883. scalar progret, progexit, r;
  2884. progret := c!:newreg();
  2885. progexit := c!:my_gensym();
  2886. blockstack := (cadr u . progret . progexit) . blockstack;
  2887. u := cddr u;
  2888. for each a in u do r := c!:cval(a, env);
  2889. c!:outop('movr, progret, nil, r);
  2890. c!:endblock('goto, list progexit);
  2891. c!:startblock progexit;
  2892. blockstack := cdr blockstack;
  2893. return progret
  2894. end;
  2895. put('block, 'c!:code, function c!:cblock);
  2896. !#endif
  2897. symbolic procedure c!:ccatch(u, env);
  2898. error(0, "catch");
  2899. put('catch, 'c!:code, function c!:ccatch);
  2900. symbolic procedure c!:ccompile_let(u, env);
  2901. error(0, "compiler-let");
  2902. put('compiler!-let, 'c!:code, function c!:ccompiler_let);
  2903. symbolic procedure c!:ccond(u, env);
  2904. begin
  2905. scalar v, join;
  2906. v := c!:newreg();
  2907. join := c!:my_gensym();
  2908. for each c in cdr u do begin
  2909. scalar l1, l2;
  2910. l1 := c!:my_gensym(); l2 := c!:my_gensym();
  2911. if atom cdr c then <<
  2912. c!:outop('movr, v, nil, c!:cval(car c, env));
  2913. c!:endblock(list('ifnull, v), list(l2, join)) >>
  2914. else <<
  2915. c!:cjumpif(car c, env, l1, l2);
  2916. c!:startblock l1; % if the condition is true
  2917. c!:outop('movr, v, nil, c!:cval('progn . cdr c, env));
  2918. c!:endblock('goto, list join) >>;
  2919. c!:startblock l2 end;
  2920. c!:outop('movk1, v, nil, nil);
  2921. c!:endblock('goto, list join);
  2922. c!:startblock join;
  2923. return v
  2924. end;
  2925. put('cond, 'c!:code, function c!:ccond);
  2926. symbolic procedure c!:cdeclare(u, env);
  2927. error(0, "declare");
  2928. put('declare, 'c!:code, function c!:cdeclare);
  2929. symbolic procedure c!:cde(u, env);
  2930. error(0, "de");
  2931. put('de, 'c!:code, function c!:cde);
  2932. symbolic procedure c!:cdefun(u, env);
  2933. error(0, "defun");
  2934. put('!~defun, 'c!:code, function c!:cdefun);
  2935. symbolic procedure c!:ceval_when(u, env);
  2936. error(0, "eval-when");
  2937. put('eval!-when, 'c!:code, function c!:ceval_when);
  2938. symbolic procedure c!:cflet(u, env);
  2939. error(0, "flet");
  2940. put('flet, 'c!:code, function c!:cflet);
  2941. symbolic procedure c!:cfunction(u, env);
  2942. begin
  2943. scalar v;
  2944. u := cadr u;
  2945. if not atom u then error(0, "function/funarg needed");
  2946. v := c!:newreg();
  2947. c!:outop('movk, v, u, c!:find_literal u);
  2948. return v
  2949. end;
  2950. put('function, 'c!:code, function c!:cfunction);
  2951. symbolic procedure c!:cgo(u, env);
  2952. begin
  2953. scalar w, w1;
  2954. w1 := proglabs;
  2955. while null w and w1 do <<
  2956. w := assoc!*!*(cadr u, car w1);
  2957. w1 := cdr w1 >>;
  2958. if null w then error(0, list(u, "label not set"));
  2959. c!:endblock('goto, list cadr w);
  2960. return nil % value should not be used
  2961. end;
  2962. put('go, 'c!:code, function c!:cgo);
  2963. symbolic procedure c!:cif(u, env);
  2964. begin
  2965. scalar v, join, l1, l2;
  2966. v := c!:newreg();
  2967. join := c!:my_gensym();
  2968. l1 := c!:my_gensym();
  2969. l2 := c!:my_gensym();
  2970. c!:cjumpif(cadr u, env, l1, l2);
  2971. c!:startblock l1;
  2972. c!:outop('movr, v, nil, c!:cval(car (u := cddr u), env));
  2973. c!:endblock('goto, list join);
  2974. c!:startblock l2;
  2975. c!:outop('movr, v, nil, c!:cval(cadr u, env));
  2976. c!:endblock('goto, list join);
  2977. c!:startblock join;
  2978. return v
  2979. end;
  2980. put('if, 'c!:code, function c!:cif);
  2981. symbolic procedure c!:clabels(u, env);
  2982. error(0, "labels");
  2983. put('labels, 'c!:code, function c!:clabels);
  2984. symbolic procedure c!:expand!-let(vl, b);
  2985. if null vl then 'progn . b
  2986. else if null cdr vl then c!:expand!-let!*(vl, b)
  2987. else begin scalar vars, vals;
  2988. for each v in vl do
  2989. if atom v then << vars := v . vars; vals := nil . vals >>
  2990. else if atom cdr v then << vars := car v . vars; vals := nil . vals >>
  2991. else << vars := car v . vars; vals := cadr v . vals >>;
  2992. return ('lambda . vars . b) . vals
  2993. end;
  2994. symbolic procedure c!:clet(x, env);
  2995. c!:cval(c!:expand!-let(cadr x, cddr x), env);
  2996. !#if common!-lisp!-mode
  2997. put('let, 'c!:code, function c!:clet);
  2998. !#else
  2999. put('!~let, 'c!:code, function c!:clet);
  3000. !#endif
  3001. symbolic procedure c!:expand!-let!*(vl, b);
  3002. if null vl then 'progn . b
  3003. else begin scalar var, val;
  3004. var := car vl;
  3005. if not atom var then <<
  3006. val := cdr var;
  3007. var := car var;
  3008. if not atom val then val := car val >>;
  3009. b := list list('return, c!:expand!-let!*(cdr vl, b));
  3010. if val then b := list('setq, var, val) . b;
  3011. return 'prog . list var . b
  3012. end;
  3013. symbolic procedure c!:clet!*(x, env);
  3014. c!:cval(c!:expand!-let!*(cadr x, cddr x), env);
  3015. put('let!*, 'c!:code, function c!:clet!*);
  3016. symbolic procedure c!:clist(u, env);
  3017. if null cdr u then c!:cval(nil, env)
  3018. else if null cddr u then c!:cval('ncons . cdr u, env)
  3019. else if eqcar(cadr u, 'cons) then
  3020. c!:cval(list('acons, cadr cadr u, caddr cadr u, 'list . cddr u), env)
  3021. else if null cdddr u then c!:cval('list2 . cdr u, env)
  3022. else c!:cval(list('list2!*, cadr u, caddr u, 'list . cdddr u), env);
  3023. put('list, 'c!:code, function c!:clist);
  3024. symbolic procedure c!:clist!*(u, env);
  3025. begin
  3026. scalar v;
  3027. u := reverse cdr u;
  3028. v := car u;
  3029. for each a in cdr u do
  3030. v := list('cons, a, v);
  3031. return c!:cval(v, env)
  3032. end;
  3033. put('list!*, 'c!:code, function c!:clist!*);
  3034. symbolic procedure c!:ccons(u, env);
  3035. begin
  3036. scalar a1, a2;
  3037. a1 := s!:improve cadr u;
  3038. a2 := s!:improve caddr u;
  3039. if a2 = nil or a2 = '(quote nil) or a2 = '(list) then
  3040. return c!:cval(list('ncons, a1), env);
  3041. if eqcar(a1, 'cons) then
  3042. return c!:cval(list('acons, cadr a1, caddr a1, a2), env);
  3043. if eqcar(a2, 'cons) then
  3044. return c!:cval(list('list2!*, a1, cadr a2, caddr a2), env);
  3045. if eqcar(a2, 'list) then
  3046. return c!:cval(list('cons, a1,
  3047. list('cons, cadr a2, 'list . cddr a2)), env);
  3048. return c!:ccall(car u, cdr u, env)
  3049. end;
  3050. put('cons, 'c!:code, function c!:ccons);
  3051. symbolic procedure c!:cget(u, env);
  3052. begin
  3053. scalar a1, a2, w, r, r1;
  3054. a1 := s!:improve cadr u;
  3055. a2 := s!:improve caddr u;
  3056. if eqcar(a2, 'quote) and idp(w := cadr a2) and
  3057. (w := symbol!-make!-fastget(w, nil)) then <<
  3058. r := c!:newreg();
  3059. c!:outop('fastget, r, c!:cval(a1, env), w . cadr a2);
  3060. return r >>
  3061. else return c!:ccall(car u, cdr u, env)
  3062. end;
  3063. put('get, 'c!:code, function c!:cget);
  3064. symbolic procedure c!:cflag(u, env);
  3065. begin
  3066. scalar a1, a2, w, r, r1;
  3067. a1 := s!:improve cadr u;
  3068. a2 := s!:improve caddr u;
  3069. if eqcar(a2, 'quote) and idp(w := cadr a2) and
  3070. (w := symbol!-make!-fastget(w, nil)) then <<
  3071. r := c!:newreg();
  3072. c!:outop('fastflag, r, c!:cval(a1, env), w . cadr a2);
  3073. return r >>
  3074. else return c!:ccall(car u, cdr u, env)
  3075. end;
  3076. put('flagp, 'c!:code, function c!:cflag);
  3077. symbolic procedure c!:cgetv(u, env);
  3078. if not !*fastvector then c!:ccall(car u, cdr u, env)
  3079. else c!:cval('qgetv . cdr u, env);
  3080. put('getv, 'c!:code, function c!:cgetv);
  3081. !#if common!-lisp!-mode
  3082. put('svref, 'c!:code, function c!:cgetv);
  3083. !#endif
  3084. symbolic procedure c!:cputv(u, env);
  3085. if not !*fastvector then c!:ccall(car u, cdr u, env)
  3086. else c!:cval('qputv . cdr u, env);
  3087. put('putv, 'c!:code, function c!:cputv);
  3088. symbolic procedure c!:cqputv(x, env);
  3089. begin
  3090. scalar rr;
  3091. rr := c!:pareval(cdr x, env);
  3092. c!:outop('qputv, caddr rr, car rr, cadr rr);
  3093. return caddr rr
  3094. end;
  3095. put('qputv, 'c!:code, function c!:cqputv);
  3096. symbolic procedure c!:cmacrolet(u, env);
  3097. error(0, "macrolet");
  3098. put('macrolet, 'c!:code, function c!:cmacrolet);
  3099. symbolic procedure c!:cmultiple_value_call(u, env);
  3100. error(0, "multiple_value_call");
  3101. put('multiple!-value!-call, 'c!:code, function c!:cmultiple_value_call);
  3102. symbolic procedure c!:cmultiple_value_prog1(u, env);
  3103. error(0, "multiple_value_prog1");
  3104. put('multiple!-value!-prog1, 'c!:code, function c!:cmultiple_value_prog1);
  3105. symbolic procedure c!:cor(u, env);
  3106. begin
  3107. scalar next, done, v, r;
  3108. v := c!:newreg();
  3109. done := c!:my_gensym();
  3110. u := cdr u;
  3111. while cdr u do <<
  3112. next := c!:my_gensym();
  3113. c!:outop('movr, v, nil, c!:cval(car u, env));
  3114. u := cdr u;
  3115. c!:endblock(list('ifnull, v), list(next, done));
  3116. c!:startblock next >>;
  3117. c!:outop('movr, v, nil, c!:cval(car u, env));
  3118. c!:endblock('goto, list done);
  3119. c!:startblock done;
  3120. return v
  3121. end;
  3122. put('or, 'c!:code, function c!:cor);
  3123. symbolic procedure c!:cprog(u, env);
  3124. begin
  3125. scalar w, w1, bvl, local_proglabs, progret, progexit, fluids, env1;
  3126. env1 := car env;
  3127. bvl := cadr u;
  3128. for each v in bvl do
  3129. if globalp v then error(0, list(v, "attempt to bind a global"))
  3130. else if fluidp v then <<
  3131. fluids := (v . c!:newreg()) . fluids;
  3132. flag(list cdar fluids, 'c!:live_across_call); % silly if not
  3133. env1 := ('c!:dummy!:name . cdar fluids) . env1;
  3134. c!:outop('ldrglob, cdar fluids, v, c!:find_literal v);
  3135. c!:outop('nilglob, nil, v, c!:find_literal v) >>
  3136. else <<
  3137. env1 := (v . c!:newreg()) . env1;
  3138. c!:outop('movk1, cdar env1, nil, nil) >>;
  3139. if fluids then c!:outop('fluidbind, nil, nil, fluids);
  3140. env := env1 . append(fluids, cdr env);
  3141. u := cddr u;
  3142. progret := c!:newreg();
  3143. progexit := c!:my_gensym();
  3144. blockstack := (nil . progret . progexit) . blockstack;
  3145. for each a in u do if atom a then
  3146. if atsoc(a, local_proglabs) then <<
  3147. if not null a then <<
  3148. w := wrs nil;
  3149. princ "+++++ multiply defined label: "; prin a;
  3150. terpri(); wrs w >> >>
  3151. else local_proglabs := list(a, c!:my_gensym()) . local_proglabs;
  3152. proglabs := local_proglabs . proglabs;
  3153. for each a in u do
  3154. if atom a then <<
  3155. w := cdr(assoc!*!*(a, local_proglabs));
  3156. if null cdr w then <<
  3157. rplacd(w, t);
  3158. c!:endblock('goto, list car w);
  3159. c!:startblock car w >> >>
  3160. else c!:cval(a, env);
  3161. c!:outop('movk1, progret, nil, nil);
  3162. c!:endblock('goto, list progexit);
  3163. c!:startblock progexit;
  3164. for each v in fluids do
  3165. c!:outop('strglob, cdr v, car v, c!:find_literal car v);
  3166. blockstack := cdr blockstack;
  3167. proglabs := cdr proglabs;
  3168. return progret
  3169. end;
  3170. put('prog, 'c!:code, function c!:cprog);
  3171. symbolic procedure c!:cprog!*(u, env);
  3172. error(0, "prog*");
  3173. put('prog!*, 'c!:code, function c!:cprog!*);
  3174. symbolic procedure c!:cprog1(u, env);
  3175. begin
  3176. scalar g;
  3177. g := c!:my_gensym();
  3178. g := list('prog, list g,
  3179. list('setq, g, cadr u),
  3180. 'progn . cddr u,
  3181. list('return, g));
  3182. return c!:cval(g, env)
  3183. end;
  3184. put('prog1, 'c!:code, function c!:cprog1);
  3185. symbolic procedure c!:cprog2(u, env);
  3186. begin
  3187. scalar g;
  3188. u := cdr u;
  3189. g := c!:my_gensym();
  3190. g := list('prog, list g,
  3191. list('setq, g, cadr u),
  3192. 'progn . cddr u,
  3193. list('return, g));
  3194. g := list('progn, car u, g);
  3195. return c!:cval(g, env)
  3196. end;
  3197. put('prog2, 'c!:code, function c!:cprog2);
  3198. symbolic procedure c!:cprogn(u, env);
  3199. begin
  3200. scalar r;
  3201. u := cdr u;
  3202. if u = nil then u := '(nil);
  3203. for each s in u do r := c!:cval(s, env);
  3204. return r
  3205. end;
  3206. put('progn, 'c!:code, function c!:cprogn);
  3207. symbolic procedure c!:cprogv(u, env);
  3208. error(0, "progv");
  3209. put('progv, 'c!:code, function c!:cprogv);
  3210. symbolic procedure c!:cquote(u, env);
  3211. begin
  3212. scalar v;
  3213. u := cadr u;
  3214. v := c!:newreg();
  3215. if null u or u = 't or c!:small_number u then
  3216. c!:outop('movk1, v, nil, u)
  3217. else c!:outop('movk, v, u, c!:find_literal u);
  3218. return v;
  3219. end;
  3220. put('quote, 'c!:code, function c!:cquote);
  3221. symbolic procedure c!:creturn(u, env);
  3222. begin
  3223. scalar w;
  3224. w := assoc!*!*(nil, blockstack);
  3225. if null w then error(0, "RETURN out of context");
  3226. c!:outop('movr, cadr w, nil, c!:cval(cadr u, env));
  3227. c!:endblock('goto, list cddr w);
  3228. return nil % value should not be used
  3229. end;
  3230. put('return, 'c!:code, function c!:creturn);
  3231. !#if common!-lisp!-mode
  3232. symbolic procedure c!:creturn_from(u, env);
  3233. begin
  3234. scalar w;
  3235. w := assoc!*!*(cadr u, blockstack);
  3236. if null w then error(0, "RETURN-FROM out of context");
  3237. c!:outop('movr, cadr w, nil, c!:cval(caddr u, env));
  3238. c!:endblock('goto, list cddr w);
  3239. return nil % value should not be used
  3240. end;
  3241. !#endif
  3242. put('return!-from, 'c!:code, function c!:creturn_from);
  3243. symbolic procedure c!:csetq(u, env);
  3244. begin
  3245. scalar v, w;
  3246. v := c!:cval(caddr u, env);
  3247. u := cadr u;
  3248. if not idp u then error(0, list(u, "bad variable in setq"))
  3249. else if (w := c!:locally_bound(u, env)) then
  3250. c!:outop('movr, cdr w, nil, v)
  3251. else if flagp(u, 'c!:constant) then
  3252. error(0, list(u, "attempt to use setq on a constant"))
  3253. else c!:outop('strglob, v, u, c!:find_literal u);
  3254. return v
  3255. end;
  3256. put('setq, 'c!:code, function c!:csetq);
  3257. put('noisy!-setq, 'c!:code, function c!:csetq);
  3258. !#if common!-lisp!-mode
  3259. symbolic procedure c!:ctagbody(u, env);
  3260. begin
  3261. scalar w, bvl, local_proglabs, res;
  3262. u := cdr u;
  3263. for each a in u do if atom a then
  3264. if atsoc(a, local_proglabs) then <<
  3265. if not null a then <<
  3266. w := wrs nil;
  3267. princ "+++++ multiply defined label: "; prin a;
  3268. terpri(); wrs w >> >>
  3269. else local_proglabs := list(a, c!:my_gensym()) . local_proglabs;
  3270. proglabs := local_proglabs . proglabs;
  3271. for each a in u do
  3272. if atom a then <<
  3273. w := cdr(assoc!*!*(a, local_proglabs));
  3274. if null cdr w then <<
  3275. rplacd(w, t);
  3276. c!:endblock('goto, list car w);
  3277. c!:startblock car w >> >>
  3278. else res := c!:cval(a, env);
  3279. if null res then res := c!:cval(nil, env);
  3280. proglabs := cdr proglabs;
  3281. return res
  3282. end;
  3283. put('tagbody, 'c!:code, function c!:ctagbody);
  3284. !#endif
  3285. symbolic procedure c!:cprivate_tagbody(u, env);
  3286. % This sets a label for use for tail-call to self.
  3287. begin
  3288. u := cdr u;
  3289. c!:endblock('goto, list car u);
  3290. c!:startblock car u;
  3291. % This seems to be the proper place to capture the internal names associated
  3292. % with argument-vars that must be reset if a tail-call is mapped into a loop.
  3293. current_args := for each v in current_args collect begin
  3294. scalar z;
  3295. z := assoc!*!*(v, car env);
  3296. return if z then cdr z else v end;
  3297. return c!:cval(cadr u, env)
  3298. end;
  3299. put('c!:private_tagbody, 'c!:code, function c!:cprivate_tagbody);
  3300. symbolic procedure c!:cthe(u, env);
  3301. c!:cval(caddr u, env);
  3302. put('the, 'c!:code, function c!:cthe);
  3303. symbolic procedure c!:cthrow(u, env);
  3304. error(0, "throw");
  3305. put('throw, 'c!:code, function c!:cthrow);
  3306. symbolic procedure c!:cunless(u, env);
  3307. begin
  3308. scalar v, join, l1, l2;
  3309. v := c!:newreg();
  3310. join := c!:my_gensym();
  3311. l1 := c!:my_gensym();
  3312. l2 := c!:my_gensym();
  3313. c!:cjumpif(cadr u, env, l2, l1);
  3314. c!:startblock l1;
  3315. c!:outop('movr, v, nil, c!:cval('progn . cddr u, env));
  3316. c!:endblock('goto, list join);
  3317. c!:startblock l2;
  3318. c!:outop('movk1, v, nil, nil);
  3319. c!:endblock('goto, list join);
  3320. c!:startblock join;
  3321. return v
  3322. end;
  3323. put('unless, 'c!:code, function c!:cunless);
  3324. symbolic procedure c!:cunwind_protect(u, env);
  3325. error(0, "unwind_protect");
  3326. put('unwind!-protect, 'c!:code, function c!:cunwind_protect);
  3327. symbolic procedure c!:cwhen(u, env);
  3328. begin
  3329. scalar v, join, l1, l2;
  3330. v := c!:newreg();
  3331. join := c!:my_gensym();
  3332. l1 := c!:my_gensym();
  3333. l2 := c!:my_gensym();
  3334. c!:cjumpif(cadr u, env, l1, l2);
  3335. c!:startblock l1;
  3336. c!:outop('movr, v, nil, c!:cval('progn . cddr u, env));
  3337. c!:endblock('goto, list join);
  3338. c!:startblock l2;
  3339. c!:outop('movk1, v, nil, nil);
  3340. c!:endblock('goto, list join);
  3341. c!:startblock join;
  3342. return v
  3343. end;
  3344. put('when, 'c!:code, function c!:cwhen);
  3345. %
  3346. % End of code to handle special forms - what comes from here on is
  3347. % more concerned with performance than with speed.
  3348. %
  3349. !#if (not common!-lisp!-mode)
  3350. % mapcar etc are compiled specially as a fudge to achieve an effect as
  3351. % if proper environment-capture was implemented for the functional
  3352. % argument (which I do not support at present).
  3353. symbolic procedure c!:expand_map(fnargs);
  3354. begin
  3355. scalar carp, fn, fn1, args, var, avar, moveon, l1, r, s, closed;
  3356. fn := car fnargs;
  3357. % if the value of a mapping function is not needed I demote from mapcar to
  3358. % mapc or from maplist to map.
  3359. % if context > 1 then <<
  3360. % if fn = 'mapcar then fn := 'mapc
  3361. % else if fn = 'maplist then fn := 'map >>;
  3362. if fn = 'mapc or fn = 'mapcar or fn = 'mapcan then carp := t;
  3363. fnargs := cdr fnargs;
  3364. if atom fnargs then error(0,"bad arguments to map function");
  3365. fn1 := cadr fnargs;
  3366. while eqcar(fn1, 'function) or
  3367. (eqcar(fn1, 'quote) and eqcar(cadr fn1, 'lambda)) do <<
  3368. fn1 := cadr fn1;
  3369. closed := t >>;
  3370. % if closed is false I will insert FUNCALL since I am invoking a function
  3371. % stored in a variable - NB this means that the word FUNCTION becomes
  3372. % essential when using mapping operators - this is because I have built
  3373. % a 2-Lisp rather than a 1-Lisp.
  3374. args := car fnargs;
  3375. l1 := c!:my_gensym();
  3376. r := c!:my_gensym();
  3377. s := c!:my_gensym();
  3378. var := c!:my_gensym();
  3379. avar := var;
  3380. if carp then avar := list('car, avar);
  3381. if closed then fn1 := list(fn1, avar)
  3382. else fn1 := list('apply1, fn1, avar);
  3383. moveon := list('setq, var, list('cdr, var));
  3384. if fn = 'map or fn = 'mapc then fn := sublis(
  3385. list('l1 . l1, 'var . var,
  3386. 'fn . fn1, 'args . args, 'moveon . moveon),
  3387. '(prog (var)
  3388. (setq var args)
  3389. l1 (cond
  3390. ((not var) (return nil)))
  3391. fn
  3392. moveon
  3393. (go l1)))
  3394. else if fn = 'maplist or fn = 'mapcar then fn := sublis(
  3395. list('l1 . l1, 'var . var,
  3396. 'fn . fn1, 'args . args, 'moveon . moveon, 'r . r),
  3397. '(prog (var r)
  3398. (setq var args)
  3399. l1 (cond
  3400. ((not var) (return (reversip r))))
  3401. (setq r (cons fn r))
  3402. moveon
  3403. (go l1)))
  3404. else fn := sublis(
  3405. list('l1 . l1, 'l2 . c!:my_gensym(), 'var . var,
  3406. 'fn . fn1, 'args . args, 'moveon . moveon,
  3407. 'r . c!:my_gensym(), 's . c!:my_gensym()),
  3408. '(prog (var r s)
  3409. (setq var args)
  3410. (setq r (setq s (list nil)))
  3411. l1 (cond
  3412. ((not var) (return (cdr r))))
  3413. (rplacd s fn)
  3414. l2 (cond
  3415. ((not (atom (cdr s))) (setq s (cdr s)) (go l2)))
  3416. moveon
  3417. (go l1)));
  3418. return fn
  3419. end;
  3420. put('map, 'c!:compile_macro, function c!:expand_map);
  3421. put('maplist, 'c!:compile_macro, function c!:expand_map);
  3422. put('mapc, 'c!:compile_macro, function c!:expand_map);
  3423. put('mapcar, 'c!:compile_macro, function c!:expand_map);
  3424. put('mapcon, 'c!:compile_macro, function c!:expand_map);
  3425. put('mapcan, 'c!:compile_macro, function c!:expand_map);
  3426. !#endif
  3427. % caaar to cddddr get expanded into compositions of
  3428. % car, cdr which are compiled in-line
  3429. symbolic procedure c!:expand_carcdr(x);
  3430. begin
  3431. scalar name;
  3432. name := cdr reverse cdr explode2 car x;
  3433. x := cadr x;
  3434. for each v in name do
  3435. x := list(if v = 'a then 'car else 'cdr, x);
  3436. return x
  3437. end;
  3438. << put('caar, 'c!:compile_macro, function c!:expand_carcdr);
  3439. put('cadr, 'c!:compile_macro, function c!:expand_carcdr);
  3440. put('cdar, 'c!:compile_macro, function c!:expand_carcdr);
  3441. put('cddr, 'c!:compile_macro, function c!:expand_carcdr);
  3442. put('caaar, 'c!:compile_macro, function c!:expand_carcdr);
  3443. put('caadr, 'c!:compile_macro, function c!:expand_carcdr);
  3444. put('cadar, 'c!:compile_macro, function c!:expand_carcdr);
  3445. put('caddr, 'c!:compile_macro, function c!:expand_carcdr);
  3446. put('cdaar, 'c!:compile_macro, function c!:expand_carcdr);
  3447. put('cdadr, 'c!:compile_macro, function c!:expand_carcdr);
  3448. put('cddar, 'c!:compile_macro, function c!:expand_carcdr);
  3449. put('cdddr, 'c!:compile_macro, function c!:expand_carcdr);
  3450. put('caaaar, 'c!:compile_macro, function c!:expand_carcdr);
  3451. put('caaadr, 'c!:compile_macro, function c!:expand_carcdr);
  3452. put('caadar, 'c!:compile_macro, function c!:expand_carcdr);
  3453. put('caaddr, 'c!:compile_macro, function c!:expand_carcdr);
  3454. put('cadaar, 'c!:compile_macro, function c!:expand_carcdr);
  3455. put('cadadr, 'c!:compile_macro, function c!:expand_carcdr);
  3456. put('caddar, 'c!:compile_macro, function c!:expand_carcdr);
  3457. put('cadddr, 'c!:compile_macro, function c!:expand_carcdr);
  3458. put('cdaaar, 'c!:compile_macro, function c!:expand_carcdr);
  3459. put('cdaadr, 'c!:compile_macro, function c!:expand_carcdr);
  3460. put('cdadar, 'c!:compile_macro, function c!:expand_carcdr);
  3461. put('cdaddr, 'c!:compile_macro, function c!:expand_carcdr);
  3462. put('cddaar, 'c!:compile_macro, function c!:expand_carcdr);
  3463. put('cddadr, 'c!:compile_macro, function c!:expand_carcdr);
  3464. put('cdddar, 'c!:compile_macro, function c!:expand_carcdr);
  3465. put('cddddr, 'c!:compile_macro, function c!:expand_carcdr) >>;
  3466. symbolic procedure c!:builtin_one(x, env);
  3467. begin
  3468. scalar r1, r2;
  3469. r1 := c!:cval(cadr x, env);
  3470. c!:outop(car x, r2:=c!:newreg(), cdr env, r1);
  3471. return r2
  3472. end;
  3473. symbolic procedure c!:builtin_two(x, env);
  3474. begin
  3475. scalar a1, a2, r, rr;
  3476. a1 := cadr x;
  3477. a2 := caddr x;
  3478. rr := c!:pareval(list(a1, a2), env);
  3479. c!:outop(car x, r:=c!:newreg(), car rr, cadr rr);
  3480. return r
  3481. end;
  3482. symbolic procedure c!:narg(x, env);
  3483. c!:cval(expand(cdr x, get(car x, 'c!:binary_version)), env);
  3484. for each n in
  3485. '((plus plus2)
  3486. (times times2)
  3487. (iplus iplus2)
  3488. (itimes itimes2)) do <<
  3489. put(car n, 'c!:binary_version, cadr n);
  3490. put(car n, 'c!:code, function c!:narg) >>;
  3491. !#if common!-lisp!-mode
  3492. for each n in
  3493. '((!+ plus2)
  3494. (!* times2)) do <<
  3495. put(car n, 'c!:binary_version, cadr n);
  3496. put(car n, 'c!:code, function c!:narg) >>;
  3497. !#endif
  3498. symbolic procedure c!:cplus2(u, env);
  3499. begin
  3500. scalar a, b;
  3501. a := s!:improve cadr u;
  3502. b := s!:improve caddr u;
  3503. return if numberp a and numberp b then c!:cval(a+b, env)
  3504. else if a = 0 then c!:cval(b, env)
  3505. else if a = 1 then c!:cval(list('add1, b), env)
  3506. else if b = 0 then c!:cval(a, env)
  3507. else if b = 1 then c!:cval(list('add1, a), env)
  3508. else if b = -1 then c!:cval(list('sub1, a), env)
  3509. else c!:ccall(car u, cdr u, env)
  3510. end;
  3511. put('plus2, 'c!:code, function c!:cplus2);
  3512. symbolic procedure c!:ciplus2(u, env);
  3513. begin
  3514. scalar a, b;
  3515. a := s!:improve cadr u;
  3516. b := s!:improve caddr u;
  3517. return if numberp a and numberp b then c!:cval(a+b, env)
  3518. else if a = 0 then c!:cval(b, env)
  3519. else if a = 1 then c!:cval(list('iadd1, b), env)
  3520. else if b = 0 then c!:cval(a, env)
  3521. else if b = 1 then c!:cval(list('iadd1, a), env)
  3522. else if b = -1 then c!:cval(list('isub1, a), env)
  3523. else c!:builtin_two(u, env)
  3524. end;
  3525. put('iplus2, 'c!:code, function c!:ciplus2);
  3526. symbolic procedure c!:cdifference(u, env);
  3527. begin
  3528. scalar a, b;
  3529. a := s!:improve cadr u;
  3530. b := s!:improve caddr u;
  3531. return if numberp a and numberp b then c!:cval(a-b, env)
  3532. else if a = 0 then c!:cval(list('minus, b), env)
  3533. else if b = 0 then c!:cval(a, env)
  3534. else if b = 1 then c!:cval(list('sub1, a), env)
  3535. else if b = -1 then c!:cval(list('add1, a), env)
  3536. else c!:ccall(car u, cdr u, env)
  3537. end;
  3538. put('difference, 'c!:code, function c!:cdifference);
  3539. symbolic procedure c!:cidifference(u, env);
  3540. begin
  3541. scalar a, b;
  3542. a := s!:improve cadr u;
  3543. b := s!:improve caddr u;
  3544. return if numberp a and numberp b then c!:cval(a-b, env)
  3545. else if a = 0 then c!:cval(list('iminus, b), env)
  3546. else if b = 0 then c!:cval(a, env)
  3547. else if b = 1 then c!:cval(list('isub1, a), env)
  3548. else if b = -1 then c!:cval(list('iadd1, a), env)
  3549. else c!:builtin_two(u, env)
  3550. end;
  3551. put('idifference, 'c!:code, function c!:cidifference);
  3552. symbolic procedure c!:ctimes2(u, env);
  3553. begin
  3554. scalar a, b;
  3555. a := s!:improve cadr u;
  3556. b := s!:improve caddr u;
  3557. return if numberp a and numberp b then c!:cval(a*b, env)
  3558. else if a = 0 or b = 0 then c!:cval(0, env)
  3559. else if a = 1 then c!:cval(b, env)
  3560. else if b = 1 then c!:cval(a, env)
  3561. else if a = -1 then c!:cval(list('minus, b), env)
  3562. else if b = -1 then c!:cval(list('minus, a), env)
  3563. else c!:ccall(car u, cdr u, env)
  3564. end;
  3565. put('times2, 'c!:code, function c!:ctimes2);
  3566. symbolic procedure c!:citimes2(u, env);
  3567. begin
  3568. scalar a, b;
  3569. a := s!:improve cadr u;
  3570. b := s!:improve caddr u;
  3571. return if numberp a and numberp b then c!:cval(a*b, env)
  3572. else if a = 0 or b = 0 then c!:cval(0, env)
  3573. else if a = 1 then c!:cval(b, env)
  3574. else if b = 1 then c!:cval(a, env)
  3575. else if a = -1 then c!:cval(list('iminus, b), env)
  3576. else if b = -1 then c!:cval(list('iminus, a), env)
  3577. else c!:builtin_two(u, env)
  3578. end;
  3579. put('itimes2, 'c!:code, function c!:citimes2);
  3580. symbolic procedure c!:cminus(u, env);
  3581. begin
  3582. scalar a, b;
  3583. a := s!:improve cadr u;
  3584. return if numberp a then c!:cval(-a, env)
  3585. else if eqcar(a, 'minus) then c!:cval(cadr a, env)
  3586. else c!:ccall(car u, cdr u, env)
  3587. end;
  3588. put('minus, 'c!:code, function c!:cminus);
  3589. symbolic procedure c!:ceq(x, env);
  3590. begin
  3591. scalar a1, a2, r, rr;
  3592. a1 := s!:improve cadr x;
  3593. a2 := s!:improve caddr x;
  3594. if a1 = nil then return c!:cval(list('null, a2), env)
  3595. else if a2 = nil then return c!:cval(list('null, a1), env);
  3596. rr := c!:pareval(list(a1, a2), env);
  3597. c!:outop('eq, r:=c!:newreg(), car rr, cadr rr);
  3598. return r
  3599. end;
  3600. put('eq, 'c!:code, function c!:ceq);
  3601. symbolic procedure c!:cequal(x, env);
  3602. begin
  3603. scalar a1, a2, r, rr;
  3604. a1 := s!:improve cadr x;
  3605. a2 := s!:improve caddr x;
  3606. if a1 = nil then return c!:cval(list('null, a2), env)
  3607. else if a2 = nil then return c!:cval(list('null, a1), env);
  3608. rr := c!:pareval(list(a1, a2), env);
  3609. c!:outop((if c!:eqvalid a1 or c!:eqvalid a2 then 'eq else 'equal),
  3610. r:=c!:newreg(), car rr, cadr rr);
  3611. return r
  3612. end;
  3613. put('equal, 'c!:code, function c!:cequal);
  3614. %
  3615. % The next few cases are concerned with demoting functions that use
  3616. % equal tests into ones that use eq instead
  3617. symbolic procedure c!:is_fixnum x;
  3618. fixp x and x >= -134217728 and x <= 134217727;
  3619. symbolic procedure c!:certainlyatom x;
  3620. null x or x=t or c!:is_fixnum x or
  3621. (eqcar(x, 'quote) and (symbolp cadr x or c!:is_fixnum cadr x));
  3622. symbolic procedure c!:atomlist1 u;
  3623. atom u or
  3624. ((symbolp car u or c!:is_fixnum car u) and c!:atomlist1 cdr u);
  3625. symbolic procedure c!:atomlist x;
  3626. null x or
  3627. (eqcar(x, 'quote) and c!:atomlist1 cadr x) or
  3628. (eqcar(x, 'list) and
  3629. (null cdr x or
  3630. (c!:certainlyatom cadr x and
  3631. c!:atomlist ('list . cddr x)))) or
  3632. (eqcar(x, 'cons) and
  3633. c!:certainlyatom cadr x and
  3634. c!:atomlist caddr x);
  3635. symbolic procedure c!:atomcar x;
  3636. (eqcar(x, 'cons) or eqcar(x, 'list)) and
  3637. not null cdr x and
  3638. c!:certainlyatom cadr x;
  3639. symbolic procedure c!:atomkeys1 u;
  3640. atom u or
  3641. (not atom car u and
  3642. (symbolp caar u or c!:is_fixnum caar u) and
  3643. c!:atomlist1 cdr u);
  3644. symbolic procedure c!:atomkeys x;
  3645. null x or
  3646. (eqcar(x, 'quote) and c!:atomkeys1 cadr x) or
  3647. (eqcar(x, 'list) and
  3648. (null cdr x or
  3649. (c!:atomcar cadr x and
  3650. c!:atomkeys ('list . cddr x)))) or
  3651. (eqcar(x, 'cons) and
  3652. c!:atomcar cadr x and
  3653. c!:atomkeys caddr x);
  3654. !#if (not common!-lisp!-mode)
  3655. symbolic procedure c!:comsublis x;
  3656. if c!:atomkeys cadr x then 'subla . cdr x
  3657. else nil;
  3658. put('sublis, 'c!:compile_macro, function c!:comsublis);
  3659. symbolic procedure c!:comassoc x;
  3660. if c!:certainlyatom cadr x or c!:atomkeys caddr x then 'atsoc . cdr x
  3661. else nil;
  3662. put('assoc, 'c!:compile_macro, function c!:comassoc);
  3663. put('assoc!*!*, 'c!:compile_macro, function c!:comassoc);
  3664. symbolic procedure c!:commember x;
  3665. if c!:certainlyatom cadr x or c!:atomlist caddr x then 'memq . cdr x
  3666. else nil;
  3667. put('member, 'c!:compile_macro, function c!:commember);
  3668. symbolic procedure c!:comdelete x;
  3669. if c!:certainlyatom cadr x or c!:atomlist caddr x then 'deleq . cdr x
  3670. else nil;
  3671. put('delete, 'c!:compile_macro, function c!:comdelete);
  3672. !#endif
  3673. symbolic procedure c!:ctestif(x, env, d1, d2);
  3674. begin
  3675. scalar l1, l2;
  3676. l1 := c!:my_gensym();
  3677. l2 := c!:my_gensym();
  3678. c!:jumpif(cadr x, l1, l2);
  3679. x := cddr x;
  3680. c!:startblock l1;
  3681. c!:jumpif(car x, d1, d2);
  3682. c!:startblock l2;
  3683. c!:jumpif(cadr x, d1, d2)
  3684. end;
  3685. put('if, 'c!:ctest, function c!:ctestif);
  3686. symbolic procedure c!:ctestnull(x, env, d1, d2);
  3687. c!:cjumpif(cadr x, env, d2, d1);
  3688. put('null, 'c!:ctest, function c!:ctestnull);
  3689. put('not, 'c!:ctest, function c!:ctestnull);
  3690. symbolic procedure c!:ctestatom(x, env, d1, d2);
  3691. begin
  3692. x := c!:cval(cadr x, env);
  3693. c!:endblock(list('ifatom, x), list(d1, d2))
  3694. end;
  3695. put('atom, 'c!:ctest, function c!:ctestatom);
  3696. symbolic procedure c!:ctestconsp(x, env, d1, d2);
  3697. begin
  3698. x := c!:cval(cadr x, env);
  3699. c!:endblock(list('ifatom, x), list(d2, d1))
  3700. end;
  3701. put('consp, 'c!:ctest, function c!:ctestconsp);
  3702. symbolic procedure c!:ctestsymbol(x, env, d1, d2);
  3703. begin
  3704. x := c!:cval(cadr x, env);
  3705. c!:endblock(list('ifsymbol, x), list(d1, d2))
  3706. end;
  3707. put('idp, 'c!:ctest, function c!:ctestsymbol);
  3708. symbolic procedure c!:ctestnumberp(x, env, d1, d2);
  3709. begin
  3710. x := c!:cval(cadr x, env);
  3711. c!:endblock(list('ifnumber, x), list(d1, d2))
  3712. end;
  3713. put('numberp, 'c!:ctest, function c!:ctestnumberp);
  3714. symbolic procedure c!:ctestizerop(x, env, d1, d2);
  3715. begin
  3716. x := c!:cval(cadr x, env);
  3717. c!:endblock(list('ifizerop, x), list(d1, d2))
  3718. end;
  3719. put('izerop, 'c!:ctest, function c!:ctestizerop);
  3720. symbolic procedure c!:ctesteq(x, env, d1, d2);
  3721. begin
  3722. scalar a1, a2, r;
  3723. a1 := cadr x;
  3724. a2 := caddr x;
  3725. if a1 = nil then return c!:cjumpif(a2, env, d2, d1)
  3726. else if a2 = nil then return c!:cjumpif(a1, env, d2, d1);
  3727. r := c!:pareval(list(a1, a2), env);
  3728. c!:endblock('ifeq . r, list(d1, d2))
  3729. end;
  3730. put('eq, 'c!:ctest, function c!:ctesteq);
  3731. symbolic procedure c!:ctesteqcar(x, env, d1, d2);
  3732. begin
  3733. scalar a1, a2, r, d3;
  3734. a1 := cadr x;
  3735. a2 := caddr x;
  3736. d3 := c!:my_gensym();
  3737. r := c!:pareval(list(a1, a2), env);
  3738. c!:endblock(list('ifatom, car r), list(d2, d3));
  3739. c!:startblock d3;
  3740. c!:outop('qcar, car r, nil, car r);
  3741. c!:endblock('ifeq . r, list(d1, d2))
  3742. end;
  3743. put('eqcar, 'c!:ctest, function c!:ctesteqcar);
  3744. global '(least_fixnum greatest_fixnum);
  3745. least_fixnum := -expt(2, 27);
  3746. greatest_fixnum := expt(2, 27) - 1;
  3747. symbolic procedure c!:small_number x;
  3748. fixp x and x >= least_fixnum and x <= greatest_fixnum;
  3749. symbolic procedure c!:eqvalid x;
  3750. if atom x then c!:small_number x
  3751. else if flagp(car x, 'c!:fixnum_fn) then t
  3752. else car x = 'quote and (idp cadr x or c!:small_number cadr x);
  3753. flag('(iplus iplus2 idifference iminus itimes itimes2), 'c!:fixnum_fn);
  3754. symbolic procedure c!:ctestequal(x, env, d1, d2);
  3755. begin
  3756. scalar a1, a2, r;
  3757. a1 := s!:improve cadr x;
  3758. a2 := s!:improve caddr x;
  3759. if a1 = nil then return c!:cjumpif(a2, env, d2, d1)
  3760. else if a2 = nil then return c!:cjumpif(a1, env, d2, d1);
  3761. r := c!:pareval(list(a1, a2), env);
  3762. c!:endblock((if c!:eqvalid a1 or c!:eqvalid a2 then 'ifeq else 'ifequal) .
  3763. r, list(d1, d2))
  3764. end;
  3765. put('equal, 'c!:ctest, function c!:ctestequal);
  3766. symbolic procedure c!:ctestilessp(x, env, d1, d2);
  3767. begin
  3768. scalar r;
  3769. r := c!:pareval(list(cadr x, caddr x), env);
  3770. c!:endblock('ifilessp . r, list(d1, d2))
  3771. end;
  3772. put('ilessp, 'c!:ctest, function c!:ctestilessp);
  3773. symbolic procedure c!:ctestigreaterp(x, env, d1, d2);
  3774. begin
  3775. scalar r;
  3776. r := c!:pareval(list(cadr x, caddr x), env);
  3777. c!:endblock('ifigreaterp . r, list(d1, d2))
  3778. end;
  3779. put('igreaterp, 'c!:ctest, function c!:ctestigreaterp);
  3780. symbolic procedure c!:ctestand(x, env, d1, d2);
  3781. begin
  3782. scalar next;
  3783. for each a in cdr x do <<
  3784. next := c!:my_gensym();
  3785. c!:cjumpif(a, env, next, d2);
  3786. c!:startblock next >>;
  3787. c!:endblock('goto, list d1)
  3788. end;
  3789. put('and, 'c!:ctest, function c!:ctestand);
  3790. symbolic procedure c!:ctestor(x, env, d1, d2);
  3791. begin
  3792. scalar next;
  3793. for each a in cdr x do <<
  3794. next := c!:my_gensym();
  3795. c!:cjumpif(a, env, d1, next);
  3796. c!:startblock next >>;
  3797. c!:endblock('goto, list d2)
  3798. end;
  3799. put('or, 'c!:ctest, function c!:ctestor);
  3800. % Here are some of the things that are built into the Lisp kernel
  3801. % and that I am happy to allow the compiler to generate direct calls to.
  3802. <<
  3803. %
  3804. % In these tables there are some functions that would need adjusting
  3805. % for a Common Lisp compiler, since they take different numbers of
  3806. % args in Common and Standard Lisp.
  3807. % This means, to be specific:
  3808. %
  3809. % Lgensym Lread Latan Ltruncate Lfloat
  3810. % Lintern Lmacroexpand Lmacroexpand_1
  3811. % Lrandom Lunintern Lappend Leqn Lgcd
  3812. % Lgeq Lgreaterp Llcm Lleq Llessp
  3813. % Lquotient
  3814. %
  3815. % In these cases (at least!) the Common Lisp version of the compiler will
  3816. % need to avoid generating the call that uses this table.
  3817. %
  3818. % Some functions are missing from the list here because they seemed
  3819. % critical enough to be awarded single-byte opcodes or because the
  3820. % compiler always expands them away - car through cddddr are the main
  3821. % cases, together with eq and equal.
  3822. %
  3823. put('batchp, 'zero_arg_fn, 0);
  3824. put('date, 'zero_arg_fn, 1);
  3825. put('eject, 'zero_arg_fn, 2);
  3826. put('error0, 'zero_arg_fn, 3);
  3827. put('gctime, 'zero_arg_fn, 4);
  3828. put('gensym, 'zero_arg_fn, 5);
  3829. put('lposn, 'zero_arg_fn, 6);
  3830. put('next!-random, 'zero_arg_fn, 7);
  3831. put('posn, 'zero_arg_fn, 8);
  3832. put('read, 'zero_arg_fn, 9);
  3833. put('readch, 'zero_arg_fn, 10);
  3834. put('terpri, 'zero_arg_fn, 11);
  3835. put('time, 'zero_arg_fn, 12);
  3836. put('tyi, 'zero_arg_fn, 13);
  3837. put('load!-spid, 'zero_arg_fn, 14); % ONLY used in compiled code
  3838. put('absval, 'one_arg_fn, 0);
  3839. put('add1, 'one_arg_fn, 1);
  3840. put('atan, 'one_arg_fn, 2);
  3841. put('apply0, 'one_arg_fn, 3);
  3842. put('atom, 'one_arg_fn, 4);
  3843. put('boundp, 'one_arg_fn, 5);
  3844. put('char!-code, 'one_arg_fn, 6);
  3845. put('close, 'one_arg_fn, 7);
  3846. put('codep, 'one_arg_fn, 8);
  3847. put('compress, 'one_arg_fn, 9);
  3848. put('constantp, 'one_arg_fn, 10);
  3849. put('digitp, 'one_arg_fn, 11);
  3850. put('endp, 'one_arg_fn, 12);
  3851. put('eval, 'one_arg_fn, 13);
  3852. put('evenp, 'one_arg_fn, 14);
  3853. put('evlis, 'one_arg_fn, 15);
  3854. put('explode, 'one_arg_fn, 16);
  3855. put('explode2lc, 'one_arg_fn, 17);
  3856. put('explodec, 'one_arg_fn, 18);
  3857. put('fixp, 'one_arg_fn, 19);
  3858. put('float, 'one_arg_fn, 20);
  3859. put('floatp, 'one_arg_fn, 21);
  3860. put('symbol!-specialp, 'one_arg_fn, 22);
  3861. put('gc, 'one_arg_fn, 23);
  3862. put('gensym1, 'one_arg_fn, 24);
  3863. put('getenv, 'one_arg_fn, 25);
  3864. put('symbol!-globalp, 'one_arg_fn, 26);
  3865. put('iadd1, 'one_arg_fn, 27);
  3866. put('symbolp, 'one_arg_fn, 28);
  3867. put('iminus, 'one_arg_fn, 29);
  3868. put('iminusp, 'one_arg_fn, 30);
  3869. put('indirect, 'one_arg_fn, 31);
  3870. put('integerp, 'one_arg_fn, 32);
  3871. put('intern, 'one_arg_fn, 33);
  3872. put('isub1, 'one_arg_fn, 34);
  3873. put('length, 'one_arg_fn, 35);
  3874. put('lengthc, 'one_arg_fn, 36);
  3875. put('linelength, 'one_arg_fn, 37);
  3876. put('alpha!-char!-p, 'one_arg_fn, 38);
  3877. put('load!-module, 'one_arg_fn, 39);
  3878. put('lognot, 'one_arg_fn, 40);
  3879. put('macroexpand, 'one_arg_fn, 41);
  3880. put('macroexpand!-1, 'one_arg_fn, 42);
  3881. put('macro!-function, 'one_arg_fn, 43);
  3882. put('get!-bps, 'one_arg_fn, 44);
  3883. put('make!-global, 'one_arg_fn, 45);
  3884. put('smkvect, 'one_arg_fn, 46);
  3885. put('make!-special, 'one_arg_fn, 47);
  3886. put('minus, 'one_arg_fn, 48);
  3887. put('minusp, 'one_arg_fn, 49);
  3888. put('mkvect, 'one_arg_fn, 50);
  3889. put('modular!-minus, 'one_arg_fn, 51);
  3890. put('modular!-number, 'one_arg_fn, 52);
  3891. put('modular!-reciprocal, 'one_arg_fn, 53);
  3892. put('null, 'one_arg_fn, 54);
  3893. put('oddp, 'one_arg_fn, 55);
  3894. put('onep, 'one_arg_fn, 56);
  3895. put('pagelength, 'one_arg_fn, 57);
  3896. put('consp, 'one_arg_fn, 58);
  3897. put('plist, 'one_arg_fn, 59);
  3898. put('plusp, 'one_arg_fn, 60);
  3899. put('prin, 'one_arg_fn, 61);
  3900. put('princ, 'one_arg_fn, 62);
  3901. put('print, 'one_arg_fn, 63);
  3902. put('printc, 'one_arg_fn, 64);
  3903. put('random, 'one_arg_fn, 65);
  3904. put('rational, 'one_arg_fn, 66);
  3905. put('rdf1, 'one_arg_fn, 67);
  3906. put('rds, 'one_arg_fn, 68);
  3907. put('remd, 'one_arg_fn, 69);
  3908. put('reverse, 'one_arg_fn, 70);
  3909. put('nreverse, 'one_arg_fn, 71);
  3910. put('whitespace!-char!-p, 'one_arg_fn, 72);
  3911. put('set!-small!-modulus, 'one_arg_fn, 73);
  3912. put('xtab, 'one_arg_fn, 74);
  3913. put('special!-char, 'one_arg_fn, 75);
  3914. put('special!-form!-p, 'one_arg_fn, 76);
  3915. put('spool, 'one_arg_fn, 77);
  3916. put('stop, 'one_arg_fn, 78);
  3917. put('stringp, 'one_arg_fn, 79);
  3918. put('sub1, 'one_arg_fn, 80);
  3919. put('symbol!-env, 'one_arg_fn, 81);
  3920. put('symbol!-function, 'one_arg_fn, 82);
  3921. put('symbol!-name, 'one_arg_fn, 83);
  3922. put('symbol!-value, 'one_arg_fn, 84);
  3923. put('system, 'one_arg_fn, 85);
  3924. put('truncate, 'one_arg_fn, 86);
  3925. put('ttab, 'one_arg_fn, 87);
  3926. put('tyo, 'one_arg_fn, 88);
  3927. put('unintern, 'one_arg_fn, 89);
  3928. put('unmake!-global, 'one_arg_fn, 90);
  3929. put('unmake!-special, 'one_arg_fn, 91);
  3930. put('upbv, 'one_arg_fn, 92);
  3931. put('simple!-vectorp, 'one_arg_fn, 93);
  3932. put('verbos, 'one_arg_fn, 94);
  3933. put('wrs, 'one_arg_fn, 95);
  3934. put('zerop, 'one_arg_fn, 96);
  3935. put('car, 'one_arg_fn, 97);
  3936. put('cdr, 'one_arg_fn, 98);
  3937. put('caar, 'one_arg_fn, 99);
  3938. put('cadr, 'one_arg_fn, 100);
  3939. put('cdar, 'one_arg_fn, 101);
  3940. put('cddr, 'one_arg_fn, 102);
  3941. put('car, 'one_arg_fn, 103); % Really QCAR (unchecked)
  3942. put('cdr, 'one_arg_fn, 104);
  3943. put('caar, 'one_arg_fn, 105);
  3944. put('cadr, 'one_arg_fn, 106);
  3945. put('cdar, 'one_arg_fn, 107);
  3946. put('cddr, 'one_arg_fn, 108);
  3947. put('ncons, 'one_arg_fn, 109);
  3948. put('numberp, 'one_arg_fn, 110);
  3949. put('is!-spid, 'one_arg_fn, 111); % ONLY used in compiled code
  3950. put('spid!-to!-nil, 'one_arg_fn, 112); % ONLY used in compiled code
  3951. put('mv!-list, 'one_arg_fn, 113); % ONLY used in compiled code
  3952. put('append, 'two_arg_fn, 0);
  3953. put('ash, 'two_arg_fn, 1);
  3954. put('assoc, 'two_arg_fn, 2);
  3955. put('atsoc, 'two_arg_fn, 3);
  3956. put('deleq, 'two_arg_fn, 4);
  3957. put('delete, 'two_arg_fn, 5);
  3958. put('divide, 'two_arg_fn, 6);
  3959. put('eqcar, 'two_arg_fn, 7);
  3960. put('eql, 'two_arg_fn, 8);
  3961. put('eqn, 'two_arg_fn, 9);
  3962. put('expt, 'two_arg_fn, 10);
  3963. put('flag, 'two_arg_fn, 11);
  3964. put('flagpcar, 'two_arg_fn, 12);
  3965. put('gcd, 'two_arg_fn, 13);
  3966. put('geq, 'two_arg_fn, 14);
  3967. put('getv, 'two_arg_fn, 15);
  3968. put('greaterp, 'two_arg_fn, 16);
  3969. put('idifference, 'two_arg_fn, 17);
  3970. put('igreaterp, 'two_arg_fn, 18);
  3971. put('ilessp, 'two_arg_fn, 19);
  3972. put('imax, 'two_arg_fn, 20);
  3973. put('imin, 'two_arg_fn, 21);
  3974. put('iplus2, 'two_arg_fn, 22);
  3975. put('iquotient, 'two_arg_fn, 23);
  3976. put('iremainder, 'two_arg_fn, 24);
  3977. put('irightshift, 'two_arg_fn, 25);
  3978. put('itimes2, 'two_arg_fn, 26);
  3979. put('lcm, 'two_arg_fn, 27);
  3980. put('leq, 'two_arg_fn, 28);
  3981. put('lessp, 'two_arg_fn, 29);
  3982. put('make!-random!-state, 'two_arg_fn, 30);
  3983. put('max2, 'two_arg_fn, 31);
  3984. put('member, 'two_arg_fn, 32);
  3985. put('memq, 'two_arg_fn, 33);
  3986. put('min2, 'two_arg_fn, 34);
  3987. put('mod, 'two_arg_fn, 35);
  3988. put('modular!-difference, 'two_arg_fn, 36);
  3989. put('modular!-expt, 'two_arg_fn, 37);
  3990. put('modular!-plus, 'two_arg_fn, 38);
  3991. put('modular!-quotient, 'two_arg_fn, 39);
  3992. put('modular!-times, 'two_arg_fn, 40);
  3993. put('nconc, 'two_arg_fn, 41);
  3994. put('neq, 'two_arg_fn, 42);
  3995. put('orderp, 'two_arg_fn, 43);
  3996. put('quotient, 'two_arg_fn, 44);
  3997. put('rem, 'two_arg_fn, 45);
  3998. put('remflag, 'two_arg_fn, 46);
  3999. put('remprop, 'two_arg_fn, 47);
  4000. put('rplaca, 'two_arg_fn, 48);
  4001. put('rplacd, 'two_arg_fn, 49);
  4002. put('sgetv, 'two_arg_fn, 50);
  4003. put('set, 'two_arg_fn, 51);
  4004. put('smemq, 'two_arg_fn, 52);
  4005. put('subla, 'two_arg_fn, 53);
  4006. put('sublis, 'two_arg_fn, 54);
  4007. put('symbol!-set!-definition, 'two_arg_fn, 55);
  4008. put('symbol!-set!-env, 'two_arg_fn, 56);
  4009. put('times2, 'two_arg_fn, 57);
  4010. put('xcons, 'two_arg_fn, 58);
  4011. put('equal, 'two_arg_fn, 59);
  4012. put('eq, 'two_arg_fn, 60);
  4013. put('cons, 'two_arg_fn, 61);
  4014. put('list2, 'two_arg_fn, 62);
  4015. put('get, 'two_arg_fn, 63);
  4016. put('getv, 'two_arg_fn, 64); % QGETV
  4017. put('flagp, 'two_arg_fn, 65);
  4018. put('apply1, 'two_arg_fn, 66);
  4019. put('difference2, 'two_arg_fn, 67);
  4020. put('plus2, 'two_arg_fn, 68);
  4021. put('times2, 'two_arg_fn, 69);
  4022. put('bpsputv, 'three_arg_fn, 0);
  4023. put('errorsetn, 'three_arg_fn, 1);
  4024. put('list2star, 'three_arg_fn, 2);
  4025. put('list3, 'three_arg_fn, 3);
  4026. put('putprop, 'three_arg_fn, 4);
  4027. put('putv, 'three_arg_fn, 5);
  4028. put('sputv, 'three_arg_fn, 6);
  4029. put('subst, 'three_arg_fn, 7);
  4030. put('apply2, 'three_arg_fn, 8);
  4031. put('acons, 'three_arg_fn, 9);
  4032. "native entrypoints established" >>;
  4033. flag(
  4034. '(atom atsoc codep constantp deleq digit endp eq eqcar evenp
  4035. eql fixp flagp flagpcar floatp get globalp iadd1 idifference idp
  4036. igreaterp ilessp iminus iminusp indirect integerp iplus2 irightshift
  4037. isub1 itimes2 liter memq minusp modular!-difference modular!-expt
  4038. modular!-minus modular!-number modular!-plus modular!-times not
  4039. null numberp onep pairp plusp qcaar qcadr qcar qcdar qcddr
  4040. qcdr remflag remprop reversip seprp special!-form!-p stringp
  4041. symbol!-env symbol!-name symbol!-value threevectorp vectorp zerop),
  4042. 'c!:no_errors);
  4043. end;
  4044. % End of i86comp.red