FoxARMBackend.Mod 160 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900
  1. MODULE FoxARMBackend; (** AUTHOR ""; PURPOSE "backend for ARM (advanced RISC machines)"; *)
  2. IMPORT
  3. Basic := FoxBasic, SyntaxTree := FoxSyntaxTree, Global := FoxGlobal, Backend := FoxBackend, Sections := FoxSections,
  4. IntermediateCode := FoxIntermediateCode, IntermediateBackend := FoxIntermediateBackend, CodeGenerators := FoxCodeGenerators, BinaryCode := FoxBinaryCode,
  5. SemanticChecker := FoxSemanticChecker, Formats := FoxFormats, Assembler := FoxARMAssembler, InstructionSet := FoxARMInstructionSet,
  6. SYSTEM, Diagnostics, Streams, Options, Strings, ObjectFile, Scanner := FoxScanner, ObjectFileFormat := FoxGenericObjectFile,
  7. D := Debugging;
  8. CONST
  9. Trace = FALSE; (* general trace *)
  10. DefaultRuntimeModuleName = "ARMRuntime";
  11. None = -1;
  12. (* parts of an ARM operand *)
  13. Low = 0; High = 1;
  14. (* mnemonics of the ARM instruction set *)
  15. opADC = InstructionSet.opADC; opADD = InstructionSet.opADD;
  16. opAND = InstructionSet.opAND; opB = InstructionSet.opB;
  17. opBIC = InstructionSet.opBIC; opBKPT = InstructionSet.opBKPT;
  18. opBL = InstructionSet.opBL; opBLX = InstructionSet.opBLX;
  19. opBX = InstructionSet.opBX; opCDP = InstructionSet.opCDP;
  20. opCDP2 = InstructionSet.opCDP2; opCLZ = InstructionSet.opCLZ;
  21. opCMN = InstructionSet.opCMN; opCMP = InstructionSet.opCMP;
  22. opEOR = InstructionSet.opEOR; opFABSD = InstructionSet.opFABSD;
  23. opFABSS = InstructionSet.opFABSS; opFADDD = InstructionSet.opFADDD;
  24. opFADDS = InstructionSet.opFADDS; opFCMPD = InstructionSet.opFCMPD;
  25. opFCMPED = InstructionSet.opFCMPED; opFCMPES = InstructionSet.opFCMPES;
  26. opFCMPEZD = InstructionSet.opFCMPEZD; opFCMPEZS = InstructionSet.opFCMPEZS;
  27. opFCMPS = InstructionSet.opFCMPS; opFCMPZD = InstructionSet.opFCMPZD;
  28. opFCMPZS = InstructionSet.opFCMPZS; opFCPYD = InstructionSet.opFCPYD;
  29. opFCPYS = InstructionSet.opFCPYS; opFCVTDS = InstructionSet.opFCVTDS;
  30. opFCVTSD = InstructionSet.opFCVTSD; opFDIVD = InstructionSet.opFDIVD;
  31. opFDIVS = InstructionSet.opFDIVS; opFLDD = InstructionSet.opFLDD;
  32. opFLDMIAD = InstructionSet.opFLDMIAD; opFLDMIAS = InstructionSet.opFLDMIAS;
  33. opFLDMIAX = InstructionSet.opFLDMIAX; opFLDMDBD = InstructionSet.opFLDMDBD;
  34. opFLDMDBS = InstructionSet.opFLDMDBS; opFLDMDBX = InstructionSet.opFLDMDBX;
  35. opFLDS = InstructionSet.opFLDS; opFMACD = InstructionSet.opFMACD;
  36. opFMACS = InstructionSet.opFMACS; opFMDHR = InstructionSet.opFMDHR;
  37. opFMDLR = InstructionSet.opFMDLR; opFMRDH = InstructionSet.opFMRDH;
  38. opFMRDL = InstructionSet.opFMRDL; opFMRS = InstructionSet.opFMRS;
  39. opFMRX = InstructionSet.opFMRX; opFMSCD = InstructionSet.opFMSCD;
  40. opFMSCS = InstructionSet.opFMSCS; opFMSR = InstructionSet.opFMSR;
  41. opFMSTAT = InstructionSet.opFMSTAT; opFMULD = InstructionSet.opFMULD;
  42. opFMULS = InstructionSet.opFMULS; opFMXR = InstructionSet.opFMXR;
  43. opFNEGD = InstructionSet.opFNEGD; opFNEGS = InstructionSet.opFNEGS;
  44. opFNMACD = InstructionSet.opFNMACD; opFNMACS = InstructionSet.opFNMACS;
  45. opFNMSCD = InstructionSet.opFNMSCD; opFNMSCS = InstructionSet.opFNMSCS;
  46. opFNMULD = InstructionSet.opFNMULD ; opFNMULS = InstructionSet.opFNMULS;
  47. opFSITOD = InstructionSet.opFSITOD; opFSITOS = InstructionSet.opFSITOS;
  48. opFSQRTD = InstructionSet.opFSQRTD; opFSQRTS = InstructionSet.opFSQRTS;
  49. opFSTD = InstructionSet.opFSTD; opFSTMIAD = InstructionSet.opFSTMIAD;
  50. opFSTMIAS = InstructionSet.opFSTMIAS; opFSTMIAX = InstructionSet.opFSTMIAX;
  51. opFSTMDBD = InstructionSet.opFSTMDBD; opFSTMDBS = InstructionSet.opFSTMDBS;
  52. opFSTMDBX = InstructionSet.opFSTMDBX; opFSTS = InstructionSet.opFSTS;
  53. opFSUBD = InstructionSet.opFSUBD; opFSUBS = InstructionSet.opFSUBS;
  54. opFTOSID = InstructionSet.opFTOSID; opFTOSIZD = InstructionSet.opFTOSIZD;
  55. opFTOSIS = InstructionSet.opFTOSIS; opFTOSIZS = InstructionSet.opFTOSIZS;
  56. opFTOUID = InstructionSet.opFTOUID; opFTOUIZD = InstructionSet.opFTOUIZD;
  57. opFTOUIS = InstructionSet.opFTOUIS; opFTOUIZS = InstructionSet.opFTOUIZS;
  58. opFUITOD = InstructionSet.opFUITOD; opFUITOS = InstructionSet.opFUITOS;
  59. opLDC = InstructionSet.opLDC; opLDC2 = InstructionSet.opLDC2;
  60. opLDM = InstructionSet.opLDM; opLDR = InstructionSet.opLDR;
  61. opLDREX = InstructionSet.opLDREX; opSTREX = InstructionSet.opSTREX;
  62. opMCR = InstructionSet.opMCR; opMCR2 = InstructionSet.opMCR2;
  63. opMCRR = InstructionSet.opMCRR; opMLA = InstructionSet.opMLA;
  64. opMOV = InstructionSet.opMOV; opMRC = InstructionSet.opMRC;
  65. opMRC2 = InstructionSet.opMRC2; opMRRC = InstructionSet.opMRRC;
  66. opMRS = InstructionSet.opMRS; opMSR = InstructionSet.opMSR;
  67. opMUL = InstructionSet.opMUL; opMVN = InstructionSet.opMVN;
  68. opORR = InstructionSet.opORR; opPLD = InstructionSet.opPLD;
  69. opQADD = InstructionSet.opQADD; opQDADD = InstructionSet.opQDADD;
  70. opQDSUB = InstructionSet.opQDSUB; opQSUB = InstructionSet.opQSUB;
  71. opRSB = InstructionSet.opRSB; opRSC = InstructionSet.opRSC;
  72. opSBC = InstructionSet.opSBC; opSMLABB = InstructionSet.opSMLABB;
  73. opSMLABT = InstructionSet.opSMLABT; opSMLAL = InstructionSet.opSMLAL;
  74. opSMLATB = InstructionSet.opSMLATB; opSMLATT = InstructionSet.opSMLATT;
  75. opSMLALBB = InstructionSet.opSMLALBB; opSMLALBT = InstructionSet.opSMLALBT;
  76. opSMLALTB = InstructionSet.opSMLALTB; opSMLALTT = InstructionSet.opSMLALTT;
  77. opSMLAWB = InstructionSet.opSMLAWB; opSMLAWT = InstructionSet.opSMLAWT;
  78. opSMULBB = InstructionSet.opSMULBB; opSMULBT = InstructionSet.opSMULBT;
  79. opSMULTB = InstructionSet.opSMULTB; opSMULTT = InstructionSet.opSMULTT;
  80. opSMULWB = InstructionSet.opSMULWB; opSMULWT = InstructionSet.opSMULWT;
  81. opSMULL = InstructionSet.opSMULL; opSTC = InstructionSet.opSTC;
  82. opSTC2 = InstructionSet.opSTC2; opSTM = InstructionSet.opSTM;
  83. opSTR = InstructionSet.opSTR; opSUB = InstructionSet.opSUB;
  84. opSWI = InstructionSet.opSWI; opSWP = InstructionSet.opSWP;
  85. opTEQ = InstructionSet.opTEQ; opTST = InstructionSet.opTST;
  86. opUMLAL = InstructionSet.opUMLAL; opUMULL = InstructionSet.opUMULL;
  87. (* builtin backend specific system instructions *)
  88. GetSP = 0; SetSP = 1;
  89. GetFP = 2; SetFP = 3;
  90. GetLNK = 4; SetLNK = 5;
  91. GetPC = 6; SetPC = 7;
  92. LDPSR = 8; STPSR = 9;
  93. LDCPR = 10; STCPR = 11;
  94. FLUSH = 12;
  95. NULL = 13; XOR = 14; MULD = 15; ADDC = 16;
  96. PACK = 17; UNPK = 18;
  97. UseFPU32Flag = "useFPU32";
  98. UseFPU64Flag = "useFPU64";
  99. TYPE
  100. Operand = InstructionSet.Operand;
  101. Ticket = CodeGenerators.Ticket;
  102. (* a citation of a symbol, i.e., an ARM instruction that requires a symbol's address *)
  103. Citation = OBJECT
  104. VAR
  105. pc: LONGINT; (* program counter of the ARM instruction *)
  106. bits: SIZE;
  107. shift: SIZE; (* fixup shift ! *)
  108. next: Citation;
  109. END Citation;
  110. (* a reference to a symbol and offset in IR units that is used by at least one instruction *)
  111. Reference = OBJECT
  112. VAR
  113. firstCitation, lastCitation: Citation; (* linked list of citations *)
  114. next: Reference;
  115. size: SIZE; (* storage size of this reference *)
  116. PROCEDURE & Init(size: SIZE);
  117. BEGIN
  118. firstCitation := NIL; lastCitation := NIL; next := NIL; SELF.size := size;
  119. END Init;
  120. PROCEDURE Emit(out: BinaryCode.Section);
  121. BEGIN
  122. HALT(100);
  123. END Emit;
  124. PROCEDURE AddCitation(pc: LONGINT; bits: SIZE; shift: SIZE);
  125. VAR
  126. citation: Citation;
  127. BEGIN
  128. NEW(citation); citation.pc := pc; citation.next := NIL; citation.bits := bits; citation.shift := shift;
  129. IF firstCitation = NIL THEN firstCitation := citation ELSE lastCitation.next := citation END;
  130. lastCitation := citation
  131. END AddCitation;
  132. END Reference;
  133. ImmediateReference = OBJECT (Reference)
  134. VAR value: LONGINT;
  135. PROCEDURE & InitImm(v: LONGINT);
  136. BEGIN
  137. Init(4);
  138. SELF.value := v;
  139. END InitImm;
  140. PROCEDURE Emit(out: BinaryCode.Section);
  141. BEGIN
  142. IF out.comments # NIL THEN
  143. out.comments.String("longint/real");
  144. out.comments.Ln; out.comments.Update
  145. END;
  146. out.PutBits(value,32);
  147. END Emit;
  148. END ImmediateReference;
  149. ImmediateHReference = OBJECT (Reference)
  150. VAR value: HUGEINT;
  151. PROCEDURE & InitImm(v: HUGEINT);
  152. BEGIN
  153. Init(8);
  154. SELF.value := v;
  155. END InitImm;
  156. PROCEDURE Emit(out: BinaryCode.Section);
  157. BEGIN
  158. IF out.comments # NIL THEN
  159. out.comments.String("hugeint/longreal");
  160. out.comments.Ln; out.comments.Update
  161. END;
  162. (* assumption: big endian *)
  163. out.PutBits(SHORT(value),32);
  164. out.PutBits(SHORT(ASH(value,-32)),32);
  165. END Emit;
  166. END ImmediateHReference;
  167. (* a reference to a symbol and offset in IR units that is used by at least one instruction *)
  168. SymbolReference = OBJECT (Reference)
  169. VAR
  170. identifier: ObjectFile.Identifier;
  171. symbolOffset: LONGINT; (* offset to the symbol in IR units *)
  172. PROCEDURE & InitSym(s: Sections.SectionName; fp: LONGINT; offs: LONGINT);
  173. BEGIN
  174. Init(4);
  175. identifier.name := s;
  176. identifier.fingerprint := fp;
  177. symbolOffset := offs;
  178. END InitSym;
  179. PROCEDURE Emit(out: BinaryCode.Section);
  180. VAR
  181. fixup: BinaryCode.Fixup;
  182. BEGIN
  183. IF out.comments # NIL THEN
  184. out.comments.String("fixup location for ");
  185. Basic.WriteSegmentedName(out.comments, identifier.name);
  186. out.comments.String(":"); out.comments.Int(symbolOffset, 0);
  187. out.comments.String(" :"); out.comments.Ln; out.comments.Update
  188. END;
  189. fixup := BinaryCode.NewFixup(BinaryCode.Absolute, out.pc, identifier, symbolOffset, 0, 0, rFixupPattern);
  190. out.fixupList.AddFixup(fixup);
  191. out.PutBits(0, 32);
  192. END Emit;
  193. END SymbolReference;
  194. ListOfReferences = OBJECT
  195. VAR
  196. firstReference, lastReference: Reference; (* linked list of all symbol references *)
  197. size: SIZE; (* length of the required fixup block *)
  198. due: SIZE; (* the PC at which the reference block has to be written (the latest) *)
  199. PROCEDURE & Init;
  200. BEGIN
  201. firstReference := NIL; lastReference := NIL;
  202. size := 0;
  203. due := MAX(SIZE);
  204. END Init;
  205. PROCEDURE UpdateDue(pc: SIZE; bits: SIZE; shift: SIZE);
  206. VAR max: SIZE;
  207. BEGIN
  208. (* bits determine the address size in words *)
  209. max := ASH(1, bits+shift) (* maximal fixup range *) + pc (* current pc *) - size (* fixup block size as of now *) - 8 (* offset *) - 64 (* 16 instructions safety *);
  210. IF max < due THEN
  211. due := max;
  212. END;
  213. END UpdateDue;
  214. PROCEDURE AddCitation(reference: Reference; pc: SIZE; bits: SIZE; shift: SIZE);
  215. BEGIN
  216. reference.AddCitation(pc, bits, shift);
  217. UpdateDue(pc, bits, shift);
  218. END AddCitation;
  219. PROCEDURE AddReference(reference: Reference): Reference;
  220. BEGIN
  221. IF firstReference = NIL THEN firstReference := reference ELSE lastReference.next := reference END;
  222. lastReference := reference;
  223. INC(size, reference.size);
  224. RETURN reference;
  225. END AddReference;
  226. PROCEDURE AddSymbol(symbol: Sections.SectionName; fingerprint: LONGINT; symbolOffset: LONGINT; pc: LONGINT; bits: LONGINT);
  227. VAR
  228. reference, foundReference: Reference; symbolReference: SymbolReference;
  229. BEGIN
  230. (* go through the list of symbol/offset-combinations and check if there already is an entry for the symbol and offset in question *)
  231. reference := firstReference;
  232. WHILE reference # NIL DO
  233. IF reference IS SymbolReference THEN
  234. WITH reference: SymbolReference DO
  235. IF (reference.identifier.name = symbol) & (reference.symbolOffset = symbolOffset) THEN
  236. foundReference := reference (* an entry already exists *)
  237. END;
  238. END;
  239. END;
  240. reference := reference.next
  241. END;
  242. IF foundReference # NIL THEN
  243. reference := foundReference
  244. ELSE
  245. (* no entry was found for the symbol/offset combination: create a new one *)
  246. NEW(symbolReference, symbol, fingerprint, symbolOffset);
  247. reference := AddReference(symbolReference);
  248. END;
  249. (* add a citation to the reference *)
  250. AddCitation(reference, pc, bits, 0);
  251. END AddSymbol;
  252. PROCEDURE AddImmediate(value: LONGINT; pc: SIZE; bits: SIZE);
  253. VAR
  254. reference, foundReference: Reference; immediateReference: ImmediateReference;
  255. BEGIN
  256. (* go through the list of symbol/offset-combinations and check if there already is an entry for the symbol and offset in question *)
  257. reference := firstReference;
  258. WHILE reference # NIL DO
  259. IF reference IS ImmediateReference THEN
  260. WITH reference: ImmediateReference DO
  261. IF (reference.value = value) THEN
  262. foundReference := reference (* an entry already exists *)
  263. END;
  264. END;
  265. END;
  266. reference := reference.next
  267. END;
  268. IF foundReference # NIL THEN
  269. reference := foundReference
  270. ELSE
  271. (* no entry was found for the symbol/offset combination: create a new one *)
  272. NEW(immediateReference, value);
  273. reference := AddReference(immediateReference);
  274. END;
  275. (* add a citation to the reference *)
  276. AddCitation(reference, pc, bits, 0);
  277. END AddImmediate;
  278. PROCEDURE AddHImmediate(value: HUGEINT; pc: LONGINT; bits: SIZE);
  279. VAR
  280. reference, foundReference: Reference; immediateHReference: ImmediateHReference;
  281. BEGIN
  282. (* go through the list of symbol/offset-combinations and check if there already is an entry for the symbol and offset in question *)
  283. reference := firstReference;
  284. WHILE reference # NIL DO
  285. IF reference IS ImmediateHReference THEN
  286. WITH reference: ImmediateHReference DO
  287. IF (reference.value = value) THEN
  288. foundReference := reference (* an entry already exists *)
  289. END;
  290. END;
  291. END;
  292. reference := reference.next
  293. END;
  294. IF foundReference # NIL THEN
  295. reference := foundReference
  296. ELSE
  297. (* no entry was found for the symbol/offset combination: create a new one *)
  298. NEW(immediateHReference, value);
  299. reference := AddReference(immediateHReference);
  300. END;
  301. (* add a citation to the reference *)
  302. AddCitation(reference, pc, bits, 2);
  303. END AddHImmediate;
  304. END ListOfReferences;
  305. PhysicalRegisters* = OBJECT(CodeGenerators.PhysicalRegisters)
  306. VAR
  307. toVirtual: ARRAY InstructionSet.NumberRegisters OF Ticket; (* registers real register -> none / reserved / split / blocked / virtual register (>0) *)
  308. reserved: ARRAY InstructionSet.NumberRegisters OF BOOLEAN;
  309. unusable: Ticket;
  310. blocked: Ticket;
  311. hint: LONGINT;
  312. useFPU32:BOOLEAN;
  313. useFPU64:BOOLEAN;
  314. PROCEDURE & InitPhysicalRegisters(supportFramePointer, useFPU32, useFPU64, cooperative: BOOLEAN);
  315. VAR
  316. i: LONGINT;
  317. unusable: Ticket;
  318. BEGIN
  319. SELF.useFPU32 := useFPU32;
  320. SELF.useFPU64 := useFPU64;
  321. FOR i := 0 TO LEN(toVirtual) - 1 DO
  322. toVirtual[i] := NIL;
  323. reserved[i] := FALSE
  324. END;
  325. NEW(unusable);
  326. NEW(blocked);
  327. (* reserve special purpose registers *)
  328. toVirtual[InstructionSet.RES] := unusable; (* low part result register *)
  329. toVirtual[InstructionSet.RESHI] := unusable; (* high part result register *)
  330. toVirtual[InstructionSet.RESFS] := unusable; (* single precision floatin point result register *)
  331. toVirtual[InstructionSet.RESFD] := unusable; (* single precision floatin point result register *)
  332. toVirtual[InstructionSet.SP] := unusable; (* stack pointer *)
  333. toVirtual[InstructionSet.FP] := unusable; (* frame pointer *)
  334. toVirtual[InstructionSet.PC] := unusable; (* program counter *)
  335. toVirtual[InstructionSet.LR] := unusable; (* link register *)
  336. toVirtual[InstructionSet.CPSR] := unusable; (* current program state register *)
  337. toVirtual[InstructionSet.SPSR] := unusable; (* saved program state register *)
  338. IF cooperative THEN
  339. toVirtual[InstructionSet.R11] := unusable; (* current activity register *)
  340. END;
  341. (* disable coprocessor registers *)
  342. FOR i := InstructionSet.CR0 TO InstructionSet.CR15 DO toVirtual[i] := unusable END;
  343. IF ~useFPU32 THEN
  344. (* disable single precision VFP registers *)
  345. FOR i := InstructionSet.SR0 TO InstructionSet.SR31 DO toVirtual[i] := unusable END
  346. END;
  347. IF ~useFPU64 THEN
  348. (* disable double precision VFP registers *)
  349. FOR i := InstructionSet.DR0 TO InstructionSet.DR31 DO toVirtual[i] := unusable END;
  350. END;
  351. END InitPhysicalRegisters;
  352. (** the number of physical registers **)
  353. PROCEDURE NumberRegisters(): LONGINT;
  354. BEGIN RETURN InstructionSet.NumberRegisters
  355. END NumberRegisters;
  356. (** allocate, i.e., map, a physical register to a ticket **)
  357. PROCEDURE Allocate(physicalRegisterNumber: LONGINT; ticket: Ticket);
  358. VAR index: LONGINT;
  359. BEGIN
  360. ASSERT(~ticket.spilled);
  361. Assert(toVirtual[physicalRegisterNumber] = NIL,"register already allocated");
  362. toVirtual[physicalRegisterNumber] := ticket;
  363. (* FP register overlap: *)
  364. IF (InstructionSet.SR0 <= physicalRegisterNumber) & (physicalRegisterNumber <= InstructionSet.SR31) THEN
  365. index := physicalRegisterNumber - InstructionSet.SR0;
  366. toVirtual[InstructionSet.DR0 + index DIV 2] := blocked;
  367. ELSIF (InstructionSet.DR0 <= physicalRegisterNumber) & (physicalRegisterNumber <= InstructionSet.DR31) THEN
  368. index := physicalRegisterNumber - InstructionSet.DR0;
  369. IF index*2 < 32 THEN
  370. toVirtual[InstructionSet.SR0 + index *2] := blocked;
  371. toVirtual[InstructionSet.SR0 + index *2 + 1] := blocked;
  372. END;
  373. END;
  374. END Allocate;
  375. (** set whether a certain physical register is reserved or not **)
  376. PROCEDURE SetReserved(physicalRegisterNumber: LONGINT; isReserved: BOOLEAN);
  377. BEGIN reserved[physicalRegisterNumber] := isReserved
  378. END SetReserved;
  379. (** whether a certain physical register is reserved **)
  380. PROCEDURE Reserved(physicalRegisterNumber: LONGINT): BOOLEAN;
  381. BEGIN RETURN (physicalRegisterNumber > 0) & reserved[physicalRegisterNumber]
  382. END Reserved;
  383. (** free a certain physical register **)
  384. PROCEDURE Free(physicalRegisterNumber: LONGINT);
  385. VAR index: LONGINT;
  386. BEGIN
  387. Assert((toVirtual[physicalRegisterNumber] # NIL), "register not reserved");
  388. toVirtual[physicalRegisterNumber] := NIL;
  389. (* FP register overlap: *)
  390. IF (InstructionSet.SR0 <= physicalRegisterNumber) & (physicalRegisterNumber <= InstructionSet.SR31) THEN
  391. index := physicalRegisterNumber - InstructionSet.SR0;
  392. IF ODD(index) & (toVirtual[InstructionSet.SR0+index-1] = NIL) OR
  393. ~ODD(index) & (toVirtual[InstructionSet.SR0+index+1] = NIL) THEN
  394. ASSERT(toVirtual[InstructionSet.DR0 + index DIV 2] = blocked);
  395. toVirtual[InstructionSet.DR0 + index DIV 2] := NIL;
  396. END;
  397. ELSIF (InstructionSet.DR0 <= physicalRegisterNumber) & (physicalRegisterNumber <= InstructionSet.DR31) THEN
  398. index := physicalRegisterNumber - InstructionSet.DR0;
  399. IF index*2 < 32 THEN
  400. ASSERT(toVirtual[InstructionSet.SR0 + index *2] = blocked);
  401. ASSERT(toVirtual[InstructionSet.SR0 + index *2+1] = blocked);
  402. toVirtual[InstructionSet.SR0 + index *2] := NIL;
  403. toVirtual[InstructionSet.SR0 + index *2 + 1] := NIL;
  404. END;
  405. END;
  406. END Free;
  407. (** get the number of the next free physical register for a certain data type
  408. - if a register hint has been set, it is respected if possible
  409. **)
  410. PROCEDURE NextFree(CONST type: IntermediateCode.Type): LONGINT;
  411. VAR
  412. result, i: LONGINT;
  413. BEGIN
  414. result := None;
  415. IF (type.form IN IntermediateCode.Integer) THEN
  416. ASSERT(type.sizeInBits <= 32); (* integers of larger size have already been split *)
  417. (* allocate a regular general purpose ARM register *)
  418. FOR i := InstructionSet.R0 TO InstructionSet.R15 DO
  419. IF (toVirtual[i] = NIL) & ((result = None) OR (i = hint)) THEN result := i END
  420. END
  421. ELSIF type.form = IntermediateCode.Float THEN
  422. IF (type.sizeInBits = 32) & useFPU32 THEN
  423. (* allocate a single precision VFP register *)
  424. FOR i := InstructionSet.SR0 TO InstructionSet.SR31 DO
  425. IF (toVirtual[i] = NIL) & ((result = None) OR (i = hint)) THEN result := i; END;
  426. END;
  427. ELSIF (type.sizeInBits = 64) & (useFPU64) THEN
  428. FOR i := InstructionSet.DR0 TO InstructionSet.DR31 DO
  429. IF (toVirtual[i] = NIL) & ((result = None) OR (i = hint)) THEN result := i END;
  430. END;
  431. ELSE
  432. (* allocate a regular general purpose ARM register *)
  433. FOR i := InstructionSet.R0 TO InstructionSet.R15 DO
  434. IF (toVirtual[i] = NIL) & ((result = None) OR (i = hint)) THEN result := i END
  435. END
  436. END
  437. ELSE
  438. HALT(100)
  439. END;
  440. IF result # None THEN ASSERT(toVirtual[result] = NIL) END;
  441. RETURN result
  442. END NextFree;
  443. (** give the register allocator a hint on what physical register to use next **)
  444. PROCEDURE AllocationHint(physicalRegisterNumber: LONGINT);
  445. BEGIN hint := physicalRegisterNumber
  446. END AllocationHint;
  447. (** get the ticket that is currently mapped to a certain physical register **)
  448. PROCEDURE Mapped(physicalRegisterNumber: LONGINT): Ticket;
  449. BEGIN RETURN toVirtual[physicalRegisterNumber]
  450. END Mapped;
  451. (** dump the current register mapping to a stream **)
  452. PROCEDURE Dump(w: Streams.Writer);
  453. VAR i: LONGINT; virtual: Ticket;
  454. BEGIN
  455. w.String("---- registers ----"); w.Ln;
  456. FOR i := 0 TO LEN(toVirtual)-1 DO
  457. virtual := toVirtual[i];
  458. IF (virtual # unusable) & (virtual # blocked) THEN
  459. w.String("reg "); w.Int(i,1); w.String(": ");
  460. IF virtual = NIL THEN w.String("free")
  461. ELSE w.String(" r"); w.Int(virtual.register,1);
  462. END;
  463. IF reserved[i] THEN w.String("reserved") END;
  464. w.Ln
  465. END
  466. END
  467. END Dump;
  468. END PhysicalRegisters;
  469. CodeGeneratorARM = OBJECT(CodeGenerators.GeneratorWithTickets)
  470. VAR
  471. runtimeModuleName: SyntaxTree.IdentifierString;
  472. backend: BackendARM;
  473. opSP, opFP, opPC, opLR, opRES, opRESHI, opRESFS, opRESFD, fpscr: InstructionSet.Operand;
  474. listOfReferences: ListOfReferences;
  475. spillStackStart, pushChainLength: LONGINT;
  476. stackSize: LONGINT; (* the size of the current stack frame *)
  477. stackSizeKnown: BOOLEAN; (* whether the size of the current stack frame is known at compile time *)
  478. inStackAllocation: BOOLEAN;
  479. PROCEDURE & InitGeneratorARM(CONST runtimeModuleName: SyntaxTree.IdentifierString; diagnostics: Diagnostics.Diagnostics; backend: BackendARM);
  480. VAR
  481. physicalRegisters: PhysicalRegisters;
  482. BEGIN
  483. SELF.runtimeModuleName := runtimeModuleName;
  484. SELF.backend := backend;
  485. IF Trace THEN IF backend.useFPU32 THEN D.String("use FPU"); D.Ln ELSE D.String("don't use FPU"); D.Ln END END;
  486. NEW(physicalRegisters, TRUE, backend.useFPU32, backend.useFPU64, backend.cooperative);
  487. InitTicketGenerator(diagnostics, backend.optimize, 2, physicalRegisters);
  488. error := FALSE;
  489. inStackAllocation := FALSE;
  490. pushChainLength := 0;
  491. opSP := InstructionSet.NewRegister(InstructionSet.SP, None, None, 0);
  492. opFP := InstructionSet.NewRegister(InstructionSet.FP, None, None, 0);
  493. opPC := InstructionSet.NewRegister(InstructionSet.PC, None, None, 0);
  494. opLR := InstructionSet.NewRegister(InstructionSet.LR, None, None, 0);
  495. opRES := InstructionSet.NewRegister(InstructionSet.RES, None, None, 0);
  496. opRESHI := InstructionSet.NewRegister(InstructionSet.RESHI, None, None, 0);
  497. opRESFS := InstructionSet.NewRegister(InstructionSet.RESFS, None, None, 0);
  498. opRESFD := InstructionSet.NewRegister(InstructionSet.RESFD, None, None, 0);
  499. fpscr := InstructionSet.NewRegister(InstructionSet.FPSCR, None, None, 0);
  500. dump := NIL;
  501. NEW(listOfReferences);
  502. END InitGeneratorARM;
  503. (*------------------- overwritten methods ----------------------*)
  504. (* TODO: revise this *)
  505. PROCEDURE Section(in: IntermediateCode.Section; out: BinaryCode.Section);
  506. VAR
  507. oldSpillStackSize: LONGINT;
  508. PROCEDURE CheckEmptySpillStack(): BOOLEAN;
  509. BEGIN
  510. IF spillStack.Size() # 0 THEN
  511. Error(inPC,"implementation error, spill stack not cleared");
  512. IF dump # NIL THEN
  513. spillStack.Dump(dump);
  514. tickets.Dump(dump)
  515. END;
  516. RETURN FALSE
  517. ELSE
  518. RETURN TRUE
  519. END
  520. END CheckEmptySpillStack;
  521. BEGIN
  522. stackSizeKnown := TRUE;
  523. stackSize := 0; (* TODO: ok? *)
  524. tickets.Init; spillStack.Init; listOfReferences.Init;
  525. Section^(in, out); (* pass 1 *)
  526. EmitFinalFixupBlock; (* force the emission of fixups for all references *)
  527. IF stackSizeKnown = FALSE THEN
  528. tickets.Init; spillStack.Init; listOfReferences.Init;
  529. out.Reset;
  530. Section^(in, out); (* pass 2 *)
  531. EmitFinalFixupBlock (* force the emission of fixups for all references *)
  532. END;
  533. IF CheckEmptySpillStack() & (spillStack.MaxSize() > 0) THEN
  534. listOfReferences.Init;
  535. oldSpillStackSize := spillStack.MaxSize();
  536. out.Reset;
  537. Section^(in, out); (* pass 3 *)
  538. EmitFinalFixupBlock; (* force the emission of fixups for all references *)
  539. ASSERT(spillStack.MaxSize() = oldSpillStackSize);
  540. END;
  541. IF CheckEmptySpillStack() THEN END
  542. END Section;
  543. (* TODO: complete this *)
  544. (** whether the code generator can generate code for a certain intermediate code intstruction
  545. if not, the location of a runtime is returned **)
  546. PROCEDURE Supported(CONST irInstruction: IntermediateCode.Instruction; VAR moduleName, procedureName: ARRAY OF CHAR): BOOLEAN;
  547. VAR
  548. result: BOOLEAN; value: HUGEINT; exp: LONGINT;
  549. BEGIN
  550. CASE irInstruction.opcode OF
  551. | IntermediateCode.add, IntermediateCode.sub, IntermediateCode.mul, IntermediateCode.abs, IntermediateCode.neg:
  552. IF (irInstruction.opcode = IntermediateCode.mul) & IsInteger(irInstruction.op1) & IsInteger(irInstruction.op2) & (IsComplex(irInstruction.op1) OR IsComplex(irInstruction.op2)) THEN
  553. result := FALSE;
  554. ELSE
  555. result := ~IsFloat(irInstruction.op1) OR backend.useFPU32 & IsSinglePrecisionFloat(irInstruction.op1) OR backend.useFPU64 & IsDoublePrecisionFloat(irInstruction.op1);
  556. END;
  557. | IntermediateCode.div:
  558. result := backend.useFPU32 & IsSinglePrecisionFloat(irInstruction.op1)
  559. OR backend.useFPU64 & IsDoublePrecisionFloat(irInstruction.op1)
  560. OR backend.useFPU64 & IsNonComplexInteger(irInstruction.op1);
  561. result := result OR IntermediateCode.IsConstantInteger(irInstruction.op3,value) & IntermediateBackend.PowerOf2(value,exp)
  562. | IntermediateCode.conv:
  563. IF IsInteger64(irInstruction.op1) & IsFloat(irInstruction.op2) THEN (* ENTIERH: REAL/LONGREAL --> HUGEINT*)
  564. result := FALSE
  565. ELSIF IsInteger64(irInstruction.op2) & IsFloat(irInstruction.op1) THEN (* HUGEINT --> REAL / HUGEINT --> LONGREAL *)
  566. result := FALSE;
  567. ELSE
  568. result := ~IsFloat(irInstruction.op1) & ~IsFloat(irInstruction.op2)
  569. OR backend.useFPU32 & ~IsDoublePrecisionFloat(irInstruction.op1) & ~IsDoublePrecisionFloat(irInstruction.op2)
  570. OR backend.useFPU64;
  571. END;
  572. | IntermediateCode.mod:
  573. result := IntermediateCode.IsConstantInteger(irInstruction.op3,value) & IntermediateBackend.PowerOf2(value,exp)
  574. | IntermediateCode.rol, IntermediateCode.ror:
  575. result := ~IsComplex(irInstruction.op1)
  576. ELSE
  577. result := TRUE
  578. END;
  579. IF ~result THEN
  580. COPY(runtimeModuleName, moduleName);
  581. GetRuntimeProcedureName(irInstruction, procedureName);
  582. END;
  583. RETURN result
  584. END Supported;
  585. (* determines the name of a runtime procedure to handle a certain IR instruction *)
  586. PROCEDURE GetRuntimeProcedureName(CONST irInstruction: IntermediateCode.Instruction; VAR resultingName: ARRAY OF CHAR);
  587. PROCEDURE AppendType(VAR string: ARRAY OF CHAR; type: IntermediateCode.Type);
  588. VAR
  589. sizeString: ARRAY 3 OF CHAR;
  590. BEGIN
  591. CASE type.form OF
  592. | IntermediateCode.SignedInteger: Strings.AppendChar(string, 'S')
  593. | IntermediateCode.UnsignedInteger: Strings.AppendChar(string, 'U')
  594. | IntermediateCode.Float:Strings.AppendChar(string, 'F')
  595. ELSE HALT(200)
  596. END;
  597. Strings.IntToStr(type.sizeInBits, sizeString); Strings.Append(string, sizeString)
  598. END AppendType;
  599. BEGIN
  600. COPY(IntermediateCode.instructionFormat[irInstruction.opcode].name, resultingName);
  601. Strings.UpperCaseChar(resultingName[0]);
  602. AppendType(resultingName, irInstruction.op1.type);
  603. IF irInstruction.op1.mode # IntermediateCode.Undefined THEN
  604. IF (irInstruction.op1.type.form # irInstruction.op2.type.form) OR (irInstruction.op1.type.sizeInBits # irInstruction.op2.type.sizeInBits) THEN
  605. AppendType(resultingName, irInstruction.op2.type);
  606. (* special case: result returned in FPU register *)
  607. IF IsSinglePrecisionFloat(irInstruction.op1) & backend.useFPU32 THEN
  608. Strings.Append(resultingName, 'F')
  609. ELSIF IsDoublePrecisionFloat(irInstruction.op1) & backend.useFPU64 THEN
  610. Strings.Append(resultingName, 'F')
  611. END;
  612. END
  613. END;
  614. IF Trace THEN D.Ln; D.String(" runtime procedure name: "); D.String(resultingName); D.Ln; D.Update END
  615. END GetRuntimeProcedureName;
  616. (* check whether the instruction modifies the stack pointer (outside of a stack allocation )*)
  617. PROCEDURE CheckStackPointer(CONST destination: Operand);
  618. BEGIN
  619. IF stackSizeKnown & ~inStackAllocation THEN
  620. IF (destination.mode = InstructionSet.modeRegister) & (destination.register = InstructionSet.SP) THEN
  621. IF dump # NIL THEN dump.String("stackSize unkown"); dump.Ln END;
  622. stackSizeKnown := FALSE
  623. END
  624. END
  625. END CheckStackPointer;
  626. (** emit an ARM instruction with an arbitrary amount of operands **)
  627. PROCEDURE Emit(opCode, condition: LONGINT; flags: SET; CONST operands: ARRAY InstructionSet.MaxOperands OF Operand);
  628. VAR
  629. BEGIN
  630. (* check whether the instruction modifies the stack pointer *)
  631. CheckStackPointer(operands[0]);
  632. (*
  633. (* dump the instruction *)
  634. IF Trace THEN
  635. D.String("opCode="); D.Int(opCode, 0); D.Ln;
  636. D.String("condition="); D.Int(condition, 0); D.Ln;
  637. D.String("flags="); D.Set(flags); D.Ln;
  638. FOR i := 0 TO InstructionSet.MaxOperands - 1 DO
  639. D.String("operand #"); D.Int(i, 0); D.String(": ");
  640. InstructionSet.DumpOperand(D.Log, operands[i]);
  641. D.Ln
  642. END;
  643. D.Ln;
  644. D.Ln
  645. END;
  646. *)
  647. (* emit the instruction *)
  648. InstructionSet.Emit(opCode, condition, flags, operands, out);
  649. END Emit;
  650. (** emit an ARM instruction with no operand **)
  651. PROCEDURE Emit0(opCode: LONGINT);
  652. VAR
  653. operands: ARRAY InstructionSet.MaxOperands OF Operand;
  654. BEGIN
  655. ASSERT(InstructionSet.MaxOperands = 6);
  656. operands[0] := emptyOperand;
  657. operands[1] := emptyOperand;
  658. operands[2] := emptyOperand;
  659. operands[3] := emptyOperand;
  660. operands[4] := emptyOperand;
  661. operands[5] := emptyOperand;
  662. Emit(opCode, InstructionSet.unconditional, {}, operands)
  663. END Emit0;
  664. (** emit an ARM instruction with 1 operand **)
  665. PROCEDURE Emit1(opCode: LONGINT; op: Operand);
  666. VAR
  667. operands: ARRAY InstructionSet.MaxOperands OF Operand;
  668. BEGIN
  669. ASSERT(InstructionSet.MaxOperands = 6);
  670. operands[0] := op;
  671. operands[1] := emptyOperand;
  672. operands[2] := emptyOperand;
  673. operands[3] := emptyOperand;
  674. operands[4] := emptyOperand;
  675. operands[5] := emptyOperand;
  676. Emit(opCode, InstructionSet.unconditional, {}, operands)
  677. END Emit1;
  678. (** emit an ARM instruction with 2 operands **)
  679. PROCEDURE Emit2(opCode: LONGINT; op1, op2: Operand);
  680. VAR
  681. operands: ARRAY InstructionSet.MaxOperands OF Operand;
  682. BEGIN
  683. ASSERT(InstructionSet.MaxOperands = 6);
  684. operands[0] := op1;
  685. operands[1] := op2;
  686. operands[2] := emptyOperand;
  687. operands[3] := emptyOperand;
  688. operands[4] := emptyOperand;
  689. operands[5] := emptyOperand;
  690. Emit(opCode, InstructionSet.unconditional, {}, operands)
  691. END Emit2;
  692. (** emit an ARM instruction with 3 operands **)
  693. PROCEDURE Emit3(opCode: LONGINT; op1, op2, op3: Operand);
  694. VAR
  695. operands: ARRAY InstructionSet.MaxOperands OF Operand;
  696. BEGIN
  697. ASSERT(InstructionSet.MaxOperands = 6);
  698. operands[0] := op1;
  699. operands[1] := op2;
  700. operands[2] := op3;
  701. operands[3] := emptyOperand;
  702. operands[4] := emptyOperand;
  703. operands[5] := emptyOperand;
  704. Emit(opCode, InstructionSet.unconditional, {}, operands)
  705. END Emit3;
  706. (** emit an ARM instruction with 4 operands **)
  707. PROCEDURE Emit4(opCode: LONGINT; op1, op2, op3, op4: Operand);
  708. VAR
  709. operands: ARRAY InstructionSet.MaxOperands OF Operand;
  710. BEGIN
  711. ASSERT(InstructionSet.MaxOperands = 6);
  712. operands[0] := op1;
  713. operands[1] := op2;
  714. operands[2] := op3;
  715. operands[3] := op4;
  716. operands[4] := emptyOperand;
  717. operands[5] := emptyOperand;
  718. Emit(opCode, InstructionSet.unconditional, {}, operands)
  719. END Emit4;
  720. (** emit an ARM instruction with 6 operands **)
  721. PROCEDURE Emit6(opCode: LONGINT; op1, op2, op3, op4, op5, op6: Operand);
  722. VAR
  723. operands: ARRAY InstructionSet.MaxOperands OF Operand;
  724. BEGIN
  725. ASSERT(InstructionSet.MaxOperands = 6);
  726. operands[0] := op1;
  727. operands[1] := op2;
  728. operands[2] := op3;
  729. operands[3] := op4;
  730. operands[4] := op5;
  731. operands[5] := op6;
  732. Emit(opCode, InstructionSet.unconditional, {}, operands)
  733. END Emit6;
  734. (** emit an ARM instruction with 2 operands and certain flags **)
  735. PROCEDURE Emit2WithFlags(opCode: LONGINT; op1, op2: Operand; flags: SET);
  736. VAR
  737. operands: ARRAY InstructionSet.MaxOperands OF Operand;
  738. BEGIN
  739. ASSERT(InstructionSet.MaxOperands = 6);
  740. operands[0] := op1;
  741. operands[1] := op2;
  742. operands[2] := emptyOperand;
  743. operands[3] := emptyOperand;
  744. operands[4] := emptyOperand;
  745. operands[5] := emptyOperand;
  746. Emit(opCode, InstructionSet.unconditional, flags, operands)
  747. END Emit2WithFlags;
  748. (** emit an ARM instruction with 3 operands and certain flags **)
  749. PROCEDURE Emit3WithFlags(opCode: LONGINT; op1, op2, op3: Operand; flags: SET);
  750. VAR
  751. operands: ARRAY InstructionSet.MaxOperands OF Operand;
  752. BEGIN
  753. ASSERT(InstructionSet.MaxOperands = 6);
  754. operands[0] := op1;
  755. operands[1] := op2;
  756. operands[2] := op3;
  757. operands[3] := emptyOperand;
  758. operands[4] := emptyOperand;
  759. operands[5] := emptyOperand;
  760. Emit(opCode, InstructionSet.unconditional, flags, operands)
  761. END Emit3WithFlags;
  762. (** emit an ARM instruction with 1 operand and a condition **)
  763. PROCEDURE Emit1WithCondition(opCode: LONGINT; op1: Operand; condition: LONGINT);
  764. VAR
  765. operands: ARRAY InstructionSet.MaxOperands OF Operand;
  766. BEGIN
  767. ASSERT(InstructionSet.MaxOperands = 6);
  768. operands[0] := op1;
  769. operands[1] := emptyOperand;
  770. operands[2] := emptyOperand;
  771. operands[3] := emptyOperand;
  772. operands[4] := emptyOperand;
  773. operands[5] := emptyOperand;
  774. Emit(opCode, condition, {}, operands)
  775. END Emit1WithCondition;
  776. (** emit an ARM instruction with 2 operands and a condition **)
  777. PROCEDURE Emit2WithCondition(opCode: LONGINT; op1, op2: Operand; condition: LONGINT);
  778. VAR
  779. operands: ARRAY InstructionSet.MaxOperands OF Operand;
  780. BEGIN
  781. ASSERT(InstructionSet.MaxOperands = 6);
  782. operands[0] := op1;
  783. operands[1] := op2;
  784. operands[2] := emptyOperand;
  785. operands[3] := emptyOperand;
  786. operands[4] := emptyOperand;
  787. operands[5] := emptyOperand;
  788. Emit(opCode, condition, {}, operands)
  789. END Emit2WithCondition;
  790. (** emit an ARM instruction with 3 operands and a condition **)
  791. PROCEDURE Emit3WithCondition(opCode: LONGINT; op1, op2, op3: Operand; condition: LONGINT);
  792. VAR
  793. operands: ARRAY InstructionSet.MaxOperands OF Operand;
  794. BEGIN
  795. ASSERT(InstructionSet.MaxOperands = 6);
  796. operands[0] := op1;
  797. operands[1] := op2;
  798. operands[2] := op3;
  799. operands[3] := emptyOperand;
  800. operands[4] := emptyOperand;
  801. operands[5] := emptyOperand;
  802. Emit(opCode, condition, {}, operands)
  803. END Emit3WithCondition;
  804. (**
  805. - generate an arbitrary 32 bit value with as few as possible instructions and move the result into a specified target register
  806. - return the number of instructions required
  807. - if 'doEmit' is TRUE, emit the instructions
  808. **)
  809. PROCEDURE ValueComposition(value: LONGINT; doEmit: BOOLEAN; CONST targetRegister: Operand): LONGINT;
  810. VAR
  811. result: LONGINT;
  812. BEGIN
  813. IF doEmit THEN ASSERT(targetRegister.mode = InstructionSet.modeRegister) END;
  814. IF Trace & doEmit THEN D.Ln; D.String("original value: "); DBin(value, -32); D.String(" ("); D.Int(value, 0); D.String(") "); D.Ln; END;
  815. IF ValueComposition2(value, FALSE, emptyOperand) <= ValueComposition2(-value, FALSE, emptyOperand) + 1 THEN
  816. (* more efficient to calculate the value directly *)
  817. result := ValueComposition2(value, doEmit, targetRegister)
  818. ELSE
  819. (* more efficient to calculate the negation of the value and then negate it *)
  820. result := ValueComposition2(-value, doEmit, targetRegister) + 1;
  821. IF doEmit THEN
  822. Emit3(opRSB, targetRegister, targetRegister, InstructionSet.NewImmediate(0))
  823. END
  824. END;
  825. ASSERT((result >= 1) & (result <= 4));
  826. RETURN result
  827. END ValueComposition;
  828. (* note: used by 'ValueComposition'. do not call directly *)
  829. PROCEDURE ValueComposition2(value: LONGINT; doEmit: BOOLEAN; CONST targetRegister: Operand): LONGINT;
  830. VAR
  831. immediateOperand: Operand;
  832. result, position, partialValue, i: LONGINT;
  833. valueAsSet: SET;
  834. isFirst: BOOLEAN;
  835. BEGIN
  836. IF doEmit THEN ASSERT(targetRegister.mode = InstructionSet.modeRegister) END;
  837. IF Trace & doEmit THEN D.String("value to use: "); DBin(value, -32); D.String(" ("); D.Int(value, 0); D.String(") "); D.Ln; END;
  838. IF (value >= 0) & (value <= 255) THEN
  839. (* directly encodable as ARM immediate *)
  840. result := 1;
  841. IF doEmit THEN
  842. Emit2(opMOV, targetRegister, InstructionSet.NewImmediate(value))
  843. END
  844. ELSE
  845. valueAsSet := SYSTEM.VAL(SET, value);
  846. result := 0;
  847. position := 0;
  848. isFirst := TRUE;
  849. WHILE position < 32 DO
  850. IF (position IN valueAsSet) OR (position + 1 IN valueAsSet) THEN
  851. (* determine partial value for the 8 bit block *)
  852. partialValue := 0;
  853. FOR i := 7 TO 0 BY -1 DO
  854. partialValue := partialValue * 2;
  855. IF ((position + i) < 32) & ((position + i) IN valueAsSet) THEN INC(partialValue) END
  856. END;
  857. IF Trace & doEmit THEN
  858. D.String(" block found @ "); D.Int(position, 0); D.Ln;
  859. D.String(" unshifted partialValue: "); DBin(partialValue, -32); D.String(" ("); D.Int(partialValue, 0); D.String(") "); D.Ln;
  860. D.String(" shifted partialValue: "); DBin(ASH(partialValue, position), -32); D.String(" ("); D.Int(ASH(partialValue, position), 0); D.String(") "); D.Ln;
  861. END;
  862. ASSERT(~ODD(position));
  863. INC(result);
  864. IF doEmit THEN
  865. immediateOperand := InstructionSet.NewImmediate(ASH(partialValue, position)); (* TODO: check shift direction *)
  866. IF isFirst THEN
  867. Emit2(opMOV, targetRegister, immediateOperand);
  868. isFirst := FALSE
  869. ELSE
  870. Emit3(opADD, targetRegister, targetRegister, immediateOperand)
  871. END
  872. END;
  873. INC(position, 8)
  874. ELSE
  875. INC(position, 2)
  876. END
  877. END
  878. END;
  879. ASSERT((result >= 1) & (result <= 4));
  880. RETURN result
  881. END ValueComposition2;
  882. (** get the physical register number that corresponds to a virtual register number and part **)
  883. PROCEDURE PhysicalRegisterNumber(virtualRegisterNumber: LONGINT; part: LONGINT): LONGINT;
  884. VAR
  885. ticket: Ticket;
  886. result: LONGINT;
  887. BEGIN
  888. IF virtualRegisterNumber = IntermediateCode.FP THEN
  889. result := InstructionSet.FP
  890. ELSIF virtualRegisterNumber = IntermediateCode.SP THEN
  891. result := InstructionSet.SP
  892. ELSIF virtualRegisterNumber = IntermediateCode.LR THEN
  893. result := InstructionSet.LR
  894. ELSIF virtualRegisterNumber = IntermediateCode.AP THEN
  895. result := InstructionSet.R11
  896. ELSE
  897. ticket := virtualRegisters.Mapped(virtualRegisterNumber, part);
  898. IF ticket = NIL THEN
  899. result := None
  900. ELSE
  901. result := ticket.register
  902. END
  903. END;
  904. RETURN result
  905. END PhysicalRegisterNumber;
  906. (** get an ARM memory operand that represents a spill location (from a ticket) **)
  907. PROCEDURE GetSpillOperand(ticket: Ticket): Operand;
  908. VAR
  909. offset: LONGINT;
  910. result: Operand;
  911. BEGIN
  912. ASSERT(ticket.spilled);
  913. offset := spillStackStart + ticket.offset + 1; (* TODO: check this *)
  914. ASSERT((0 <= offset) & (offset < InstructionSet.Bits12));
  915. result := InstructionSet.NewImmediateOffsetMemory(PhysicalRegisterNumber(IntermediateCode.FP, Low), offset, {InstructionSet.Decrement});
  916. ASSERT(result.mode = InstructionSet.modeMemory);
  917. RETURN result
  918. END GetSpillOperand;
  919. (** get an ARM operand that represents a certain ticket (might be spilled or not) **)
  920. PROCEDURE OperandFromTicket(ticket: Ticket): Operand;
  921. VAR
  922. result: Operand;
  923. BEGIN
  924. ASSERT(ticket # NIL);
  925. IF ticket.spilled THEN
  926. (* the ticket is spilled *)
  927. result := GetSpillOperand(ticket)
  928. ELSE
  929. result := InstructionSet.NewRegister(ticket.register, None, None, 0)
  930. END;
  931. RETURN result
  932. END OperandFromTicket;
  933. (** get a free temporary register that holds data of a certain type **)
  934. PROCEDURE GetFreeRegister(CONST type: IntermediateCode.Type): Operand;
  935. VAR
  936. result: Operand;
  937. BEGIN
  938. result := OperandFromTicket(TemporaryTicket(IntermediateCode.GeneralPurposeRegister, type));
  939. ASSERT(result.mode = InstructionSet.modeRegister);
  940. RETURN result
  941. END GetFreeRegister;
  942. (** get a new free ARM register
  943. - if a register hint is provided that can hold data of the required type, it is returned instead
  944. **)
  945. PROCEDURE GetFreeRegisterOrHint(CONST type: IntermediateCode.Type; CONST registerHint: Operand): Operand;
  946. VAR
  947. result: Operand;
  948. BEGIN
  949. IF (registerHint.mode = InstructionSet.modeRegister) & IsRegisterForType(registerHint.register, type) THEN
  950. result := registerHint
  951. ELSE
  952. result := GetFreeRegister(type)
  953. END;
  954. ASSERT(result.mode = InstructionSet.modeRegister);
  955. RETURN result
  956. END GetFreeRegisterOrHint;
  957. (** whether a register can hold data of a certain IR type **)
  958. PROCEDURE IsRegisterForType(registerNumber: LONGINT; CONST type: IntermediateCode.Type): BOOLEAN;
  959. VAR
  960. result: BOOLEAN; form:LONGINT;
  961. BEGIN
  962. result := FALSE;
  963. form := type.form;
  964. IF type.form IN IntermediateCode.Integer THEN
  965. IF type.sizeInBits <= 32 THEN
  966. result := (registerNumber >= InstructionSet.R0) & (registerNumber <= InstructionSet.R15)
  967. END
  968. ELSIF type.form = IntermediateCode.Float THEN
  969. IF type.sizeInBits = 32 THEN
  970. result := (registerNumber >= InstructionSet.SR0) & (registerNumber <= InstructionSet.SR31)
  971. ELSE
  972. result := (registerNumber >= InstructionSet.DR0) & (registerNumber <= InstructionSet.DR31)
  973. END
  974. ELSE
  975. HALT(100)
  976. END;
  977. RETURN result
  978. END IsRegisterForType;
  979. (** get an ARM register that that is set off by a certain amount **)
  980. PROCEDURE RegisterAfterAppliedOffset(register: Operand; offset: LONGINT; registerHint: Operand): Operand;
  981. VAR
  982. result, offsetOperand: Operand;
  983. BEGIN
  984. IF offset = 0 THEN
  985. result := register
  986. ELSE
  987. result := GetFreeRegisterOrHint(IntermediateCode.UnsignedIntegerType(32), registerHint);
  988. offsetOperand := OperandFromValue(ABS(offset), result); (* might be immediate operand or register (tempRegister is given as a register hint) *)
  989. IF offset > 0 THEN
  990. Emit3(opADD, result, register, offsetOperand)
  991. ELSE
  992. Emit3(opSUB, result, register, offsetOperand)
  993. END
  994. END;
  995. RETURN result
  996. END RegisterAfterAppliedOffset;
  997. (** get an ARM register from an IR register
  998. - use register hint if provided
  999. **)
  1000. PROCEDURE RegisterFromIrRegister(CONST irRegisterOperand: IntermediateCode.Operand; part: LONGINT; registerHint: Operand): Operand;
  1001. VAR
  1002. result: Operand;
  1003. BEGIN
  1004. ASSERT(irRegisterOperand.mode = IntermediateCode.ModeRegister);
  1005. result := InstructionSet.NewRegister(PhysicalRegisterNumber(irRegisterOperand.register, part), None, None, 0);
  1006. result := RegisterAfterAppliedOffset(result, irRegisterOperand.offset, registerHint);
  1007. ASSERT(result.mode = InstructionSet.modeRegister);
  1008. RETURN result
  1009. END RegisterFromIrRegister;
  1010. PROCEDURE Load(targetRegister, memoryOperand: Operand; irType: IntermediateCode.Type);
  1011. BEGIN
  1012. IF (irType.form IN IntermediateCode.Integer) THEN
  1013. CASE irType.sizeInBits OF
  1014. | 8: Emit2WithFlags(opLDR, targetRegister, memoryOperand, {InstructionSet.flagB}) (* LDRB *)
  1015. | 16: Emit2WithFlags(opLDR, targetRegister, memoryOperand, {InstructionSet.flagH}) (* LDRH *)
  1016. | 32: (* TM*)
  1017. Emit2(opLDR, targetRegister, memoryOperand)
  1018. ELSE HALT(100)
  1019. END
  1020. ELSIF irType.form = IntermediateCode.Float THEN
  1021. IF irType.sizeInBits=32 THEN
  1022. IF backend.useFPU32 THEN
  1023. ASSERT(irType.sizeInBits = 32, 200);
  1024. Emit2(opFLDS, targetRegister, memoryOperand)
  1025. ELSE
  1026. Emit2(opLDR, targetRegister, memoryOperand)
  1027. END;
  1028. ELSE
  1029. IF backend.useFPU64 THEN
  1030. ASSERT(irType.sizeInBits = 64, 200);
  1031. Emit2(opFLDD, targetRegister, memoryOperand)
  1032. ELSE
  1033. Emit2(opLDR, targetRegister, memoryOperand)
  1034. END;
  1035. END;
  1036. ELSE
  1037. HALT(100)
  1038. END
  1039. END Load;
  1040. PROCEDURE Store(sourceRegister, memoryOperand: Operand; type: IntermediateCode.Type);
  1041. BEGIN
  1042. IF (type.form IN IntermediateCode.Integer) THEN
  1043. CASE type.sizeInBits OF
  1044. | 8: Emit2WithFlags(opSTR, sourceRegister, memoryOperand, {InstructionSet.flagB}) (* STRB *)
  1045. | 16: Emit2WithFlags(opSTR, sourceRegister, memoryOperand, {InstructionSet.flagH}) (* STRH *)
  1046. | 32: Emit2(opSTR, sourceRegister, memoryOperand)
  1047. ELSE HALT(100)
  1048. END
  1049. ELSIF type.form = IntermediateCode.Float THEN
  1050. IF (type.sizeInBits = 32) & backend.useFPU32 THEN
  1051. Emit2(opFSTS, sourceRegister, memoryOperand)
  1052. ELSIF (type.sizeInBits=64) & backend.useFPU64 THEN
  1053. Emit2(opFSTD, sourceRegister, memoryOperand)
  1054. ELSE
  1055. Emit2(opSTR, sourceRegister, memoryOperand)
  1056. END;
  1057. ELSE
  1058. HALT(100)
  1059. END
  1060. END Store;
  1061. (** get an ARM register that contains the address of a symbol/section
  1062. - use register hint if provided **)
  1063. PROCEDURE RegisterFromSymbol(symbol: Sections.SectionName; fingerprint: LONGINT; resolved: Sections.Section; symbolOffset: LONGINT; CONST registerHint: Operand): Operand;
  1064. VAR
  1065. address: LONGINT;
  1066. result: Operand;
  1067. irSection: IntermediateCode.Section;
  1068. BEGIN
  1069. IF resolved # NIL THEN
  1070. irSection := resolved(IntermediateCode.Section);
  1071. END;
  1072. IF (irSection # NIL) & (irSection.resolved # NIL) & (irSection.resolved.os.fixed) THEN
  1073. (* optimization: if the IR section is already resolved and positioned at a fixed location, no fixup is required *)
  1074. address := irSection.resolved.os.alignment + irSection.instructions[symbolOffset].pc;
  1075. result := RegisterFromValue(address, registerHint)
  1076. ELSE
  1077. result := GetFreeRegisterOrHint(IntermediateCode.UnsignedIntegerType(32), registerHint);
  1078. listOfReferences.AddSymbol(symbol, fingerprint, symbolOffset, out.pc, 12);
  1079. Emit2(opLDR, result, InstructionSet.NewImmediateOffsetMemory(opPC.register, 0, {InstructionSet.Increment})); (* LDR ..., [PC, #+???] *)
  1080. END;
  1081. ASSERT(result.mode = InstructionSet.modeRegister);
  1082. RETURN result
  1083. END RegisterFromSymbol;
  1084. (** get an ARM memory operand from an IR memory operand
  1085. - note that the constraints on memory operands depend on the type of data (e.g., the allowed offset range is more restricted for memory operands on floating point values)
  1086. **)
  1087. PROCEDURE MemoryOperandFromIrMemoryOperand(VAR irMemoryOperand: IntermediateCode.Operand; part: LONGINT; CONST registerHint: Operand): Operand;
  1088. VAR
  1089. baseAddressRegisterNumber, offset: LONGINT;
  1090. indexingMode: SET;
  1091. result, baseAddressRegister, offsetRegister, tempRegister: Operand;
  1092. BEGIN
  1093. ASSERT(irMemoryOperand.mode = IntermediateCode.ModeMemory);
  1094. (* determine base address register *)
  1095. IF irMemoryOperand.register # IntermediateCode.None THEN
  1096. (* case 1: [r1] or [r1 + 7] *)
  1097. ASSERT(irMemoryOperand.symbol.name = "");
  1098. baseAddressRegisterNumber := PhysicalRegisterNumber(irMemoryOperand.register, Low); (* addresses always are in the lower part *)
  1099. baseAddressRegister := InstructionSet.NewRegister(baseAddressRegisterNumber, InstructionSet.None, InstructionSet.None, InstructionSet.None);
  1100. ELSIF irMemoryOperand.symbol.name # "" THEN
  1101. (* case 2: [symbol], [symbol:3], [symbol + 7] or [symbol:3 + 7] *)
  1102. Resolve(irMemoryOperand);
  1103. baseAddressRegister := RegisterFromSymbol(irMemoryOperand.symbol.name, irMemoryOperand.symbol.fingerprint, irMemoryOperand.resolved, irMemoryOperand.symbolOffset, registerHint);
  1104. baseAddressRegisterNumber := baseAddressRegister.register
  1105. ELSE
  1106. (* case 3: [123456] *)
  1107. ASSERT(irMemoryOperand.offset = 0);
  1108. baseAddressRegister := RegisterFromValue(LONGINT(irMemoryOperand.intValue), registerHint);
  1109. baseAddressRegisterNumber := baseAddressRegister.register
  1110. END;
  1111. ASSERT(baseAddressRegisterNumber # None);
  1112. (* get offset of part in question *)
  1113. offset := irMemoryOperand.offset + part * 4;
  1114. (* determine indexing mode *)
  1115. IF offset >= 0 THEN indexingMode := {InstructionSet.Increment} ELSE indexingMode := {InstructionSet.Decrement} END;
  1116. IF irMemoryOperand.type.form IN IntermediateCode.Integer THEN
  1117. (* regular ARM memory operand *)
  1118. (*! LDRH supports only 8 bits immediates, while LDR and LDRB support 12 bits immediates *)
  1119. IF ((irMemoryOperand.type.sizeInBits = 16) & (ABS(offset) < 256)) OR ((irMemoryOperand.type.sizeInBits # 16) & (ABS(offset) < InstructionSet.Bits12)) THEN
  1120. (* offset can be encoded directly *)
  1121. result := InstructionSet.NewImmediateOffsetMemory(baseAddressRegisterNumber, ABS(offset), indexingMode)
  1122. ELSE
  1123. (* offset has to be provided in a register *)
  1124. offsetRegister := RegisterFromValue(ABS(offset), emptyOperand);
  1125. result := InstructionSet.NewRegisterOffsetMemory(baseAddressRegisterNumber, offsetRegister.register, None, 0, indexingMode)
  1126. END
  1127. ELSIF irMemoryOperand.type.form = IntermediateCode.Float THEN
  1128. (* VFP memory operand *)
  1129. ASSERT((ABS(offset) MOD 4) = 0);
  1130. IF ABS(offset) >= 1024 THEN
  1131. (* offset cannot be encoded directly _> it has to be provided by means of an adapted base register *)
  1132. tempRegister := RegisterFromValue(ABS(offset), emptyOperand);
  1133. IF offset < 0 THEN
  1134. Emit3(opSUB, tempRegister, tempRegister, baseAddressRegister)
  1135. ELSE
  1136. Emit3(opADD, tempRegister, tempRegister, baseAddressRegister)
  1137. END;
  1138. ReleaseHint(baseAddressRegister.register);
  1139. baseAddressRegister := tempRegister;
  1140. baseAddressRegisterNumber := baseAddressRegister.register;
  1141. offset := 0;
  1142. END;
  1143. result := InstructionSet.NewImmediateOffsetMemory(baseAddressRegisterNumber, ABS(offset), indexingMode)
  1144. ELSE
  1145. HALT(100)
  1146. END;
  1147. ASSERT(result.mode = InstructionSet.modeMemory);
  1148. RETURN result
  1149. END MemoryOperandFromIrMemoryOperand;
  1150. (** get an ARM immediate operand or register from any IR operand
  1151. - if possible, the an immediate is returned
  1152. - if needed, use register hint if provided
  1153. **)
  1154. PROCEDURE RegisterOrImmediateFromIrOperand(VAR irOperand: IntermediateCode.Operand; part: LONGINT; registerHint: Operand): Operand;
  1155. VAR
  1156. result: Operand;
  1157. BEGIN
  1158. IF IrOperandIsDirectlyEncodable(irOperand, part) THEN
  1159. result := InstructionSet.NewImmediate(ValueOfPart(irOperand.intValue, part))
  1160. ELSE
  1161. result := RegisterFromIrOperand(irOperand, part, registerHint)
  1162. END;
  1163. RETURN result
  1164. END RegisterOrImmediateFromIrOperand;
  1165. (** get an ARM register operand from any IR operand
  1166. - use register hint if provided
  1167. **)
  1168. PROCEDURE RegisterFromIrOperand(VAR irOperand: IntermediateCode.Operand; part: LONGINT; registerHint: Operand): Operand;
  1169. VAR
  1170. result: Operand;
  1171. BEGIN
  1172. CASE irOperand.mode OF
  1173. | IntermediateCode.ModeRegister:
  1174. ASSERT((irOperand.intValue = 0) & (irOperand.symbol.name = ""));
  1175. result := RegisterFromIrRegister(irOperand, part, registerHint)
  1176. | IntermediateCode.ModeMemory:
  1177. result := GetFreeRegisterOrHint(PartType(irOperand.type, part), registerHint);
  1178. Load(result, MemoryOperandFromIrMemoryOperand(irOperand, part, result), PartType(irOperand.type, part))
  1179. | IntermediateCode.ModeImmediate:
  1180. ASSERT(irOperand.register = IntermediateCode.None);
  1181. IF irOperand.symbol.name # "" THEN
  1182. Resolve(irOperand);
  1183. result := RegisterFromSymbol(irOperand.symbol.name, irOperand.symbol.fingerprint, irOperand.resolved, irOperand.symbolOffset, emptyOperand);
  1184. result := RegisterAfterAppliedOffset(result, irOperand.offset, registerHint);
  1185. ELSE
  1186. ASSERT(irOperand.offset = 0);
  1187. IF IsInteger(irOperand) THEN result := RegisterFromValue(ValueOfPart(irOperand.intValue, part), registerHint)
  1188. ELSIF IsSinglePrecisionFloat(irOperand) & backend.useFPU32 THEN result := SinglePrecisionFloatRegisterFromValue(REAL(irOperand.floatValue), registerHint)
  1189. ELSIF IsDoublePrecisionFloat(irOperand) & backend.useFPU64 THEN result := DoublePrecisionFloatRegisterFromValue(irOperand.floatValue, registerHint)
  1190. ELSE
  1191. IF IsSinglePrecisionFloat(irOperand) THEN
  1192. result := RegisterFromValue(BinaryCode.ConvertReal(SHORT(irOperand.floatValue)), registerHint)
  1193. ELSE
  1194. result := RegisterFromValue(ValueOfPart(BinaryCode.ConvertLongreal(irOperand.floatValue),part), registerHint);
  1195. END;
  1196. END
  1197. END
  1198. ELSE
  1199. HALT(100)
  1200. END;
  1201. ASSERT(result.mode = InstructionSet.modeRegister);
  1202. RETURN result
  1203. END RegisterFromIrOperand;
  1204. (** whether an IR operand is complex, i.e., requires more than one ARM operands to be represented **)
  1205. PROCEDURE IsComplex(CONST irOperand: IntermediateCode.Operand): BOOLEAN;
  1206. VAR
  1207. result: BOOLEAN;
  1208. BEGIN
  1209. IF (irOperand.type.form IN IntermediateCode.Integer) THEN
  1210. result := irOperand.type.sizeInBits > 32 (* integers above 32 bits have to be represented in multiple registers *)
  1211. ELSIF irOperand.type.form = IntermediateCode.Float THEN
  1212. result := (irOperand.type.sizeInBits > 32) & ~backend.useFPU64 (* integers above 32 bits have to be represented in multiple registers *)
  1213. ELSE
  1214. HALT(100)
  1215. END;
  1216. RETURN result
  1217. END IsComplex;
  1218. (** whether an IR operand hold a single precision floating point value **)
  1219. PROCEDURE IsSinglePrecisionFloat(CONST irOperand: IntermediateCode.Operand): BOOLEAN;
  1220. BEGIN RETURN (irOperand.type.sizeInBits = 32) & (irOperand.type.form = IntermediateCode.Float)
  1221. END IsSinglePrecisionFloat;
  1222. (** whether an IR operand hold a single precision floating point value **)
  1223. PROCEDURE IsDoublePrecisionFloat(CONST irOperand: IntermediateCode.Operand): BOOLEAN;
  1224. BEGIN RETURN (irOperand.type.sizeInBits = 64) & (irOperand.type.form = IntermediateCode.Float)
  1225. END IsDoublePrecisionFloat;
  1226. PROCEDURE IsFloat(CONST irOperand: IntermediateCode.Operand): BOOLEAN;
  1227. BEGIN
  1228. RETURN irOperand.type.form = IntermediateCode.Float
  1229. END IsFloat;
  1230. (** whether an IR operand hold am integer value **)
  1231. PROCEDURE IsInteger(CONST irOperand: IntermediateCode.Operand): BOOLEAN;
  1232. BEGIN RETURN irOperand.type.form IN IntermediateCode.Integer
  1233. END IsInteger;
  1234. (** whether an IR operand hold am integer value **)
  1235. PROCEDURE IsNonComplexInteger(CONST irOperand: IntermediateCode.Operand): BOOLEAN;
  1236. BEGIN RETURN (irOperand.type.form IN IntermediateCode.Integer) & (irOperand.type.sizeInBits <= 32)
  1237. END IsNonComplexInteger;
  1238. (** whether an IR operand hold am integer value **)
  1239. PROCEDURE IsInteger64(CONST irOperand: IntermediateCode.Operand): BOOLEAN;
  1240. BEGIN RETURN (irOperand.type.form IN IntermediateCode.Integer) & (irOperand.type.sizeInBits = 64)
  1241. END IsInteger64;
  1242. PROCEDURE PartType(CONST type: IntermediateCode.Type; part: LONGINT): IntermediateCode.Type;
  1243. VAR
  1244. result: IntermediateCode.Type;
  1245. BEGIN
  1246. GetPartType(type, part, result);
  1247. RETURN result
  1248. END PartType;
  1249. (* the intermediate code type of a part
  1250. - a part type is by definition directly representable in a register *)
  1251. PROCEDURE GetPartType(CONST type: IntermediateCode.Type; part: LONGINT; VAR partType: IntermediateCode.Type);
  1252. BEGIN
  1253. ASSERT((part = Low) OR (part = High));
  1254. IF (type.sizeInBits <= 32) OR (type.form = IntermediateCode.Float) & backend.useFPU64 THEN
  1255. IF part = Low THEN
  1256. partType := type
  1257. ELSE
  1258. partType := IntermediateCode.undef
  1259. END
  1260. ELSIF type.sizeInBits = 64 THEN
  1261. IF part = Low THEN
  1262. partType := IntermediateCode.NewType(IntermediateCode.UnsignedInteger, 32) (* conceptually the low part is always unsigned *)
  1263. ELSE
  1264. IF type.form = IntermediateCode.Float THEN
  1265. partType := IntermediateCode.NewType(IntermediateCode.SignedInteger, 32)
  1266. ELSE
  1267. partType := IntermediateCode.NewType(type.form, 32)
  1268. END;
  1269. END
  1270. ELSE
  1271. HALT(100)
  1272. END;
  1273. ASSERT(partType.form > IntermediateCode.Undefined);
  1274. END GetPartType;
  1275. (** the value of a 32 bit part **)
  1276. PROCEDURE ValueOfPart(value: HUGEINT; part: LONGINT): LONGINT;
  1277. VAR
  1278. result: LONGINT;
  1279. BEGIN
  1280. IF part = Low THEN
  1281. result := LONGINT(value) (* get the 32 least significant bits *)
  1282. ELSIF part = High THEN
  1283. result := LONGINT(ASH(value, -32)) (* get the 32 most significant bits *)
  1284. ELSE
  1285. HALT(100)
  1286. END;
  1287. RETURN result
  1288. END ValueOfPart;
  1289. (** whether a 32 bit value can be directly encoded as an ARM immediate (using a 8-bit base value and 4-bit half rotation) **)
  1290. PROCEDURE ValueIsDirectlyEncodable(value: LONGINT): BOOLEAN;
  1291. VAR
  1292. baseValue, halfRotation: LONGINT;
  1293. result: BOOLEAN;
  1294. BEGIN
  1295. result := InstructionSet.EncodeImmediate(value, baseValue, halfRotation);
  1296. RETURN result
  1297. END ValueIsDirectlyEncodable;
  1298. (* whether an IR operand (or part thereof) can be directly encoded as an ARM immediate *)
  1299. PROCEDURE IrOperandIsDirectlyEncodable(irOperand: IntermediateCode.Operand; part: LONGINT): BOOLEAN;
  1300. BEGIN RETURN
  1301. (irOperand.mode = IntermediateCode.ModeImmediate) &
  1302. (irOperand.symbol.name = "") &
  1303. (irOperand.type.form IN IntermediateCode.Integer) &
  1304. ValueIsDirectlyEncodable(ValueOfPart(irOperand.intValue, part))
  1305. END IrOperandIsDirectlyEncodable;
  1306. (* whether the negation of an IR operand (or part thereof) can be directly encoded as an ARM immediate *)
  1307. PROCEDURE NegatedIrOperandIsDirectlyEncodable(irOperand: IntermediateCode.Operand; part: LONGINT): BOOLEAN;
  1308. BEGIN RETURN
  1309. (irOperand.mode = IntermediateCode.ModeImmediate) &
  1310. (irOperand.symbol.name = "") &
  1311. (irOperand.type.form IN IntermediateCode.Integer) &
  1312. ValueIsDirectlyEncodable(ValueOfPart(-irOperand.intValue, part)) (* note the minus sign *)
  1313. END NegatedIrOperandIsDirectlyEncodable;
  1314. (** generate code for a certain IR instruction **)
  1315. PROCEDURE Generate(VAR irInstruction: IntermediateCode.Instruction);
  1316. BEGIN
  1317. (* CheckFixups; *)
  1318. EmitFixupBlockIfNeeded;
  1319. (*
  1320. IF ((irInstruction.opcode = IntermediateCode.mov) OR (irInstruction.opcode = IntermediateCode.pop)) & (instruction.op1.register <= IntermediateCode.ParameterRegister) THEN
  1321. hwreg := ParameterRegister(IntermediateCode.ParameterRegister-instruction.op1.register, instruction.op1.type);
  1322. Spill(physicalRegisters.Mapped(hwreg));
  1323. lastUse := inPC+1;
  1324. WHILE (lastUse < in.pc) &
  1325. ((in.instructions[lastUse].opcode # IntermediateCode.push) OR (in.instructions[lastUse].op1.register # instruction.op1.register)) & (in.instructions[lastUse].opcode # IntermediateCode.call) DO
  1326. INC(lastUse)
  1327. END;
  1328. ticket := ReservePhysicalRegister(instruction.op1.type,hwreg,lastUse);
  1329. END;
  1330. *)
  1331. ReserveOperandRegisters(irInstruction.op1, TRUE);
  1332. ReserveOperandRegisters(irInstruction.op2, TRUE);
  1333. ReserveOperandRegisters(irInstruction.op3, TRUE);
  1334. CASE irInstruction.opcode OF
  1335. | IntermediateCode.nop: (* do nothing *)
  1336. | IntermediateCode.mov: EmitMov(irInstruction, Low); IF IsComplex(irInstruction.op1) THEN EmitMov(irInstruction, High) END
  1337. | IntermediateCode.conv: EmitConv(irInstruction)
  1338. | IntermediateCode.call: EmitCall(irInstruction)
  1339. | IntermediateCode.enter: EmitEnter(irInstruction)
  1340. | IntermediateCode.leave: EmitLeave(irInstruction)
  1341. | IntermediateCode.exit: EmitExit(irInstruction)
  1342. | IntermediateCode.return: EmitReturn(irInstruction, Low); IF IsComplex(irInstruction.op1) THEN EmitReturn(irInstruction, High) END;
  1343. | IntermediateCode.result: EmitResult(irInstruction, Low); IF IsComplex(irInstruction.op1) THEN EmitResult(irInstruction, High) END;
  1344. | IntermediateCode.trap: EmitTrap(irInstruction);
  1345. | IntermediateCode.br .. IntermediateCode.brlt: EmitBr(irInstruction)
  1346. | IntermediateCode.pop: EmitPop(irInstruction.op1, Low); IF IsComplex(irInstruction.op1) THEN EmitPop(irInstruction.op1, High) END
  1347. | IntermediateCode.push: IF IsComplex(irInstruction.op1) THEN EmitPush(irInstruction.op1, High) END; EmitPush(irInstruction.op1, Low)
  1348. | IntermediateCode.neg: EmitNeg(irInstruction)
  1349. | IntermediateCode.not: EmitNot(irInstruction, Low); IF IsComplex(irInstruction.op1) THEN EmitNot(irInstruction, High) END
  1350. | IntermediateCode.abs: EmitAbs(irInstruction)
  1351. | IntermediateCode.mul: EmitMul(irInstruction)
  1352. | IntermediateCode.div: EmitDiv(irInstruction)
  1353. | IntermediateCode.mod: EmitMod(irInstruction)
  1354. | IntermediateCode.sub, IntermediateCode.add: EmitAddOrSub(irInstruction)
  1355. | IntermediateCode.and: EmitAnd(irInstruction);
  1356. | IntermediateCode.or: EmitOr(irInstruction, Low); IF IsComplex(irInstruction.op1) THEN EmitOr(irInstruction, High) END
  1357. | IntermediateCode.xor: EmitXor(irInstruction, Low); IF IsComplex(irInstruction.op1) THEN EmitXor(irInstruction, High) END
  1358. | IntermediateCode.shl: EmitShiftOrRotation(irInstruction)
  1359. | IntermediateCode.shr: EmitShiftOrRotation(irInstruction)
  1360. | IntermediateCode.rol: EmitShiftOrRotation(irInstruction)
  1361. | IntermediateCode.ror: EmitShiftOrRotation(irInstruction)
  1362. | IntermediateCode.cas: EmitCas(irInstruction);
  1363. | IntermediateCode.copy: EmitCopy(irInstruction)
  1364. | IntermediateCode.fill: EmitFill(irInstruction, FALSE)
  1365. | IntermediateCode.asm: EmitAsm(irInstruction)
  1366. | IntermediateCode.special: EmitSpecial(irInstruction)
  1367. END;
  1368. ReserveOperandRegisters(irInstruction.op3, FALSE);
  1369. ReserveOperandRegisters(irInstruction.op2 ,FALSE);
  1370. ReserveOperandRegisters(irInstruction.op1, FALSE);
  1371. END Generate;
  1372. PROCEDURE PostGenerate(CONST instruction: IntermediateCode.Instruction);
  1373. VAR ticket: Ticket;
  1374. BEGIN
  1375. TryUnmap(instruction.op3); TryUnmap(instruction.op2); TryUnmap(instruction.op1);
  1376. ticket := tickets.live;
  1377. WHILE (ticket # NIL) & (ticket.lastuse = inPC) DO
  1378. UnmapTicket(ticket);
  1379. ticket := tickets.live
  1380. END;
  1381. END PostGenerate;
  1382. PROCEDURE EmitFinalFixupBlock;
  1383. BEGIN
  1384. IF listOfReferences.size > 0 THEN
  1385. ASSERT(in.pc > 0);
  1386. IF in.instructions[in.pc - 1].opcode # IntermediateCode.exit THEN
  1387. (* there is no exit instruction at the end of the IR section -> emit a branch that skips the fixup block (in particular used by @BodyStub procedures)*)
  1388. Emit1(opB, InstructionSet.NewImmediate(4 + listOfReferences.size - 8))
  1389. END
  1390. END;
  1391. EmitFixupBlock; (* emit the fixup block *)
  1392. END EmitFinalFixupBlock;
  1393. (* if needed, emit fixup block for all used symbol references
  1394. - the fixup block is skipped by a branch instruction
  1395. - afterwards, the list of references is cleared
  1396. *)
  1397. PROCEDURE EmitFixupBlockIfNeeded;
  1398. BEGIN
  1399. IF out.pc >= listOfReferences.due THEN
  1400. listOfReferences.due := MAX(LONGINT);
  1401. Emit1(opB, InstructionSet.NewImmediate(4 + listOfReferences.size - 8 )); (* emit branch instruction that skips the fixup block *)
  1402. EmitFixupBlock; (* emit the fixup block *)
  1403. listOfReferences.Init (* clear the list *)
  1404. END
  1405. END EmitFixupBlockIfNeeded;
  1406. (* emit fixup block for all used symbol references, and clear the list *)
  1407. PROCEDURE EmitFixupBlock;
  1408. VAR
  1409. reference: Reference;
  1410. citation: Citation;
  1411. patchValue: LONGINT;
  1412. BEGIN
  1413. IF listOfReferences.size > 0 THEN
  1414. IF out.comments # NIL THEN
  1415. out.comments.String("REFERENCES BLOCK"); out.comments.String(" (");
  1416. out.comments.Int(listOfReferences.size, 0);
  1417. out.comments.String(" bytes):"); out.comments.Ln; out.comments.Update
  1418. END;
  1419. reference := listOfReferences.firstReference;
  1420. WHILE reference # NIL DO
  1421. (* 1. patch all of the citations, i.e., the LDR instructions that use the symbol reference *)
  1422. citation := reference.firstCitation;
  1423. WHILE citation # NIL DO
  1424. patchValue := out.pc - 8 - citation.pc;
  1425. patchValue := ASH(patchValue, -citation.shift); (* FLDS/VLDR reference counts number of words *)
  1426. ASSERT((0 <= patchValue) & (patchValue < ASH(1, citation.bits)));
  1427. out.PutBitsAt(citation.pc, patchValue, citation.bits);
  1428. citation := citation.next
  1429. END;
  1430. reference.Emit(out);
  1431. reference := reference.next
  1432. END
  1433. END
  1434. END EmitFixupBlock;
  1435. (** get an ARM operand that hold a certain value
  1436. - if possible the value is returned as an ARM immediate operand
  1437. - otherwise a register is returned instead (if a register hint is present, it is used) **)
  1438. PROCEDURE OperandFromValue(value: LONGINT; registerHint: Operand): Operand;
  1439. VAR
  1440. result: Operand;
  1441. BEGIN
  1442. IF ValueIsDirectlyEncodable(value) THEN
  1443. result := InstructionSet.NewImmediate(value)
  1444. ELSE
  1445. result := RegisterFromValue(value, registerHint)
  1446. END;
  1447. RETURN result
  1448. END OperandFromValue;
  1449. (** get a single precision VFP register that holds a certain floating point value **)
  1450. PROCEDURE SinglePrecisionFloatRegisterFromValue(value: REAL; registerHint: Operand): Operand;
  1451. VAR
  1452. intValue, dummy: LONGINT;
  1453. result, temp: Operand;
  1454. BEGIN
  1455. intValue := SYSTEM.VAL(LONGINT, value);
  1456. (* alternative: integerValue := BinaryCode.ConvertReal(value) *)
  1457. temp := RegisterFromValue(intValue, registerHint);
  1458. result := GetFreeRegisterOrHint(IntermediateCode.FloatType(32), registerHint);
  1459. Emit2(opFMSR, result, temp);
  1460. ASSERT(result.mode = InstructionSet.modeRegister);
  1461. ASSERT((result.register >= InstructionSet.SR0) & (result.register <= InstructionSet.SR31));
  1462. RETURN result;
  1463. END SinglePrecisionFloatRegisterFromValue;
  1464. (** get a single precision VFP register that holds a certain floating point value **)
  1465. PROCEDURE DoublePrecisionFloatRegisterFromValue(value: LONGREAL; registerHint: Operand): Operand;
  1466. VAR
  1467. intValue: HUGEINT; dummy: LONGINT;
  1468. result, temp: Operand;
  1469. BEGIN
  1470. intValue := SYSTEM.VAL(HUGEINT, value);
  1471. (* alternative: integerValue := BinaryCode.ConvertReal(value) *)
  1472. result := GetFreeRegisterOrHint(IntermediateCode.FloatType(64), registerHint);
  1473. listOfReferences.AddHImmediate(intValue, out.pc, 8);
  1474. Emit2(opFLDD, result, InstructionSet.NewImmediateOffsetMemory(opPC.register, 0, {InstructionSet.Increment})); (* LDR ..., [PC, #+???] *)
  1475. ASSERT(result.mode = InstructionSet.modeRegister);
  1476. ASSERT((result.register >= InstructionSet.DR0) & (result.register <= InstructionSet.DR31));
  1477. RETURN result;
  1478. END DoublePrecisionFloatRegisterFromValue;
  1479. (** get an ARM register that holds a certain integer value
  1480. - if a register hint is present, it is used **)
  1481. PROCEDURE RegisterFromValue(value: LONGINT; registerHint: Operand): Operand;
  1482. VAR
  1483. dummy: LONGINT;
  1484. result: Operand;
  1485. BEGIN
  1486. result := GetFreeRegisterOrHint(IntermediateCode.SignedIntegerType(32), registerHint);
  1487. IF ValueComposition(value, FALSE, result) < 3 THEN
  1488. dummy := ValueComposition(value, TRUE, result);
  1489. ELSE
  1490. result := GetFreeRegisterOrHint(IntermediateCode.UnsignedIntegerType(32), registerHint);
  1491. listOfReferences.AddImmediate(value, out.pc, 12);
  1492. Emit2(opLDR, result, InstructionSet.NewImmediateOffsetMemory(opPC.register, 0, {InstructionSet.Increment})); (* LDR ..., [PC, #+???] *)
  1493. END;
  1494. ASSERT(result.mode = InstructionSet.modeRegister);
  1495. ASSERT((result.register >= InstructionSet.R0) & (result.register <= InstructionSet.R15));
  1496. RETURN result
  1497. END RegisterFromValue;
  1498. (** allocate or deallocate on the stack
  1499. - note: updateStackSize is important as intermediate RETURNs should not change stack size
  1500. **)
  1501. PROCEDURE AllocateStack(allocationSize: LONGINT; doUpdateStackSize: BOOLEAN; clear: BOOLEAN);
  1502. VAR
  1503. operand, zero, count: InstructionSet.Operand; i: LONGINT;
  1504. BEGIN
  1505. inStackAllocation := TRUE;
  1506. operand := OperandFromValue(ABS(allocationSize), emptyOperand);
  1507. IF allocationSize > 0 THEN
  1508. IF clear THEN
  1509. zero := InstructionSet.NewRegister(0, None, None, 0);
  1510. Emit2(opMOV, zero , InstructionSet.NewImmediate(0));
  1511. IF allocationSize < 16 THEN
  1512. FOR i := 0 TO allocationSize-1 BY 4 DO
  1513. Emit2(opSTR, InstructionSet.NewRegister(0, None, None, 0), InstructionSet.NewImmediateOffsetMemory(InstructionSet.SP, 4, {InstructionSet.Decrement, InstructionSet.PreIndexed}));
  1514. END;
  1515. ELSE
  1516. count := InstructionSet.NewRegister(1, None, None, 0);
  1517. Emit1(opB, InstructionSet.NewImmediate(0)); (* PC offset = 8 ! Jump over immediate *)
  1518. out.PutBits(allocationSize DIV 4, 32);
  1519. Emit2(opLDR, count, InstructionSet.NewImmediateOffsetMemory(InstructionSet.PC, 8+4, {InstructionSet.Decrement}));
  1520. (* label *)
  1521. Emit2(opSTR, zero, InstructionSet.NewImmediateOffsetMemory(InstructionSet.SP, 4, {InstructionSet.Decrement, InstructionSet.PreIndexed}));
  1522. Emit3WithFlags(opSUB, count, count, InstructionSet.NewImmediate(1),{InstructionSet.flagS});
  1523. Emit1WithCondition(opB, InstructionSet.NewImmediate(-8 -8), InstructionSet.conditionGT); (* label *)
  1524. END;
  1525. ELSE
  1526. Emit3(opSUB, opSP, opSP, operand) (* decreasing SP: allocation *)
  1527. END;
  1528. ELSIF allocationSize < 0 THEN
  1529. Emit3(opADD, opSP, opSP, operand) (* increasing SP: deallocation *)
  1530. END;
  1531. IF doUpdateStackSize THEN stackSize := stackSize + allocationSize END;
  1532. inStackAllocation := FALSE
  1533. END AllocateStack;
  1534. (** whether two ARM operands represent the same physical register **)
  1535. PROCEDURE IsSameRegister(CONST a, b: Operand): BOOLEAN;
  1536. BEGIN RETURN (a.mode = InstructionSet.modeRegister) & (b.mode = InstructionSet.modeRegister) & (a.register = b.register)
  1537. END IsSameRegister;
  1538. (** emit a MOV instruction if the two operands do not represent the same register
  1539. - for moves involving floating point registers special VFP instructions opFCPYS, opFMSR and opFMRS are used
  1540. **)
  1541. PROCEDURE MovIfDifferent(CONST a, b: Operand);
  1542. BEGIN
  1543. IF ~IsSameRegister(a, b) THEN
  1544. ASSERT(a.mode = InstructionSet.modeRegister);
  1545. IF IsRegisterForType(a.register, IntermediateCode.FloatType(64)) THEN
  1546. IF IsRegisterForType(b.register, IntermediateCode.FloatType(64)) THEN
  1547. (* mov float, double: *)
  1548. Emit2(opFCPYD, a, b)
  1549. ELSIF IsRegisterForType(b.register, IntermediateCode.FloatType(32)) THEN
  1550. (* mov float, float: *)
  1551. Emit2(opFCVTSD, a, b)
  1552. ELSE
  1553. HALT(200);
  1554. END
  1555. ELSIF IsRegisterForType(a.register, IntermediateCode.FloatType(32)) THEN
  1556. IF IsRegisterForType(b.register, IntermediateCode.FloatType(64)) THEN
  1557. (* mov float, double: *)
  1558. Emit2(opFCVTSD, a, b)
  1559. ELSIF IsRegisterForType(b.register, IntermediateCode.FloatType(32)) THEN
  1560. (* mov float, float: *)
  1561. Emit2(opFCPYS, a, b)
  1562. ELSE
  1563. (* mov float, int: *)
  1564. Emit2(opFMSR, a, b)
  1565. END
  1566. ELSE
  1567. IF IsRegisterForType(b.register, IntermediateCode.FloatType(32)) THEN
  1568. (* mov int, float: *)
  1569. Emit2(opFMRS, a, b)
  1570. ELSIF IsRegisterForType(b.register, IntermediateCode.FloatType(64)) THEN
  1571. HALT(200)
  1572. ELSE
  1573. (* mov int, int: *)
  1574. Emit2(opMOV, a, b)
  1575. END
  1576. END
  1577. END
  1578. END MovIfDifferent;
  1579. (** acquire an ARM register fr oa IR destination operand part
  1580. - if IR operand is a memory location, get a temporary register (if provided the hinted register is used)
  1581. - if IR operand is an IR register, get the ARM register that is mapped to the corresponding part
  1582. **)
  1583. PROCEDURE AcquireDestinationRegister(CONST irDestinationOperand: IntermediateCode.Operand; part: LONGINT; registerHint: Operand): Operand;
  1584. VAR
  1585. result: Operand;
  1586. BEGIN
  1587. IF irDestinationOperand.mode = IntermediateCode.ModeMemory THEN
  1588. result := GetFreeRegisterOrHint(PartType(irDestinationOperand.type, part), registerHint)
  1589. ELSIF irDestinationOperand.mode = IntermediateCode.ModeRegister THEN
  1590. ASSERT(irDestinationOperand.offset = 0);
  1591. IF virtualRegisters.Mapped(irDestinationOperand.register, part) = NIL THEN TryAllocate(irDestinationOperand, part) END; (* create the mapping if not yet done *)
  1592. result := InstructionSet.NewRegister(PhysicalRegisterNumber(irDestinationOperand.register, part), None, None, 0)
  1593. ELSE
  1594. HALT(100)
  1595. END;
  1596. ASSERT(result.mode = InstructionSet.modeRegister);
  1597. RETURN result
  1598. END AcquireDestinationRegister;
  1599. (** write the content of an ARM register to an IR destination operand (memory location or IR register)
  1600. - afterwards, try to release the register
  1601. **)
  1602. PROCEDURE WriteBack(VAR irDestinationOperand: IntermediateCode.Operand; part: LONGINT; register: Operand);
  1603. VAR
  1604. mappedArmRegister: Operand;
  1605. BEGIN
  1606. ASSERT(register.mode = InstructionSet.modeRegister);
  1607. IF irDestinationOperand.mode = IntermediateCode.ModeMemory THEN
  1608. Store(register, MemoryOperandFromIrMemoryOperand(irDestinationOperand, part, emptyOperand), PartType(irDestinationOperand.type, part))
  1609. ELSIF irDestinationOperand.mode = IntermediateCode.ModeRegister THEN
  1610. ASSERT((virtualRegisters.Mapped(irDestinationOperand.register, part) # NIL)
  1611. OR (irDestinationOperand.register = IntermediateCode.SP)
  1612. OR (irDestinationOperand.register = IntermediateCode.FP)
  1613. OR (irDestinationOperand.register = IntermediateCode.LR)
  1614. OR (irDestinationOperand.register = IntermediateCode.AP));
  1615. mappedArmRegister := InstructionSet.NewRegister(PhysicalRegisterNumber(irDestinationOperand.register, part), None, None, 0);
  1616. MovIfDifferent(mappedArmRegister, register)
  1617. ELSE
  1618. HALT(100)
  1619. END;
  1620. ReleaseHint(register.register)
  1621. END WriteBack;
  1622. PROCEDURE ZeroExtendOperand(operand: Operand; sizeInBits: LONGINT);
  1623. BEGIN
  1624. ASSERT(sizeInBits <= 32);
  1625. IF operand.mode = InstructionSet.modeRegister THEN
  1626. IF sizeInBits = 8 THEN
  1627. Emit3(opAND, operand, operand, InstructionSet.NewImmediate(255)); (* AND reg, reg, 11111111b *)
  1628. ELSIF sizeInBits = 16 THEN
  1629. Emit2(opMOV, operand, InstructionSet.NewRegister(operand.register, InstructionSet.shiftLSL, None, 16));
  1630. Emit2(opMOV, operand, InstructionSet.NewRegister(operand.register, InstructionSet.shiftLSR, None, 16))
  1631. ELSIF sizeInBits = 32 THEN
  1632. (* nothing to do *)
  1633. ELSE
  1634. HALT(100)
  1635. END
  1636. ELSIF (sizeInBits < 32) THEN
  1637. ASSERT(operand.mode = InstructionSet.modeImmediate);
  1638. END
  1639. END ZeroExtendOperand;
  1640. PROCEDURE SignExtendOperand(operand: Operand; sizeInBits: LONGINT);
  1641. BEGIN
  1642. ASSERT(sizeInBits <= 32);
  1643. IF operand.mode = InstructionSet.modeRegister THEN
  1644. IF sizeInBits < 32 THEN
  1645. Emit2(opMOV, operand, InstructionSet.NewRegister(operand.register, InstructionSet.shiftLSL, None, 32 - sizeInBits));
  1646. Emit2(opMOV, operand, InstructionSet.NewRegister(operand.register, InstructionSet.shiftASR, None, 32 - sizeInBits))
  1647. END
  1648. ELSIF (sizeInBits < 32) THEN
  1649. ASSERT(operand.mode = InstructionSet.modeImmediate);
  1650. END
  1651. END SignExtendOperand;
  1652. (** sign or zero-extends the content of an operand to 32 bits, depending on the IR type **)
  1653. PROCEDURE SignOrZeroExtendOperand(operand: Operand; irType: IntermediateCode.Type);
  1654. BEGIN
  1655. ASSERT(irType.sizeInBits <= 32);
  1656. IF irType.form = IntermediateCode.UnsignedInteger THEN
  1657. ZeroExtendOperand(operand, irType.sizeInBits)
  1658. ELSE
  1659. SignExtendOperand(operand, irType.sizeInBits)
  1660. END
  1661. END SignOrZeroExtendOperand;
  1662. (* ACTUAL CODE GENERATION *)
  1663. PROCEDURE EmitPush(VAR irOperand: IntermediateCode.Operand; part: LONGINT);
  1664. VAR
  1665. register: Operand;
  1666. partType: IntermediateCode.Type;
  1667. (*pc: LONGINT;*)
  1668. BEGIN
  1669. register := RegisterFromIrOperand(irOperand, part, emptyOperand);
  1670. IF ~IsRegisterForType(register.register, IntermediateCode.FloatType(32)) & ~IsRegisterForType(register.register, IntermediateCode.FloatType(64)) THEN
  1671. Emit2(opSTR, register, InstructionSet.NewImmediateOffsetMemory(InstructionSet.SP, 4, {InstructionSet.Decrement, InstructionSet.PreIndexed}));
  1672. ELSE
  1673. partType := PartType(irOperand.type, part);
  1674. AllocateStack(MAX(4, partType.sizeInBits DIV 8), TRUE,FALSE);
  1675. Store(register, InstructionSet.NewImmediateOffsetMemory(InstructionSet.SP, 0, {InstructionSet.Increment}), PartType(irOperand.type, part));
  1676. END;
  1677. (*
  1678. (* optimization for push chains (THIS DOES NOT WORK IF inEmulation) *)
  1679. IF pushChainLength = 0 THEN
  1680. pc := inPC;
  1681. (* search for consecutive push instructions *)
  1682. WHILE (pc < in.pc) & (in.instructions[pc].opcode = IntermediateCode.push) DO
  1683. ASSERT(in.instructions[pc].op1.mode # IntermediateCode.Undefined);
  1684. INC(pushChainLength, MAX(4, in.instructions[pc].op1.type.sizeInBits DIV 8));
  1685. INC(pc)
  1686. END;
  1687. AllocateStack(pushChainLength, TRUE)
  1688. END;
  1689. DEC(pushChainLength, 4); (* for 64 bit operands, this procedure is executed twice -> the push chain will be decremented by 8 bytes *)
  1690. register := RegisterFromIrOperand(irOperand, part, emptyOperand);
  1691. ASSERT(pushChainLength < InstructionSet.Bits12, 100);
  1692. ASSERT((pushChainLength MOD 4) = 0);
  1693. Store(register, InstructionSet.NewImmediateOffsetMemory(InstructionSet.SP, pushChainLength, {InstructionSet.Increment}), PartType(irOperand.type, part))
  1694. *)
  1695. END EmitPush;
  1696. PROCEDURE EmitPop(VAR irOperand: IntermediateCode.Operand; part: LONGINT);
  1697. VAR
  1698. register: Operand; partType: IntermediateCode.Type;
  1699. BEGIN
  1700. register := AcquireDestinationRegister(irOperand, part, emptyOperand);
  1701. IF ~IsRegisterForType(register.register, IntermediateCode.FloatType(32)) & ~IsRegisterForType(register.register, IntermediateCode.FloatType(64)) THEN
  1702. (*Emit2(opLDR, register, InstructionSet.NewImmediateOffsetMemory(InstructionSet.SP, 4, {InstructionSet.Increment, InstructionSet.PostIndexed}));*)
  1703. Load(register, InstructionSet.NewImmediateOffsetMemory(InstructionSet.SP, 4, {InstructionSet.Increment, InstructionSet.PostIndexed}), PartType(irOperand.type, part));
  1704. ELSE
  1705. Load(register, InstructionSet.NewImmediateOffsetMemory(InstructionSet.SP, 0, {InstructionSet.Increment}), PartType(irOperand.type, part));
  1706. partType := PartType(irOperand.type, part);
  1707. AllocateStack(-MAX(4, partType.sizeInBits DIV 8), TRUE,FALSE);
  1708. END;
  1709. WriteBack(irOperand, part, register)
  1710. END EmitPop;
  1711. PROCEDURE Resolve(VAR op: IntermediateCode.Operand);
  1712. BEGIN
  1713. IF (op.symbol.name # "") & (op.resolved = NIL) THEN op.resolved := module.allSections.FindByName(op.symbol.name) END
  1714. END Resolve;
  1715. (* call <address>, <parSize> *)
  1716. PROCEDURE EmitCall(VAR irInstruction: IntermediateCode.Instruction);
  1717. VAR
  1718. code: BinaryCode.Section;
  1719. fixup, newFixup: BinaryCode.Fixup;
  1720. BEGIN
  1721. Resolve(irInstruction.op1);
  1722. IF (irInstruction.op1.resolved # NIL) & (irInstruction.op1.resolved.type = Sections.InlineCodeSection) THEN
  1723. (* call of an inline procedure: *)
  1724. code := irInstruction.op1.resolved(IntermediateCode.Section).resolved;
  1725. ASSERT(code # NIL); (* TODO: what if section is not yet resolved, i.e., code has not yet been generated? *)
  1726. IF (out.comments # NIL) THEN
  1727. out.comments.String("inlined code sequence:");
  1728. out.comments.Ln;
  1729. out.comments.Update;
  1730. END;
  1731. (* emit the generated code of the other section *)
  1732. out.CopyBits(code.os.bits, 0, code.os.bits.GetSize());
  1733. (* transfer the fixups *)
  1734. fixup := code.fixupList.firstFixup;
  1735. WHILE fixup # NIL DO
  1736. newFixup := BinaryCode.NewFixup(fixup.mode, fixup.offset + code.pc, fixup.symbol, fixup.symbolOffset, fixup.displacement, fixup.scale, fixup.pattern);
  1737. out.fixupList.AddFixup(newFixup);
  1738. fixup := fixup.nextFixup
  1739. END
  1740. ELSE
  1741. (* store the address of the procedure in a register and branch and link there *)
  1742. Emit1(opBLX, RegisterFromIrOperand(irInstruction.op1, Low, emptyOperand));
  1743. (* remove parameters on stack *)
  1744. AllocateStack(-LONGINT(irInstruction.op2.intValue), TRUE, FALSE)
  1745. END
  1746. END EmitCall;
  1747. (* enter <callingConvention>, <pafSize>, <numRegParams> *)
  1748. PROCEDURE EmitEnter(CONST irInstruction: IntermediateCode.Instruction);
  1749. VAR allocationSize: LONGINT;
  1750. BEGIN
  1751. (* store registers for interrupts, if required *)
  1752. IF (irInstruction.op1.intValue = SyntaxTree.InterruptCallingConvention) THEN (* TODO: needed? *)
  1753. (* push R0-R11, FP and LR *)
  1754. Emit2WithFlags(opSTM, opSP, InstructionSet.NewRegisterList(0, {InstructionSet.FP, InstructionSet.LR, 0..11}), {InstructionSet.flagDB, InstructionSet.flagBaseRegisterUpdate});
  1755. Emit2(opMOV, opFP, opSP);
  1756. END;
  1757. stackSize := 0;
  1758. (* allocate space on stack for local variables *)
  1759. allocationSize := LONGINT(irInstruction.op2.intValue);
  1760. Basic.Align(allocationSize, 4); (* 4 byte alignment *)
  1761. AllocateStack(allocationSize, TRUE, backend.initLocals);
  1762. (* allocate space on stack for register spills *)
  1763. spillStackStart := -stackSize;
  1764. IF spillStack.MaxSize() > 0 THEN AllocateStack(spillStack.MaxSize(), TRUE, FALSE) END
  1765. END EmitEnter;
  1766. (* leave <callingConvention> *)
  1767. PROCEDURE EmitLeave(CONST irInstruction: IntermediateCode.Instruction);
  1768. BEGIN
  1769. (* LDMFD (Full Descending) aka LDMIA (Increment After) *)
  1770. IF (irInstruction.op1.intValue = SyntaxTree.InterruptCallingConvention) THEN
  1771. (* pop R0-R11, FP and LR *)
  1772. Emit2(opMOV, opSP, opFP);
  1773. Emit2WithFlags(opLDM, opSP, InstructionSet.NewRegisterList(0, {InstructionSet.FP, InstructionSet.LR, 0..11}), {InstructionSet.flagIA, InstructionSet.flagBaseRegisterUpdate})
  1774. END
  1775. END EmitLeave;
  1776. (* exit <parSize>, <pcOffset> *)
  1777. PROCEDURE EmitExit(CONST irInstruction: IntermediateCode.Instruction);
  1778. BEGIN
  1779. Emit2(opLDR, opLR, InstructionSet.NewImmediateOffsetMemory(InstructionSet.SP, 4, {InstructionSet.Increment, InstructionSet.PostIndexed}));
  1780. IF (irInstruction.op1.intValue = 0) & (irInstruction.op2.intValue # SyntaxTree.InterruptCallingConvention) THEN
  1781. (* Emit2(opMOV, opPC, opLR) *)
  1782. Emit1(opBX, opLR) (* recommended for better interoperability between ARM and Thumb *)
  1783. ELSE
  1784. IF (irInstruction.op2.intValue = SyntaxTree.InterruptCallingConvention) THEN
  1785. Emit3WithFlags(opSUB, opPC, opLR, InstructionSet.NewImmediate(LONGINT(irInstruction.op1.intValue)),{InstructionSet.flagS})
  1786. ELSE
  1787. (* exit from an ARM interrupt procedure that has a PC offset *)
  1788. Emit3(opSUB, opPC, opLR, InstructionSet.NewImmediate(LONGINT(irInstruction.op1.intValue)))
  1789. END;
  1790. END
  1791. END EmitExit;
  1792. PROCEDURE EmitMov(VAR irInstruction: IntermediateCode.Instruction; part: LONGINT);
  1793. VAR
  1794. destinationRegister, sourceOperand: Operand;
  1795. BEGIN
  1796. IF irInstruction.op1.mode # IntermediateCode.ModeRegister THEN
  1797. (* optimization: mov [?], r? it is more optimal to determine the source operand first *)
  1798. sourceOperand := RegisterOrImmediateFromIrOperand(irInstruction.op2, part, emptyOperand);
  1799. destinationRegister := GetFreeRegisterOrHint(PartType(irInstruction.op2.type, part), sourceOperand) (* note that the source operand (possibly a register) is used as hint *)
  1800. ELSE
  1801. PrepareSingleSourceOpWithImmediate(irInstruction, part, destinationRegister, sourceOperand);
  1802. END;
  1803. MovIfDifferent(destinationRegister, sourceOperand);
  1804. WriteBack(irInstruction.op1, part, destinationRegister)
  1805. END EmitMov;
  1806. (* BITWISE LOGICAL OPERATIONS *)
  1807. PROCEDURE EmitNot(VAR irInstruction: IntermediateCode.Instruction; part: LONGINT);
  1808. VAR
  1809. destination, source: Operand;
  1810. BEGIN
  1811. PrepareSingleSourceOpWithImmediate(irInstruction, part, destination, source);
  1812. Emit2(opMVN, destination, source); (* invert bits *)
  1813. WriteBack(irInstruction.op1, part, destination)
  1814. END EmitNot;
  1815. PROCEDURE EmitAndP(VAR irInstruction: IntermediateCode.Instruction; part: LONGINT);
  1816. VAR
  1817. dummy: BOOLEAN;
  1818. destination, left, right: Operand;
  1819. BEGIN
  1820. PrepareDoubleSourceOpWithImmediate(irInstruction, part, destination, left, right, dummy);
  1821. Emit3(opAND, destination, left, right);
  1822. WriteBack(irInstruction.op1, part, destination)
  1823. END EmitAndP;
  1824. PROCEDURE EmitAnd(VAR irInstruction: IntermediateCode.Instruction);
  1825. BEGIN
  1826. EmitAndP(irInstruction, Low);
  1827. IF IsComplex(irInstruction.op1) THEN EmitAndP(irInstruction, High) END
  1828. END EmitAnd;
  1829. PROCEDURE EmitOr(VAR irInstruction: IntermediateCode.Instruction; part: LONGINT);
  1830. VAR
  1831. dummy: BOOLEAN;
  1832. destination, left, right: Operand;
  1833. BEGIN
  1834. PrepareDoubleSourceOpWithImmediate(irInstruction, part, destination, left, right, dummy);
  1835. Emit3(opORR, destination, left, right);
  1836. WriteBack(irInstruction.op1, part, destination)
  1837. END EmitOr;
  1838. PROCEDURE EmitXor(VAR irInstruction: IntermediateCode.Instruction; part: LONGINT);
  1839. VAR
  1840. dummy: BOOLEAN;
  1841. destination, left, right: Operand;
  1842. BEGIN
  1843. PrepareDoubleSourceOpWithImmediate(irInstruction, part, destination, left, right, dummy);
  1844. Emit3(opEOR, destination, left, right);
  1845. WriteBack(irInstruction.op1, part, destination)
  1846. END EmitXor;
  1847. (* ARITHMETIC OPERATIONS *)
  1848. (*
  1849. - TODO: double precision floats
  1850. - note that for operand sizes 8 and 16, the unused bits of the result might be in a unpredictable state (sign/zero-extension is not done on purpose)
  1851. *)
  1852. PROCEDURE EmitAddOrSub(VAR irInstruction: IntermediateCode.Instruction);
  1853. VAR
  1854. destination, left, right: Operand;
  1855. (* registerSR0, registerSR1, registerSR2: Operand; *)
  1856. BEGIN
  1857. IF IsSinglePrecisionFloat(irInstruction.op1) THEN
  1858. ASSERT(backend.useFPU32);
  1859. PrepareDoubleSourceOp(irInstruction, Low, destination, left, right);
  1860. IF irInstruction.opcode = IntermediateCode.add THEN
  1861. Emit3(opFADDS, destination, left, right)
  1862. ELSE
  1863. Emit3(opFSUBS, destination, left, right)
  1864. END;
  1865. WriteBack(irInstruction.op1, Low, destination)
  1866. ELSIF IsDoublePrecisionFloat(irInstruction.op1) THEN
  1867. ASSERT(backend.useFPU32);
  1868. PrepareDoubleSourceOp(irInstruction, Low, destination, left, right);
  1869. IF irInstruction.opcode = IntermediateCode.add THEN
  1870. Emit3(opFADDD, destination, left, right)
  1871. ELSE
  1872. Emit3(opFSUBD, destination, left, right)
  1873. END;
  1874. WriteBack(irInstruction.op1, Low, destination)
  1875. ELSIF IsInteger(irInstruction.op1) THEN
  1876. IF IsComplex(irInstruction.op1) THEN
  1877. EmitPartialAddOrSub(irInstruction, Low, TRUE);
  1878. EmitPartialAddOrSub(irInstruction, High, FALSE)
  1879. ELSE
  1880. EmitPartialAddOrSub(irInstruction, Low, FALSE)
  1881. END
  1882. ELSE
  1883. HALT(200)
  1884. END
  1885. END EmitAddOrSub;
  1886. PROCEDURE EmitPartialAddOrSub(CONST irInstruction: IntermediateCode.Instruction; part: LONGINT; doUpdateFlags: BOOLEAN);
  1887. VAR
  1888. destination, left, right, hint: Operand;
  1889. irDestination, irLeft, irRight: IntermediateCode.Operand;
  1890. operation: LONGINT;
  1891. doSwap, doNegateRight: BOOLEAN;
  1892. BEGIN
  1893. irDestination := irInstruction.op1; irLeft := irInstruction.op2; irRight := irInstruction.op3;
  1894. doSwap := FALSE; doNegateRight := FALSE; (* defaults *)
  1895. IF irInstruction.opcode = IntermediateCode.add THEN
  1896. IF IrOperandIsDirectlyEncodable(irRight, part) THEN
  1897. (* add r0, r1, 16 ~> ADD R0, R1, #16 *)
  1898. operation := opADD
  1899. ELSIF IrOperandIsDirectlyEncodable(irLeft, part) THEN
  1900. (* add r0, 16, r1 ~> ADD R0, R1, #16 *)
  1901. operation := opADD; doSwap := TRUE
  1902. ELSIF NegatedIrOperandIsDirectlyEncodable(irRight, part) THEN
  1903. (* add r0, r1, -16 ~> SUB R0, R1, #16 *)
  1904. operation := opSUB; doNegateRight := TRUE
  1905. ELSIF NegatedIrOperandIsDirectlyEncodable(irLeft, part) THEN
  1906. (* add r0, -16, r1 ~> SUB R0, R1, #16 *)
  1907. operation := opSUB; doSwap := TRUE; doNegateRight := TRUE
  1908. ELSE
  1909. operation := opADD
  1910. END
  1911. ELSIF irInstruction.opcode = IntermediateCode.sub THEN
  1912. IF IrOperandIsDirectlyEncodable(irRight, part) THEN
  1913. (* sub r0, r1, 16 ~> SUB R0, R1, #16 *)
  1914. operation := opSUB
  1915. ELSIF IrOperandIsDirectlyEncodable(irLeft, part) THEN
  1916. (* sub r0, 16, r1 ~> RSB R0, R1, #16 *)
  1917. operation := opRSB; doSwap := TRUE
  1918. ELSIF NegatedIrOperandIsDirectlyEncodable(irRight, part) THEN
  1919. (* sub r0, r1, -16 ~> ADD R0, R1, #16 *)
  1920. operation := opADD; doNegateRight := TRUE
  1921. ELSE
  1922. operation := opSUB
  1923. END
  1924. ELSE
  1925. HALT(100)
  1926. END;
  1927. (* get destination operand *)
  1928. destination := AcquireDestinationRegister(irDestination, part, emptyOperand);
  1929. (* get source operands *)
  1930. IF doSwap THEN SwapIrOperands(irLeft, irRight) END; (* if needed, swap operands *)
  1931. (* TODO: revise this! *)
  1932. IF IsSameRegister(right, destination) THEN hint := destination ELSE hint := emptyOperand END;
  1933. left := RegisterFromIrOperand(irLeft, part, hint);
  1934. IF doNegateRight THEN
  1935. ASSERT(NegatedIrOperandIsDirectlyEncodable(irRight, part));
  1936. right := InstructionSet.NewImmediate(-ValueOfPart(irRight.intValue, part))
  1937. ELSE
  1938. right := RegisterOrImmediateFromIrOperand(irRight, part, emptyOperand)
  1939. END;
  1940. (* if needed, use operation that incorporates carry *)
  1941. IF part # Low THEN
  1942. CASE operation OF
  1943. | opADD: operation := opADC
  1944. | opSUB: operation := opSBC
  1945. | opRSB: operation := opRSC
  1946. ELSE HALT(100)
  1947. END
  1948. END;
  1949. IF doUpdateFlags THEN
  1950. Emit3WithFlags(operation, destination, left, right, {InstructionSet.flagS})
  1951. ELSE
  1952. Emit3(operation, destination, left, right)
  1953. END;
  1954. WriteBack(irDestination, part, destination)
  1955. END EmitPartialAddOrSub;
  1956. PROCEDURE EmitMul(VAR irInstruction: IntermediateCode.Instruction);
  1957. VAR
  1958. destination, left, right: ARRAY 2 OF Operand; inst: IntermediateCode.Instruction;
  1959. value: HUGEINT;exp: LONGINT; op3:IntermediateCode.Operand;
  1960. BEGIN
  1961. IF IntermediateCode.IsConstantInteger(irInstruction.op3,value) & IntermediateBackend.PowerOf2(value,exp) THEN
  1962. IntermediateCode.InitImmediate(op3, IntermediateCode.uint32, exp);
  1963. IntermediateCode.InitInstruction(inst, -1, IntermediateCode.shl, irInstruction.op1, irInstruction.op2, op3);
  1964. EmitShiftOrRotation(inst);
  1965. RETURN;
  1966. END;
  1967. IF IsSinglePrecisionFloat(irInstruction.op1) THEN
  1968. ASSERT(backend.useFPU32);
  1969. PrepareDoubleSourceOp(irInstruction, Low, destination[Low], left[Low], right[Low]);
  1970. Emit3(opFMULS, destination[Low], left[Low], right[Low]);
  1971. WriteBack(irInstruction.op1, Low, destination[Low])
  1972. ELSIF IsDoublePrecisionFloat(irInstruction.op1) THEN
  1973. ASSERT(backend.useFPU64);
  1974. PrepareDoubleSourceOp(irInstruction, Low, destination[Low], left[Low], right[Low]);
  1975. Emit3(opFMULD, destination[Low], left[Low], right[Low]);
  1976. WriteBack(irInstruction.op1, Low, destination[Low])
  1977. ELSIF IsInteger(irInstruction.op1) THEN
  1978. IF IsComplex(irInstruction.op1) THEN
  1979. ASSERT(irInstruction.op1.type.form = IntermediateCode.SignedInteger);
  1980. HALT(200);
  1981. (* TODO: fix signed 64 bit integer multiplication:
  1982. PrepareDoubleSourceOp(irInstruction, Low, destination[Low], left[Low], right[Low]);
  1983. PrepareDoubleSourceOp(irInstruction, High, destination[High], left[High], right[High]);
  1984. Emit4(opSMULL, destination[Low], destination[High], left[Low], right[Low]); (* signed long multiplication *)
  1985. Emit3(opMLA, destination[High], left[Low], right[High]); (* multiply and accumulate *)
  1986. Emit3(opMLA, destination[High], left[High], right[Low]);
  1987. WriteBack(irInstruction.op1, Low, destination[Low]);
  1988. WriteBack(irInstruction.op1, High, destination[High]);
  1989. *)
  1990. ELSE
  1991. (* signed or unsigned integer multiplication: *)
  1992. PrepareDoubleSourceOp(irInstruction, Low, destination[Low], left[Low], right[Low]);
  1993. SignOrZeroExtendOperand(left[Low], irInstruction.op2.type);
  1994. SignOrZeroExtendOperand(right[Low], irInstruction.op3.type);
  1995. Emit3(opMUL, destination[Low], left[Low], right[Low]); (* note that the sign does not matter for the least 32 significant bits *)
  1996. WriteBack(irInstruction.op1, Low, destination[Low])
  1997. END
  1998. ELSE
  1999. HALT(200)
  2000. END
  2001. END EmitMul;
  2002. PROCEDURE EmitDiv(VAR irInstruction: IntermediateCode.Instruction);
  2003. VAR
  2004. destination, left, right, float, leftd, rightd, fpstatus: Operand;
  2005. value: HUGEINT; exp: LONGINT; op3: IntermediateCode.Operand;
  2006. inst: IntermediateCode.Instruction;
  2007. BEGIN
  2008. IF IntermediateCode.IsConstantInteger(irInstruction.op3,value) & IntermediateBackend.PowerOf2(value,exp) THEN
  2009. IntermediateCode.InitImmediate(op3, IntermediateCode.uint32, exp);
  2010. IntermediateCode.InitInstruction(inst, -1, IntermediateCode.shr, irInstruction.op1, irInstruction.op2, op3);
  2011. EmitShiftOrRotation(inst);
  2012. RETURN;
  2013. END;
  2014. IF IsSinglePrecisionFloat(irInstruction.op1) THEN
  2015. ASSERT(backend.useFPU32);
  2016. PrepareDoubleSourceOp(irInstruction, Low, destination, left, right);
  2017. Emit3(opFDIVS, destination, left, right);
  2018. WriteBack(irInstruction.op1, Low, destination)
  2019. ELSIF IsDoublePrecisionFloat(irInstruction.op1) THEN
  2020. ASSERT(backend.useFPU64);
  2021. PrepareDoubleSourceOp(irInstruction, Low, destination, left, right);
  2022. Emit3(opFDIVD, destination, left, right);
  2023. WriteBack(irInstruction.op1, Low, destination)
  2024. ELSIF IsNonComplexInteger(irInstruction.op1) THEN
  2025. ASSERT(backend.useFPU64);
  2026. PrepareDoubleSourceOp(irInstruction, Low, destination, left, right);
  2027. (* left and right operands to double *)
  2028. float := GetFreeRegister(IntermediateCode.FloatType(32));
  2029. Emit2(opFMSR, float, left);
  2030. leftd := GetFreeRegister(IntermediateCode.FloatType(64));
  2031. IF irInstruction.op1.type.form = IntermediateCode.UnsignedInteger THEN
  2032. Emit2(opFUITOD, leftd, float)
  2033. ELSE
  2034. Emit2(opFSITOD,leftd, float)
  2035. END;
  2036. Emit2(opFMSR, float,right);
  2037. rightd := GetFreeRegister(IntermediateCode.FloatType(64));
  2038. IF irInstruction.op1.type.form = IntermediateCode.UnsignedInteger THEN
  2039. Emit2(opFUITOD, rightd, float)
  2040. ELSE
  2041. Emit2(opFSITOD,rightd, float)
  2042. END;
  2043. (* div *)
  2044. Emit3(opFDIVD, leftd, leftd, rightd);
  2045. (* result to destination *)
  2046. RoundDown(fpstatus);
  2047. IF irInstruction.op1.type.form = IntermediateCode.UnsignedInteger THEN
  2048. Emit2(opFTOUID, float, leftd)
  2049. ELSE
  2050. Emit2(opFTOSID, float, leftd)
  2051. END;
  2052. ResetRounding(fpstatus);
  2053. Emit2(opFMRS, destination, float);
  2054. WriteBack(irInstruction.op1, Low, destination)
  2055. ELSE
  2056. HALT(200)
  2057. END
  2058. END EmitDiv;
  2059. PROCEDURE EmitMod(CONST irInstruction: IntermediateCode.Instruction);
  2060. VAR
  2061. value: HUGEINT;exp: LONGINT; op3:IntermediateCode.Operand; inst: IntermediateCode.Instruction;
  2062. BEGIN
  2063. IF IntermediateCode.IsConstantInteger(irInstruction.op3,value) & IntermediateBackend.PowerOf2(value,exp) THEN
  2064. IntermediateCode.InitImmediate(op3, irInstruction.op3.type, value-1);
  2065. IntermediateCode.InitInstruction(inst, -1, IntermediateCode.and, irInstruction.op1, irInstruction.op2, op3);
  2066. EmitAnd(inst);
  2067. RETURN;
  2068. END;
  2069. HALT(100) (* handled by a runtime call *)
  2070. END EmitMod;
  2071. PROCEDURE EmitAbs(VAR irInstruction: IntermediateCode.Instruction);
  2072. VAR
  2073. destination, source: ARRAY 2 OF Operand;
  2074. zero: Operand;
  2075. BEGIN
  2076. IF IsInteger(irInstruction.op1) THEN
  2077. zero := InstructionSet.NewImmediate(0);
  2078. IF IsComplex(irInstruction.op1) THEN
  2079. PrepareSingleSourceOpWithImmediate(irInstruction, Low, destination[Low], source[Low]);
  2080. PrepareSingleSourceOpWithImmediate(irInstruction, High, destination[High], source[High]);
  2081. MovIfDifferent(destination[Low], source[Low]);
  2082. MovIfDifferent(destination[High], source[High]);
  2083. (* negate the value if it is negative *)
  2084. IF irInstruction.op2.type.form = IntermediateCode.SignedInteger THEN
  2085. Emit2(opCMP, destination[High], zero); (* note that only the high part has to be looked at to determine the sign *)
  2086. Emit1WithCondition(opB, InstructionSet.NewImmediate(4), InstructionSet.conditionGE); (* BGE #4 = skip the following two instructions if greater or equal *)
  2087. Emit3WithFlags(opRSB, destination[Low], destination[Low], zero, {InstructionSet.flagS}); (* RSBS *)
  2088. Emit3(opRSC, destination[High], destination[High], zero); (* RSC - reverse subtraction with carry *)
  2089. END;
  2090. WriteBack(irInstruction.op1, Low, destination[Low]);
  2091. WriteBack(irInstruction.op1, High, destination[High])
  2092. ELSE
  2093. PrepareSingleSourceOpWithImmediate(irInstruction, Low, destination[Low], source[Low]);
  2094. SignOrZeroExtendOperand(source[Low], irInstruction.op2.type);
  2095. MovIfDifferent(destination[Low], source[Low]);
  2096. (* negate the value if it is negative *)
  2097. IF irInstruction.op2.type.form = IntermediateCode.SignedInteger THEN
  2098. SignExtendOperand(destination[Low], irInstruction.op2.type.sizeInBits);
  2099. Emit2(opCMP, destination[Low], zero);
  2100. Emit3WithCondition(opRSB, destination[Low], destination[Low], zero, InstructionSet.conditionLT)
  2101. END;
  2102. WriteBack(irInstruction.op1, Low, destination[Low])
  2103. END
  2104. ELSIF IsSinglePrecisionFloat(irInstruction.op1) THEN
  2105. ASSERT(backend.useFPU32);
  2106. PrepareSingleSourceOp(irInstruction, Low, destination[Low], source[Low]);
  2107. Emit2(opFABSS, destination[Low], source[Low]);
  2108. WriteBack(irInstruction.op1, Low, destination[Low])
  2109. ELSIF IsDoublePrecisionFloat(irInstruction.op1) THEN
  2110. ASSERT(backend.useFPU64);
  2111. PrepareSingleSourceOp(irInstruction, Low, destination[Low], source[Low]);
  2112. Emit2(opFABSD, destination[Low], source[Low]);
  2113. WriteBack(irInstruction.op1, Low, destination[Low])
  2114. ELSE
  2115. HALT(200)
  2116. END
  2117. END EmitAbs;
  2118. (* TODO: floats *)
  2119. PROCEDURE EmitNeg(VAR irInstruction: IntermediateCode.Instruction);
  2120. VAR
  2121. destination, source: ARRAY 2 OF Operand;
  2122. zero: Operand;
  2123. BEGIN
  2124. IF IsInteger(irInstruction.op1) THEN
  2125. zero := InstructionSet.NewImmediate(0);
  2126. IF IsComplex(irInstruction.op1) THEN
  2127. PrepareSingleSourceOpWithImmediate(irInstruction, Low, destination[Low], source[Low]);
  2128. PrepareSingleSourceOpWithImmediate(irInstruction, High, destination[High], source[High]);
  2129. Emit3WithFlags(opRSB, destination[Low], source[Low], zero, {InstructionSet.flagS}); (* RSBS *)
  2130. Emit3(opRSC, destination[High], source[High], zero); (* RSC - reverse subtraction with carry *)
  2131. WriteBack(irInstruction.op1, Low, destination[Low]);
  2132. WriteBack(irInstruction.op1, High, destination[High])
  2133. ELSE
  2134. PrepareSingleSourceOpWithImmediate(irInstruction, Low, destination[Low], source[Low]);
  2135. SignOrZeroExtendOperand(source[Low], irInstruction.op2.type);
  2136. Emit3(opRSB, destination[Low], source[Low], zero); (* reverse subtraction with zero *)
  2137. WriteBack(irInstruction.op1, Low, destination[Low])
  2138. END
  2139. ELSIF IsSinglePrecisionFloat(irInstruction.op1) THEN
  2140. ASSERT(backend.useFPU32);
  2141. PrepareSingleSourceOp(irInstruction, Low, destination[Low], source[Low]);
  2142. Emit2(opFNEGS, destination[Low], source[Low]);
  2143. WriteBack(irInstruction.op1, Low, destination[Low])
  2144. ELSIF IsDoublePrecisionFloat(irInstruction.op1) THEN
  2145. ASSERT(backend.useFPU64);
  2146. PrepareSingleSourceOp(irInstruction, Low, destination[Low], source[Low]);
  2147. Emit2(opFNEGD, destination[Low], source[Low]);
  2148. WriteBack(irInstruction.op1, Low, destination[Low])
  2149. ELSE
  2150. HALT(200)
  2151. END
  2152. END EmitNeg;
  2153. (*
  2154. - note that the ARM instructions ASR, LSL, LSR, ROR, etc. are actually aliases for a MOV with a shifted register operand
  2155. - note that ARM does not support LSL by 32 bits
  2156. - note that for operand sizes 8 and 16, the unused bits of the result might be in a unpredictable state (sign/zero-extension is not done on purpose)
  2157. *)
  2158. PROCEDURE EmitShiftOrRotation(VAR irInstruction: IntermediateCode.Instruction);
  2159. VAR
  2160. shiftAmountImmediate, shiftMode: LONGINT;
  2161. destination, source: ARRAY 2 OF Operand;
  2162. irShiftOperand: IntermediateCode.Operand;
  2163. temp, shiftAmountRegister: Operand;
  2164. BEGIN
  2165. ASSERT(IsInteger(irInstruction.op1), 100); (* shifts are only allowed on integers *)
  2166. destination[Low] := AcquireDestinationRegister(irInstruction.op1, Low, emptyOperand);
  2167. source[Low] := RegisterFromIrOperand(irInstruction.op2, Low, emptyOperand); (* note that the destination register cannot be used as hint for the source *)
  2168. IF IsComplex(irInstruction.op1) THEN
  2169. destination[High] := AcquireDestinationRegister(irInstruction.op1, High, emptyOperand);
  2170. source[High] := RegisterFromIrOperand(irInstruction.op2, High, emptyOperand); (* note that the destination register cannot be used as hint for the source *)
  2171. END;
  2172. irShiftOperand := irInstruction.op3;
  2173. ASSERT((irShiftOperand.type.form = IntermediateCode.UnsignedInteger) & ~IsComplex(irShiftOperand)); (* the shift operand is assumed to be a single part unsigned integer *)
  2174. (* use ARM register or shift immediate to represent IR shift operand *)
  2175. IF (irShiftOperand.mode = IntermediateCode.ModeImmediate) & (irShiftOperand.symbol.name = "") THEN
  2176. shiftAmountImmediate := LONGINT(irShiftOperand.intValue); (* note that at this point the shift amount could also be >= 32 *)
  2177. shiftAmountRegister := emptyOperand;
  2178. ASSERT(shiftAmountImmediate >= 0);
  2179. ELSE
  2180. shiftAmountImmediate := 0;
  2181. shiftAmountRegister := RegisterFromIrOperand(irShiftOperand, Low, emptyOperand);
  2182. ZeroExtendOperand(shiftAmountRegister, irShiftOperand.type.sizeInBits)
  2183. END;
  2184. CASE irInstruction.opcode OF
  2185. | IntermediateCode.ror, IntermediateCode.rol:
  2186. (* rotation: *)
  2187. IF IsComplex(irInstruction.op1) THEN HALT(100) END; (* complex rotations are handled as runtime calls *)
  2188. IF irInstruction.opcode = IntermediateCode.rol THEN
  2189. (* simple left rotation: rotate right with complementary rotation amount, since ARM does not support left rotations *)
  2190. IF shiftAmountRegister.register = None THEN
  2191. shiftAmountImmediate := 32 - shiftAmountImmediate
  2192. ELSE
  2193. IF IsSameRegister(destination[Low], source[Low]) THEN temp := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32)) ELSE temp := destination[Low] END;
  2194. Emit3(opRSB, temp, shiftAmountRegister, InstructionSet.NewImmediate(32));
  2195. shiftAmountRegister := temp
  2196. END
  2197. END;
  2198. shiftAmountImmediate := shiftAmountImmediate MOD 32; (* make sure rotation amount is in range 0..31 *)
  2199. IF (shiftAmountRegister.register = None) & (shiftAmountImmediate = 0) THEN
  2200. (* simple rotation by 0: *)
  2201. Emit2(opMOV, destination[Low], source[Low])
  2202. ELSE
  2203. IF irInstruction.op1.type.sizeInBits = 8 THEN
  2204. (* simple 8 bit rotation: *)
  2205. ZeroExtendOperand(source[Low], 8);
  2206. IF IsSameRegister(destination[Low], source[Low]) THEN temp := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32)) ELSE temp := destination[Low] END;
  2207. Emit2(opMOV, temp, InstructionSet.NewRegister(source[Low].register, InstructionSet.shiftROR, shiftAmountRegister.register, shiftAmountImmediate));
  2208. Emit3(opORR, temp, temp, InstructionSet.NewRegister(temp.register, InstructionSet.shiftLSR, None, 8));
  2209. Emit3(opORR, temp, temp, InstructionSet.NewRegister(temp.register, InstructionSet.shiftLSR, None, 16));
  2210. Emit3(opORR, destination[Low], temp, InstructionSet.NewRegister(temp.register, InstructionSet.shiftLSR, None, 24))
  2211. ELSIF irInstruction.op1.type.sizeInBits = 16 THEN
  2212. (* simple 16 bit rotation: *)
  2213. ZeroExtendOperand(source[Low], 16);
  2214. IF IsSameRegister(destination[Low], source[Low]) THEN temp := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32)) ELSE temp := destination[Low] END;
  2215. Emit2(opMOV, temp, InstructionSet.NewRegister(source[Low].register, InstructionSet.shiftROR, shiftAmountRegister.register, shiftAmountImmediate));
  2216. Emit3(opORR, destination[Low], temp, InstructionSet.NewRegister(temp.register, InstructionSet.shiftLSR, None, 16))
  2217. ELSIF irInstruction.op1.type.sizeInBits = 32 THEN
  2218. (* simple 32 bit rotation: *)
  2219. Emit2(opMOV, destination[Low], InstructionSet.NewRegister(source[Low].register, InstructionSet.shiftROR, shiftAmountRegister.register, shiftAmountImmediate))
  2220. ELSE
  2221. HALT(100)
  2222. END
  2223. END
  2224. | IntermediateCode.shl:
  2225. (* left shift: *)
  2226. IF IsComplex(irInstruction.op1) THEN
  2227. (* complex left shift: *)
  2228. IF shiftAmountRegister.register = None THEN
  2229. (* complex left immediate shift: *)
  2230. IF shiftAmountImmediate = 0 THEN
  2231. Emit2(opMOV, destination[High], source[High]);
  2232. Emit2(opMOV, destination[Low], source[Low])
  2233. ELSIF (shiftAmountImmediate > 0) & (shiftAmountImmediate < 32) THEN
  2234. IF ~IsSameRegister(destination[High], source[High]) THEN temp := destination[High] ELSE temp := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32)) END;
  2235. Emit2(opMOV, temp, InstructionSet.NewRegister(source[Low].register, InstructionSet.shiftLSR, None, 32 - shiftAmountImmediate));
  2236. Emit3(opORR, destination[High], temp, InstructionSet.NewRegister(source[High].register, InstructionSet.shiftLSL, None, shiftAmountImmediate));
  2237. Emit2(opMOV, destination[Low], InstructionSet.NewRegister(source[Low].register, InstructionSet.shiftLSL, None, shiftAmountImmediate))
  2238. ELSIF (shiftAmountImmediate >= 32) & (shiftAmountImmediate < 64) THEN
  2239. Emit2(opMOV, destination[High], InstructionSet.NewRegister(source[Low].register, InstructionSet.shiftLSL, None, shiftAmountImmediate - 32));
  2240. Emit2(opMOV, destination[Low], InstructionSet.NewImmediate(0))
  2241. ELSIF shiftAmountImmediate >= 64 THEN
  2242. Emit2(opMOV, destination[High], InstructionSet.NewImmediate(0));
  2243. Emit2(opMOV, destination[Low], InstructionSet.NewImmediate(0))
  2244. ELSE
  2245. HALT(100)
  2246. END
  2247. ELSE
  2248. (* complex left register shift: *)
  2249. IF ~IsSameRegister(destination[Low], source[Low]) THEN temp := destination[Low] ELSE temp := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32)) END;
  2250. Emit2(opCMP, shiftAmountRegister, InstructionSet.NewImmediate(32));
  2251. (* shiftAmount < 32: *)
  2252. Emit3WithCondition(opRSB, temp, shiftAmountRegister, InstructionSet.NewImmediate(32), InstructionSet.conditionLT);
  2253. Emit2WithCondition(opMOV, temp, InstructionSet.NewRegister(source[Low].register, InstructionSet.shiftLSR, temp.register, 0), InstructionSet.conditionLT);
  2254. Emit3WithCondition(opORR, destination[High], temp, InstructionSet.NewRegister(source[High].register, InstructionSet.shiftLSL, shiftAmountRegister.register, 0), InstructionSet.conditionLT);
  2255. Emit2WithCondition(opMOV, destination[Low], InstructionSet.NewRegister(source[Low].register, InstructionSet.shiftLSL, shiftAmountRegister.register, 0), InstructionSet.conditionLT);
  2256. (* shift amount >= 32: *)
  2257. Emit3WithCondition(opSUB, temp, shiftAmountRegister, InstructionSet.NewImmediate(32), InstructionSet.conditionGE);
  2258. Emit2WithCondition(opMOV, destination[High], InstructionSet.NewRegister(source[Low].register, InstructionSet.shiftLSL, temp.register, 0), InstructionSet.conditionGE);
  2259. Emit2WithCondition(opMOV, destination[Low], InstructionSet.NewImmediate(0), InstructionSet.conditionGE)
  2260. END
  2261. ELSE
  2262. (* simple left shift: *)
  2263. IF shiftAmountRegister.register = None THEN
  2264. (* simple left immediate shift *)
  2265. IF (shiftAmountImmediate >= 0) & (shiftAmountImmediate < 32) THEN
  2266. Emit2(opMOV, destination[Low], InstructionSet.NewRegister(source[Low].register, InstructionSet.shiftLSL, None, shiftAmountImmediate)) (* note: LSL has to be in the range 0..31 *)
  2267. ELSIF shiftAmountImmediate >= 32 THEN
  2268. Emit2(opMOV, destination[Low], InstructionSet.NewImmediate(0))
  2269. ELSE
  2270. HALT(100)
  2271. END
  2272. ELSE
  2273. (* simple left register shift: *)
  2274. Emit2(opMOV, destination[Low], InstructionSet.NewRegister(source[Low].register, InstructionSet.shiftLSL, shiftAmountRegister.register, 0))
  2275. END
  2276. END
  2277. | IntermediateCode.shr:
  2278. (* right shift: *)
  2279. (* determine shift mode (depends on if source operand is signed) *)
  2280. IF irInstruction.op1.type.form = IntermediateCode.UnsignedInteger THEN
  2281. (* logical right shift: *)
  2282. shiftMode := InstructionSet.shiftLSR
  2283. ELSE
  2284. (* arithmetic right shift: *)
  2285. shiftMode := InstructionSet.shiftASR
  2286. END;
  2287. IF IsComplex(irInstruction.op1) THEN
  2288. (* complex right shift: *)
  2289. IF shiftAmountRegister.register = None THEN
  2290. (* complex right immediate shift: *)
  2291. IF shiftAmountImmediate = 0 THEN
  2292. Emit2(opMOV, destination[High], source[High]);
  2293. Emit2(opMOV, destination[Low], source[Low])
  2294. ELSIF (shiftAmountImmediate > 0) & (shiftAmountImmediate < 32) THEN
  2295. IF ~IsSameRegister(destination[High], source[High]) THEN temp := destination[High] ELSE temp := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32)) END;
  2296. Emit2(opMOV, temp, InstructionSet.NewRegister(source[High].register, InstructionSet.shiftLSL, None, 32 - shiftAmountImmediate));
  2297. Emit3(opORR, destination[Low], temp, InstructionSet.NewRegister(source[Low].register, InstructionSet.shiftLSR, None, shiftAmountImmediate));
  2298. Emit2(opMOV, destination[High], InstructionSet.NewRegister(source[High].register, shiftMode, None, shiftAmountImmediate))
  2299. ELSIF shiftAmountImmediate >= 32 THEN
  2300. IF shiftAmountImmediate > 64 THEN shiftAmountImmediate := 64 END;
  2301. Emit2(opMOV, destination[Low], InstructionSet.NewRegister(source[High].register, shiftMode, None, shiftAmountImmediate - 32));
  2302. Emit2(opMOV, destination[High], InstructionSet.NewRegister(source[High].register, shiftMode, None, 32))
  2303. ELSE
  2304. HALT(100)
  2305. END
  2306. ELSE
  2307. (* complex right register shift: *)
  2308. IF ~IsSameRegister(destination[High], source[High]) THEN temp := destination[High] ELSE temp := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32)) END;
  2309. Emit2(opCMP, shiftAmountRegister, InstructionSet.NewImmediate(32));
  2310. (* shiftAmount < 32: *)
  2311. Emit3WithCondition(opRSB, temp, shiftAmountRegister, InstructionSet.NewImmediate(32), InstructionSet.conditionLT);
  2312. Emit2WithCondition(opMOV, temp, InstructionSet.NewRegister(source[High].register, InstructionSet.shiftLSL, temp.register, 0), InstructionSet.conditionLT);
  2313. Emit3WithCondition(opORR, destination[Low], temp, InstructionSet.NewRegister(source[Low].register, InstructionSet.shiftLSR, shiftAmountRegister.register, 0), InstructionSet.conditionLT);
  2314. Emit2WithCondition(opMOV, destination[High], InstructionSet.NewRegister(source[High].register, shiftMode, shiftAmountRegister.register, 0), InstructionSet.conditionLT);
  2315. (* shift amount >= 32: *)
  2316. Emit3WithCondition(opSUB, temp, shiftAmountRegister, InstructionSet.NewImmediate(32), InstructionSet.conditionGE);
  2317. Emit2WithCondition(opMOV, destination[Low], InstructionSet.NewRegister(source[High].register, shiftMode, temp.register, 0), InstructionSet.conditionGE);
  2318. Emit2WithCondition(opMOV, destination[High], InstructionSet.NewRegister(source[High].register, shiftMode, shiftAmountRegister.register, 0), InstructionSet.conditionGE)
  2319. END
  2320. ELSE
  2321. (* simple right shift: *)
  2322. SignOrZeroExtendOperand(source[Low], irInstruction.op1.type);
  2323. IF shiftAmountRegister.register = None THEN
  2324. (* simple right immediate shift: *)
  2325. IF shiftAmountImmediate > 32 THEN shiftAmountImmediate := 32 END;
  2326. Emit2(opMOV, destination[Low], InstructionSet.NewRegister(source[Low].register, shiftMode, None, shiftAmountImmediate))
  2327. ELSE
  2328. (* simple right register shift: *)
  2329. Emit2(opMOV, destination[Low], InstructionSet.NewRegister(source[Low].register, shiftMode, shiftAmountRegister.register, 0))
  2330. END
  2331. END
  2332. ELSE
  2333. HALT(100)
  2334. END;
  2335. WriteBack(irInstruction.op1, Low, destination[Low]);
  2336. IF IsComplex(irInstruction.op1) THEN WriteBack(irInstruction.op1, High, destination[High]) END
  2337. END EmitShiftOrRotation;
  2338. PROCEDURE EmitAsm(CONST irInstruction: IntermediateCode.Instruction);
  2339. VAR
  2340. reader: Streams.StringReader;
  2341. procedure: SyntaxTree.Procedure;
  2342. scope: SyntaxTree.Scope;
  2343. symbol: SyntaxTree.Symbol;
  2344. assembler: Assembler.Assembler;
  2345. scanner: Scanner.AssemblerScanner;
  2346. len: LONGINT;
  2347. BEGIN
  2348. len := Strings.Length(irInstruction.op1.string^);
  2349. NEW(reader, len);
  2350. reader.Set(irInstruction.op1.string^);
  2351. (* determine scope of the section *)
  2352. symbol := in.symbol;
  2353. IF symbol = NIL THEN
  2354. scope := NIL
  2355. ELSE
  2356. procedure := symbol(SyntaxTree.Procedure);
  2357. scope := procedure.procedureScope
  2358. END;
  2359. NEW(assembler, diagnostics);
  2360. scanner := Scanner.NewAssemblerScanner(module.moduleName(*module.module.sourceName*), reader, LONGINT(irInstruction.op1.intValue) (* ? *), diagnostics);
  2361. assembler.InlineAssemble(scanner, in, scope, module);
  2362. error := error OR assembler.error
  2363. END EmitAsm;
  2364. PROCEDURE EmitSpecial(VAR instruction: IntermediateCode.Instruction);
  2365. VAR
  2366. psrNumber, code, a, b, c, d: LONGINT;
  2367. register, register2, register3, register4, temp, cpOperand, cpRegister1, cpRegister2, opCode1Operand, opCode2Operand: Operand;
  2368. BEGIN
  2369. CASE instruction.subtype OF
  2370. | GetSP: Emit2(opMOV, opRES, opSP)
  2371. | SetSP: Emit2(opMOV, opSP, RegisterOrImmediateFromIrOperand(instruction.op1, Low, emptyOperand))
  2372. | GetFP: Emit2(opMOV, opRES, opFP)
  2373. | SetFP: Emit2(opMOV, opFP, RegisterOrImmediateFromIrOperand(instruction.op1, Low, emptyOperand))
  2374. | GetLNK: Emit2(opMOV, opRES, opLR)
  2375. | SetLNK: Emit2(opMOV, opLR, RegisterOrImmediateFromIrOperand(instruction.op1, Low, emptyOperand))
  2376. | GetPC: Emit2(opMOV, opRES, opPC)
  2377. | SetPC: Emit2(opMOV, opPC, RegisterOrImmediateFromIrOperand(instruction.op1, Low, emptyOperand))
  2378. | LDPSR, STPSR:
  2379. ASSERT(instruction.op1.type.form IN IntermediateCode.Integer);
  2380. IF instruction.op1.mode # IntermediateCode.ModeImmediate THEN
  2381. Error(instruction.textPosition,"first operand must be immediate")
  2382. ELSIF (instruction.op1.intValue < 0) OR (instruction.op1.intValue > 1) THEN
  2383. Error(instruction.textPosition,"first operand must be 0 or 1")
  2384. ELSE
  2385. IF instruction.op1.intValue = 0 THEN
  2386. psrNumber := InstructionSet.CPSR
  2387. ELSE
  2388. psrNumber := InstructionSet.SPSR
  2389. END;
  2390. register := RegisterFromIrOperand(instruction.op2, Low, emptyOperand);
  2391. IF instruction.subtype = LDPSR THEN
  2392. Emit2(opMSR, InstructionSet.NewRegisterWithFields(psrNumber, {InstructionSet.fieldF, InstructionSet.fieldC}), register)
  2393. ELSE
  2394. temp := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32));
  2395. Emit2(opMRS, temp, InstructionSet.NewRegister(psrNumber, None, None, 0));
  2396. Emit2(opSTR, temp, InstructionSet.NewImmediateOffsetMemory(register.register, 0, {InstructionSet.Increment}))
  2397. END
  2398. END
  2399. | LDCPR, STCPR:
  2400. IF instruction.op1.mode # IntermediateCode.ModeImmediate THEN
  2401. Error(instruction.textPosition,"first operand must be immediate")
  2402. ELSIF (instruction.op2.mode # IntermediateCode.ModeImmediate) THEN
  2403. Error(instruction.textPosition,"second operand must be immediate")
  2404. ELSIF (instruction.op2.intValue < 0) OR (instruction.op2.intValue > 15) THEN
  2405. Error(instruction.textPosition,"second operand must be between 0 or 15")
  2406. ELSE
  2407. code := LONGINT(instruction.op1.intValue); (* code = a00bcdH *)
  2408. a := (code DIV 100000H) MOD 10H; (* opcode1 * 2 *)
  2409. b := (code DIV 100H) MOD 10H; (* coprocessor number *)
  2410. c := (code DIV 10H) MOD 10H; (* opcode2 * 2 *)
  2411. d := code MOD 10H; (* coprocessor register2 number *)
  2412. InstructionSet.InitCoprocessor(cpOperand, InstructionSet.CP0 + b);
  2413. InstructionSet.InitOpcode(opCode1Operand, a DIV 2);
  2414. register := RegisterFromIrOperand(instruction.op3, Low, emptyOperand);
  2415. InstructionSet.InitRegister(cpRegister1, InstructionSet.CR0 + LONGINT(instruction.op2.intValue), None, None, 0);
  2416. InstructionSet.InitRegister(cpRegister2, InstructionSet.CR0 + d, None, None, 0);
  2417. InstructionSet.InitOpcode(opCode2Operand, c DIV 2);
  2418. IF instruction.subtype = LDCPR THEN
  2419. Emit6(opMCR, cpOperand, opCode1Operand, register, cpRegister1, cpRegister2, opCode2Operand)
  2420. ELSE
  2421. temp := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32));
  2422. Emit6(opMRC, cpOperand, opCode1Operand, temp, cpRegister1, cpRegister2, opCode2Operand);
  2423. Emit2(opSTR, temp, InstructionSet.NewImmediateOffsetMemory(register.register, 0, {InstructionSet.Increment}))
  2424. END
  2425. END
  2426. | FLUSH:
  2427. IF instruction.op1.mode # IntermediateCode.ModeImmediate THEN
  2428. Error(instruction.textPosition,"first operand must be immediate")
  2429. ELSIF (instruction.op1.intValue < 0) OR (instruction.op2.intValue > 0FFH) THEN
  2430. Error(instruction.textPosition,"first operand must be between 0 and 255")
  2431. ELSE
  2432. code := LONGINT(instruction.op1.intValue); (* code = aaa1bbbbB *)
  2433. a := (code DIV 20H) MOD 8; (* coprocessor opcode 2 *)
  2434. b := (code MOD 10H); (* coprocessor register2 number *)
  2435. (* examples:
  2436. 9AH = 10011000B -> MCR p15, 0, R0, c7, c10, 4
  2437. 17H = 00010111B -> MCR p15, 0, R0, c7, c7, 0
  2438. *)
  2439. InstructionSet.InitCoprocessor(cpOperand, InstructionSet.CP15);
  2440. InstructionSet.InitOpcode(opCode1Operand, 0);
  2441. InstructionSet.InitRegister(register, InstructionSet.R0, None, None, 0);
  2442. InstructionSet.InitRegister(cpRegister1, InstructionSet.CR7, None, None, 0);
  2443. InstructionSet.InitRegister(cpRegister2, InstructionSet.CR0 + b, None, None, 0);
  2444. InstructionSet.InitOpcode(opCode2Operand, a);
  2445. Emit6(opMCR, cpOperand, opCode1Operand, register, cpRegister1, cpRegister2, opCode2Operand);
  2446. Emit2(opMOV, register, register); (* NOP (register = R0) *)
  2447. Emit2(opMOV, register, register); (* NOP *)
  2448. Emit2(opMOV, register, register); (* NOP *)
  2449. Emit2(opMOV, register, register) (* NOP *)
  2450. END
  2451. | NULL:
  2452. register := RegisterFromIrOperand(instruction.op1, Low, emptyOperand);
  2453. Emit3(opBIC, register, register, InstructionSet.NewImmediate(LONGINT(80000000H)));
  2454. Emit2(opCMP, register, InstructionSet.NewImmediate(0));
  2455. Emit2WithCondition(opMOV, opRES, InstructionSet.NewImmediate(1), InstructionSet.conditionEQ);
  2456. Emit2WithCondition(opMOV, opRES, InstructionSet.NewImmediate(0), InstructionSet.conditionNE);
  2457. | XOR:
  2458. register := RegisterFromIrOperand(instruction.op1, Low, emptyOperand);
  2459. register2 := RegisterFromIrOperand(instruction.op2, Low, emptyOperand);
  2460. (*
  2461. register3 := RegisterFromIrOperand(instruction.op3, Low, emptyOperand);
  2462. *)
  2463. Emit3(opEOR, opRES, register, register2);
  2464. | MULD:
  2465. register := RegisterFromIrOperand(instruction.op1, Low, emptyOperand); (* note that 'register' contains an address *)
  2466. register2 := RegisterFromIrOperand(instruction.op2, Low, emptyOperand);
  2467. register3 := RegisterFromIrOperand(instruction.op3, Low, emptyOperand);
  2468. Emit4(opUMULL, opRES, opRESHI, register2, register3);
  2469. Emit2(opSTR, opRES, InstructionSet.NewImmediateOffsetMemory(register.register, 0, {InstructionSet.Increment})); (* JCH: 15.05.2012 *)
  2470. Emit2(opSTR, opRESHI, InstructionSet.NewImmediateOffsetMemory(register.register, 4, {InstructionSet.Increment}))
  2471. | ADDC:
  2472. register := RegisterFromIrOperand(instruction.op1, Low, emptyOperand);
  2473. register2 := RegisterFromIrOperand(instruction.op2, Low, emptyOperand);
  2474. Emit3(opADC, opRES, register, register2)
  2475. | PACK:
  2476. (* PACK(x, y):
  2477. add y to the binary exponent of y. PACK(x, y) is equivalent to x := x * 2^y. *)
  2478. register := RegisterFromIrOperand(instruction.op1, Low, emptyOperand); (* register = address of x *)
  2479. register2 := RegisterFromIrOperand(instruction.op2, Low, emptyOperand); (* register2 = value of y *)
  2480. register3 := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32)); (* a temporary INTEGER (!) register that is used to store a float *)
  2481. Emit2(opLDR, register3, InstructionSet.NewImmediateOffsetMemory(register.register, 0, {InstructionSet.Increment})); (* register3 = value of x *)
  2482. Emit3(opADD, register3, register3, InstructionSet.NewRegister(register2.register, InstructionSet.shiftLSL, None, 23)); (* increase the (biased) exponent of x by y*)
  2483. Emit2(opSTR, register3, InstructionSet.NewImmediateOffsetMemory(register.register, 0, {InstructionSet.Increment})) (* store new value of x *)
  2484. | UNPK:
  2485. (* UNPK(x, y):
  2486. remove the binary exponent on x and put it into y. UNPK is the reverse operation of PACK. The resulting x is normalized, i.e. 1.0 <= x < 2.0.
  2487. *)
  2488. register := RegisterFromIrOperand(instruction.op1, Low, emptyOperand); (* register = address of x *)
  2489. register2 := RegisterFromIrOperand(instruction.op2, Low, emptyOperand); (* register2 = address of y *)
  2490. register3 := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32)); (* a temporary INTEGER (!) register that is used to store a float *)
  2491. Emit2(opLDR, register3, InstructionSet.NewImmediateOffsetMemory(register.register, 0, {InstructionSet.Increment})); (* register3 = value of x *)
  2492. register4 := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32));
  2493. Emit2(opMOV, register4, InstructionSet.NewRegister(register3.register, InstructionSet.shiftLSR, None, 23)); (* register4 = biased exponent (and sign) of x *)
  2494. Emit3(opSUB, register4, register4, InstructionSet.NewImmediate(127)); (* register4 = exponent of x (biased exponent - 127) *)
  2495. Emit2(opSTR, register4, InstructionSet.NewImmediateOffsetMemory(register2.register, 0, {InstructionSet.Increment})); (* store exponent of x as value for y *)
  2496. Emit3(opSUB, register3, register3, InstructionSet.NewRegister(register4.register, InstructionSet.shiftLSL, None, 23)); (* reduce the biased exponent of x by the value of y *)
  2497. Emit2(opSTR, register3, InstructionSet.NewImmediateOffsetMemory(register.register, 0, {InstructionSet.Increment})) (* store new value of x *)
  2498. ELSE
  2499. HALT(100)
  2500. END
  2501. END EmitSpecial;
  2502. PROCEDURE EmitBr(VAR irInstruction: IntermediateCode.Instruction);
  2503. VAR
  2504. branchDistance: LONGINT;
  2505. isSwapped: BOOLEAN;
  2506. left, right: ARRAY 2 OF Operand;
  2507. temp: Operand;
  2508. irLeft, irRight: IntermediateCode.Operand;
  2509. fixup,failFixup: BinaryCode.Fixup;
  2510. fixupPatternList: ObjectFile.FixupPatterns;
  2511. identifier: ObjectFile.Identifier;
  2512. hiHit, hiFail, lowHit: LONGINT;
  2513. PROCEDURE JmpDest(branchConditionCode: LONGINT);
  2514. BEGIN
  2515. IF (irInstruction.op1.mode = IntermediateCode.ModeImmediate) & (irInstruction.op1.symbol.name = in.name) & (irInstruction.op1.offset = 0) THEN
  2516. (* branch within same section at a certain IR offset *)
  2517. (* optimization: abort if branch is to the next instruction *)
  2518. IF irInstruction.op1.symbolOffset = inPC + 1 THEN
  2519. IF dump # NIL THEN dump.String("branch to next instruction ignored"); dump.Ln END;
  2520. RETURN
  2521. END;
  2522. IF irInstruction.op1.symbolOffset <= inPC THEN
  2523. (* backward branch: calculate the branch distance *)
  2524. branchDistance := in.instructions[irInstruction.op1.symbolOffset].pc - out.pc - 8;
  2525. ASSERT((-33554432 <= branchDistance) & (branchDistance <= 0) & ((ABS(branchDistance) MOD 4) = 0), 200);
  2526. ELSE
  2527. (* forward branch: the distance is not yet known, use some placeholder and add a relative fixup *)
  2528. branchDistance := -4;
  2529. (* TODO: what about a branch to the next instruction? this would require the fixup meachnism to patch a negative value! (-> -4) *)
  2530. NEW(fixupPatternList, 1);
  2531. fixupPatternList[0].offset := 0;
  2532. fixupPatternList[0].bits := 24;
  2533. identifier.name := in.name;
  2534. identifier.fingerprint := in.fingerprint;
  2535. fixup := BinaryCode.NewFixup(BinaryCode.Relative, out.pc, identifier, irInstruction.op1.symbolOffset, -8, -2, fixupPatternList);
  2536. out.fixupList.AddFixup(fixup)
  2537. END;
  2538. Emit1WithCondition(opB, InstructionSet.NewImmediate(branchDistance), branchConditionCode)
  2539. ELSE
  2540. (* any other type of branch -> do register branch *)
  2541. Emit1WithCondition(opBX, RegisterFromIrOperand(irInstruction.op1, Low, emptyOperand), branchConditionCode)
  2542. END;
  2543. END JmpDest;
  2544. PROCEDURE Cmp(CONST left, right: InstructionSet.Operand; float: BOOLEAN);
  2545. BEGIN
  2546. IF float THEN
  2547. IF ~backend.useFPU32 (* NO FPU *) OR IsComplex(irLeft) (* 64 bit but not DP FPU *) THEN
  2548. (* floating point comparisons without VFP unit *)
  2549. temp := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32));
  2550. Emit3WithFlags(opAND, temp, left, right, {InstructionSet.flagS});
  2551. Emit2(opCMP, temp, InstructionSet.NewImmediate(0));
  2552. Emit1WithCondition(opB, InstructionSet.NewImmediate(4), InstructionSet.conditionLT); (* skip two instructions *)
  2553. Emit2(opCMP, left, right);
  2554. Emit1(opB, InstructionSet.NewImmediate(0)); (* skip one instructions *)
  2555. Emit2(opCMP, right, left);
  2556. ELSIF IsSinglePrecisionFloat(irLeft) THEN
  2557. Emit2(opFCMPS, left, right);
  2558. Emit0(opFMSTAT); (* transfer the VFP flags to the standard ARM flags *)
  2559. ELSIF IsDoublePrecisionFloat(irLeft) THEN
  2560. Emit2(opFCMPD, left, right);
  2561. Emit0(opFMSTAT); (* transfer the VFP flags to the standard ARM flags *)
  2562. END
  2563. ELSE
  2564. Emit2(opCMP, left, right);
  2565. END;
  2566. END Cmp;
  2567. BEGIN
  2568. hiFail := None;
  2569. hiHit := None;
  2570. IF irInstruction.opcode = IntermediateCode.br THEN
  2571. (* unconditional branch: *)
  2572. lowHit := InstructionSet.conditionAL
  2573. ELSE
  2574. (* conditional branch: *)
  2575. irLeft := irInstruction.op2; irRight := irInstruction.op3;
  2576. ASSERT((irLeft.type.form = irRight.type.form) & (irLeft.type.sizeInBits = irRight.type.sizeInBits));
  2577. IF IsInteger(irLeft) THEN
  2578. IF IsComplex(irLeft) THEN
  2579. CASE irInstruction.opcode OF
  2580. | IntermediateCode.breq, IntermediateCode.brne: (* left = right, left # right *)
  2581. lowHit := InstructionSet.conditionEQ;
  2582. left[High] := RegisterFromIrOperand(irLeft, High, emptyOperand);
  2583. right[High] := RegisterOrImmediateFromIrOperand(irRight, High, emptyOperand);
  2584. Emit2(opCMP, left[High], right[High]);
  2585. left[Low] := RegisterFromIrOperand(irLeft, Low, left[High]);
  2586. right[Low] := RegisterOrImmediateFromIrOperand(irRight, Low, right[High]);
  2587. Emit2WithCondition(opCMP, left[Low], right[Low], lowHit);
  2588. IF irInstruction.opcode = IntermediateCode.brne THEN lowHit := InstructionSet.conditionNE END;
  2589. | IntermediateCode.brlt, IntermediateCode.brge: (* left < right, left >= right *)
  2590. IF irInstruction.opcode = IntermediateCode.brlt THEN lowHit := InstructionSet.conditionLT ELSE lowHit := InstructionSet.conditionGE END;
  2591. ASSERT(irLeft.type.form = IntermediateCode.SignedInteger);
  2592. left[Low] := RegisterFromIrOperand(irLeft, Low, emptyOperand);
  2593. right[Low] := RegisterOrImmediateFromIrOperand(irRight, Low, emptyOperand);
  2594. temp := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32));
  2595. Emit3WithFlags(opSUB, temp, left[Low], right[Low], {InstructionSet.flagS});
  2596. left[High] := RegisterFromIrOperand(irLeft, High, left[Low]);
  2597. right[High] := RegisterOrImmediateFromIrOperand(irRight, High, right[Low]);
  2598. Emit3WithFlags(opSBC, temp, left[High], right[High], {InstructionSet.flagS}) (* the high part of the subtraction determines the sign *)
  2599. ELSE
  2600. HALT(100)
  2601. END
  2602. ELSE
  2603. ASSERT((irLeft.type.form IN IntermediateCode.Integer) & (irLeft.type.sizeInBits <= 32));
  2604. (* swap operands if beneficial *)
  2605. IF ~IrOperandIsDirectlyEncodable(irRight, Low) & IrOperandIsDirectlyEncodable(irLeft, Low) THEN
  2606. isSwapped := TRUE;
  2607. SwapIrOperands(irLeft, irRight)
  2608. END;
  2609. left[Low] := RegisterFromIrOperand(irLeft, Low, emptyOperand);
  2610. right[Low] := RegisterOrImmediateFromIrOperand(irRight, Low, emptyOperand);
  2611. SignOrZeroExtendOperand(left[Low], irLeft.type);
  2612. SignOrZeroExtendOperand(right[Low], irRight.type);
  2613. Cmp(left[Low], right[Low], FALSE);
  2614. (* determine condition code for the branch (take into consideration that operands could have been swapped) *)
  2615. CASE irInstruction.opcode OF
  2616. | IntermediateCode.breq: (* left = right *) lowHit := InstructionSet.conditionEQ
  2617. | IntermediateCode.brne: (* left # right *) lowHit := InstructionSet.conditionNE
  2618. | IntermediateCode.brlt: (* left < right *)
  2619. IF irInstruction.op2.type.form = IntermediateCode.UnsignedInteger THEN
  2620. IF isSwapped THEN lowHit := InstructionSet.conditionHI ELSE lowHit := InstructionSet.conditionLO END
  2621. ELSE
  2622. IF isSwapped THEN lowHit := InstructionSet.conditionGT ELSE lowHit := InstructionSet.conditionLT END
  2623. END
  2624. | IntermediateCode.brge: (* left >= right *)
  2625. IF irInstruction.op2.type.form = IntermediateCode.UnsignedInteger THEN
  2626. IF isSwapped THEN lowHit := InstructionSet.conditionLS ELSE lowHit := InstructionSet.conditionHS END
  2627. ELSE
  2628. IF isSwapped THEN lowHit := InstructionSet.conditionLE ELSE lowHit := InstructionSet.conditionGE END
  2629. END
  2630. ELSE HALT(100)
  2631. END
  2632. END
  2633. ELSIF IsSinglePrecisionFloat(irLeft) OR IsDoublePrecisionFloat(irLeft) & backend.useFPU64 THEN
  2634. left[Low] := RegisterFromIrOperand(irLeft, Low, emptyOperand);
  2635. right[Low] := RegisterFromIrOperand(irRight, Low, emptyOperand);
  2636. Cmp(left[Low], right[Low], TRUE);
  2637. CASE irInstruction.opcode OF
  2638. | IntermediateCode.breq: (* left = right *) lowHit := InstructionSet.conditionEQ
  2639. | IntermediateCode.brne: (* left # right *) lowHit := InstructionSet.conditionNE
  2640. | IntermediateCode.brlt: (* left < right *) lowHit := InstructionSet.conditionLT
  2641. | IntermediateCode.brge: (* left >= right *) lowHit := InstructionSet.conditionGE
  2642. ELSE HALT(100)
  2643. END
  2644. ELSIF IsDoublePrecisionFloat(irLeft) THEN
  2645. CASE irInstruction.opcode OF
  2646. IntermediateCode.breq:
  2647. hiHit := None; hiFail := InstructionSet.conditionNE; lowHit := InstructionSet.conditionEQ
  2648. |IntermediateCode.brne:
  2649. hiHit := InstructionSet.conditionNE; hiFail := None; lowHit := InstructionSet.conditionNE
  2650. |IntermediateCode.brge:
  2651. IF isSwapped THEN
  2652. hiHit := InstructionSet.conditionLT; hiFail := InstructionSet.conditionGT; lowHit := InstructionSet.conditionLS
  2653. ELSE
  2654. hiHit := InstructionSet.conditionGT; hiFail := InstructionSet.conditionLT; lowHit := InstructionSet.conditionHS
  2655. END;
  2656. |IntermediateCode.brlt:
  2657. IF isSwapped THEN
  2658. hiHit := InstructionSet.conditionGT; hiFail := InstructionSet.conditionLT; lowHit := InstructionSet.conditionHI
  2659. ELSE
  2660. hiHit := InstructionSet.conditionLT; hiFail := InstructionSet.conditionGT; lowHit := InstructionSet.conditionLO
  2661. END;
  2662. END;
  2663. (*
  2664. compare hi part (as float)
  2665. if hiHit then br dest
  2666. elsif hiFail then br fail
  2667. else compare low part (as unsigned int)
  2668. if lowHit then br dest
  2669. end
  2670. end,
  2671. fail:
  2672. *)
  2673. (* hi part *)
  2674. left[High] := RegisterFromIrOperand(irLeft, High, emptyOperand);
  2675. right[High] := RegisterOrImmediateFromIrOperand(irRight, High, emptyOperand);
  2676. Cmp(left[High], right[High], TRUE);
  2677. IF hiHit # None THEN
  2678. JmpDest(hiHit)
  2679. END;
  2680. IF hiFail # None THEN
  2681. NEW(fixupPatternList, 1);
  2682. fixupPatternList[0].offset := 0;
  2683. fixupPatternList[0].bits := 24;
  2684. identifier.name := in.name;
  2685. identifier.fingerprint := in.fingerprint;
  2686. failFixup := BinaryCode.NewFixup(BinaryCode.Relative, out.pc, identifier, irInstruction.op1.symbolOffset, -8, -2, fixupPatternList);
  2687. out.fixupList.AddFixup(failFixup);
  2688. Emit1WithCondition(opB, InstructionSet.NewImmediate(branchDistance), hiFail)
  2689. END;
  2690. (* low part *)
  2691. left[Low] := RegisterFromIrOperand(irLeft, Low, emptyOperand);
  2692. right[Low] := RegisterFromIrOperand(irRight, Low, emptyOperand);
  2693. Cmp(left[Low], right[Low], FALSE);
  2694. ELSE
  2695. HALT(200)
  2696. END
  2697. END;
  2698. JmpDest(lowHit);
  2699. IF failFixup # NIL THEN
  2700. failFixup.SetSymbol(in.name, in.fingerprint, 0, out.pc+failFixup.displacement (* displacement offset computed during operand emission, typically -1 *) );
  2701. failFixup.resolved := in;
  2702. END;
  2703. END EmitBr;
  2704. PROCEDURE RoundDown(VAR fpstatus: Operand);
  2705. BEGIN
  2706. fpstatus := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32));
  2707. (* round to minus infitinity *)
  2708. Emit2(InstructionSet.opVMRS, fpstatus, fpscr);
  2709. Emit3(opORR, fpstatus, fpstatus, InstructionSet.NewImmediate(0x800000));
  2710. Emit2(InstructionSet.opVMSR, fpscr, fpstatus);
  2711. END RoundDown;
  2712. PROCEDURE ResetRounding(VAR fpstatus: Operand);
  2713. BEGIN
  2714. (* reset rounding mode *)
  2715. Emit3(opBIC, fpstatus, fpstatus, InstructionSet.NewImmediate(0x800000));
  2716. Emit2(InstructionSet.opVMSR, fpscr, fpstatus);
  2717. END ResetRounding;
  2718. PROCEDURE EmitConv(VAR irInstruction: IntermediateCode.Instruction);
  2719. VAR
  2720. irDestination, irSource: IntermediateCode.Operand;
  2721. destination, source: ARRAY 2 OF Operand;
  2722. temp, fpstatus: Operand;
  2723. partType: IntermediateCode.Type;
  2724. BEGIN
  2725. irDestination := irInstruction.op1; irSource := irInstruction.op2;
  2726. (* prepare operands *)
  2727. destination[Low] := AcquireDestinationRegister(irDestination, Low, emptyOperand); (* TODO: find more optimal register allocation *)
  2728. source[Low] := RegisterOrImmediateFromIrOperand(irSource, Low, destination[Low]);
  2729. IF IsComplex(irDestination) THEN destination[High]:= AcquireDestinationRegister(irDestination, High, emptyOperand) END;
  2730. IF IsComplex(irSource) THEN source[High] := RegisterOrImmediateFromIrOperand(irSource, High, destination[High]) END; (* note that the corresponding destination register is used as hint *)
  2731. IF IsInteger(irDestination) THEN
  2732. (* to integer: *)
  2733. IF IsComplex(irDestination) THEN
  2734. ASSERT(IsInteger(irDestination));
  2735. (* to complex integer: *)
  2736. IF IsInteger(irSource) THEN
  2737. (* integer to complex integer: *)
  2738. IF IsComplex(irSource) THEN
  2739. (* complex integer to complex integer: *)
  2740. MovIfDifferent(destination[Low], source[Low]);
  2741. MovIfDifferent(destination[High], source[High]);
  2742. ELSE
  2743. (* non-complex integer to complex integer: *)
  2744. SignOrZeroExtendOperand(source[Low], irSource.type);
  2745. MovIfDifferent(destination[Low], source[Low]);
  2746. IF irDestination.type.form = IntermediateCode.UnsignedInteger THEN
  2747. Emit2(opMOV, destination[High], InstructionSet.NewImmediate(0));
  2748. ELSE
  2749. (* for signed values the high part is set to 0...0 or 1...1, depending on the sign of the low part *)
  2750. Emit2(opMOV, destination[High], InstructionSet.NewRegister(source[Low].register, InstructionSet.shiftASR, None, 31))
  2751. END
  2752. END
  2753. ELSIF IsFloat(irSource) THEN (* ENTIERH not supported natively *)
  2754. HALT(200);
  2755. ELSE
  2756. HALT(100);
  2757. END;
  2758. ELSE
  2759. (* to non-complex integer: *)
  2760. IF IsInteger(irSource) THEN
  2761. (* integer to non-complex integer *)
  2762. GetPartType(irSource.type, Low, partType);
  2763. SignOrZeroExtendOperand(source[Low], partType);
  2764. MovIfDifferent(destination[Low], source[Low])
  2765. ELSIF IsSinglePrecisionFloat(irSource) THEN
  2766. (* REAL --> INTEGER *)
  2767. ASSERT(backend.useFPU32);
  2768. (* single precision float to non-complex integer: *)
  2769. temp := GetFreeRegister(IntermediateCode.FloatType(32));
  2770. RoundDown(fpstatus);
  2771. IF irDestination.type.form = IntermediateCode.UnsignedInteger THEN
  2772. (* single precision float to non-complex unsigned integer: *)
  2773. Emit2(opFTOUIS, temp, source[Low]);
  2774. ELSE
  2775. (* single precision float to non-complex signed integer: *)
  2776. Emit2(opFTOSIS, temp, source[Low]);
  2777. END;
  2778. ResetRounding(fpstatus);
  2779. Emit2(opFMRS, destination[Low], temp)
  2780. ELSIF IsDoublePrecisionFloat(irSource) THEN
  2781. (* LONGREAL --> INTEGER *)
  2782. ASSERT(backend.useFPU64);
  2783. (* single precision float to non-complex integer: *)
  2784. temp := GetFreeRegister(IntermediateCode.FloatType(32));
  2785. RoundDown(fpstatus);
  2786. IF irDestination.type.form = IntermediateCode.UnsignedInteger THEN
  2787. (* single precision float to non-complex unsigned integer: *)
  2788. Emit2(opFTOUID, temp, source[Low]);
  2789. ELSE
  2790. (* single precision float to non-complex signed integer: *)
  2791. Emit2(opFTOSID, temp, source[Low]);
  2792. END;
  2793. ResetRounding(fpstatus);
  2794. Emit2(opFMRS, destination[Low], temp)
  2795. ELSE
  2796. (* anything to non-complex integer: *)
  2797. HALT(200)
  2798. END
  2799. END
  2800. ELSIF IsSinglePrecisionFloat(irDestination) THEN
  2801. (* to single precision float: *)
  2802. IF IsInteger(irSource) THEN
  2803. ASSERT(~IsComplex(irSource));
  2804. (* integer to single precision float: ignore high part of source *)
  2805. temp := GetFreeRegister(IntermediateCode.FloatType(32));
  2806. Emit2(opFMSR, temp, source[Low]);
  2807. IF irSource.type.form = IntermediateCode.UnsignedInteger THEN
  2808. (* non-complex unsigned integer to single precision float: *)
  2809. Emit2(opFUITOS, destination[Low], temp)
  2810. ELSE
  2811. (* non-complex signed integer to single precision float: *)
  2812. Emit2(opFSITOS, destination[Low], temp)
  2813. END
  2814. ELSIF IsSinglePrecisionFloat(irSource) THEN
  2815. (* single precision float to single precision float: *)
  2816. MovIfDifferent(destination[Low], source[Low])
  2817. ELSIF IsDoublePrecisionFloat(irSource) THEN
  2818. (* LONGREAL --> REAL *)
  2819. Emit2(opFCVTSD, destination[Low], source[Low])
  2820. ELSE
  2821. (* anything else to single precision float: *)
  2822. HALT(200)
  2823. END
  2824. ELSIF IsDoublePrecisionFloat(irDestination) THEN
  2825. (* to double precision float: *)
  2826. IF IsInteger(irSource) THEN
  2827. ASSERT(~IsComplex(irSource));
  2828. (* integer to double precision float: ignore high part of source *)
  2829. temp := GetFreeRegister(IntermediateCode.FloatType(32));
  2830. Emit2(opFMSR, temp, source[Low]);
  2831. IF irSource.type.form = IntermediateCode.UnsignedInteger THEN
  2832. (* non-complex unsigned integer to double precision float: *)
  2833. Emit2(opFUITOD, destination[Low], temp)
  2834. ELSE
  2835. (* non-complex signed integer to double precision float: *)
  2836. Emit2(opFSITOD, destination[Low], temp)
  2837. END
  2838. ELSIF IsSinglePrecisionFloat(irSource) THEN
  2839. (* REAL --> LONGREAL *)
  2840. Emit2(opFCVTDS, destination[Low], source[Low])
  2841. ELSIF IsDoublePrecisionFloat(irSource) THEN
  2842. (* single precision float to single precision float: *)
  2843. MovIfDifferent(destination[Low], source[Low])
  2844. ELSE
  2845. (* anything else to single precision float: *)
  2846. HALT(200)
  2847. END
  2848. ELSE
  2849. (* to anything else: *)
  2850. HALT(200)
  2851. END;
  2852. WriteBack(irDestination, Low, destination[Low]);
  2853. IF IsComplex(irDestination) THEN WriteBack(irInstruction.op1, High, destination[High]) END
  2854. END EmitConv;
  2855. (** get the register that is dedicated to store a return value of a function **)
  2856. PROCEDURE ResultRegister(part: LONGINT; type: IntermediateCode.Type): InstructionSet.Operand;
  2857. VAR
  2858. result: Operand;
  2859. BEGIN
  2860. IF (type.form IN IntermediateCode.Integer) THEN
  2861. IF part = Low THEN result := opRES
  2862. ELSIF part = High THEN result := opRESHI
  2863. ELSE HALT(200)
  2864. END
  2865. ELSIF type.form = IntermediateCode.Float THEN
  2866. IF (type.sizeInBits = 32) THEN
  2867. IF backend.useFPU32 THEN
  2868. result := opRESFS
  2869. ELSE
  2870. result := opRES
  2871. END;
  2872. ELSE
  2873. IF backend.useFPU64 THEN
  2874. result := opRESFD
  2875. ELSE
  2876. IF part = Low THEN result := opRES
  2877. ELSIF part = High THEN result := opRESHI
  2878. ELSE HALT(200)
  2879. END
  2880. END;
  2881. END;
  2882. END;
  2883. RETURN result
  2884. END ResultRegister;
  2885. PROCEDURE EmitReturn(VAR irInstruction: IntermediateCode.Instruction; part: LONGINT);
  2886. VAR
  2887. source: Operand;
  2888. BEGIN
  2889. source := RegisterOrImmediateFromIrOperand(irInstruction.op1, part, ResultRegister(part, irInstruction.op1.type)); (* note: the result register is given as a hint *)
  2890. MovIfDifferent(ResultRegister(part, irInstruction.op1.type), source)
  2891. END EmitReturn;
  2892. PROCEDURE EmitResult(VAR irInstruction: IntermediateCode.Instruction; part: LONGINT);
  2893. VAR
  2894. destinationRegister: Operand;
  2895. BEGIN
  2896. destinationRegister := AcquireDestinationRegister(irInstruction.op1, part, emptyOperand);
  2897. MovIfDifferent(destinationRegister, ResultRegister(part, irInstruction.op1.type));
  2898. WriteBack(irInstruction.op1, part, destinationRegister)
  2899. END EmitResult;
  2900. PROCEDURE EmitTrap(CONST irInstruction: IntermediateCode.Instruction);
  2901. BEGIN
  2902. ASSERT(irInstruction.op1.mode = IntermediateCode.ModeNumber);
  2903. Emit1(opSWI, InstructionSet.NewImmediate(LONGINT(irInstruction.op1.intValue))) (* software interrupt *)
  2904. END EmitTrap;
  2905. PROCEDURE EmitCas(VAR irInstruction: IntermediateCode.Instruction);
  2906. VAR
  2907. addressReg, addressBaseReg, comparandReg, comparandBaseReg, comparatorReg, comparatorBaseReg, tempReg: Operand
  2908. BEGIN
  2909. addressReg := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32));
  2910. addressBaseReg := RegisterFromIrOperand(irInstruction.op1, Low, addressReg);
  2911. MovIfDifferent(addressReg, addressBaseReg);
  2912. IF IntermediateCode.OperandEquals (irInstruction.op2, irInstruction.op3) THEN
  2913. Emit2(opLDR, opRES, InstructionSet.NewImmediateOffsetMemory(addressReg.register, 0, {InstructionSet.Increment}));
  2914. ELSE
  2915. comparandReg := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32));
  2916. comparandBaseReg := RegisterFromIrOperand(irInstruction.op2, Low, comparandReg);
  2917. MovIfDifferent(comparandReg, comparandBaseReg);
  2918. comparatorReg := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32));
  2919. comparatorBaseReg := RegisterFromIrOperand(irInstruction.op3, Low, comparatorReg);
  2920. MovIfDifferent(comparatorReg, comparatorBaseReg);
  2921. Emit2(opLDREX, opRES, addressReg);
  2922. Emit2(opCMP, opRES, comparandReg);
  2923. tempReg := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32));
  2924. Emit3WithCondition(opSTREX, tempReg, comparatorReg, addressReg, InstructionSet.conditionEQ);
  2925. Emit2WithCondition(opCMP, tempReg, InstructionSet.NewImmediate(1), InstructionSet.conditionEQ);
  2926. Emit1WithCondition(opB, InstructionSet.NewImmediate (-24), InstructionSet.conditionEQ);
  2927. END;
  2928. END EmitCas;
  2929. (* possible optimization: use a combination of LDR and LDRB (would be 4x faster on average) *)
  2930. PROCEDURE EmitCopy(VAR irInstruction: IntermediateCode.Instruction);
  2931. VAR
  2932. targetBaseReg, sourceBaseReg, length, lastSourceAddress, currentTargetReg, currentSourceReg, tempReg: Operand;
  2933. BEGIN
  2934. ASSERT((irInstruction.op1.type.form = IntermediateCode.UnsignedInteger) & (irInstruction.op1.type.sizeInBits = 32));
  2935. ASSERT((irInstruction.op2.type.form = IntermediateCode.UnsignedInteger) & (irInstruction.op2.type.sizeInBits = 32));
  2936. ASSERT((irInstruction.op3.type.form = IntermediateCode.UnsignedInteger) & (irInstruction.op3.type.sizeInBits = 32));
  2937. currentTargetReg := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32));
  2938. currentSourceReg := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32));
  2939. (* note that the registers that store the current addresses are used as hints: *)
  2940. targetBaseReg := RegisterFromIrOperand(irInstruction.op1, Low, currentTargetReg);
  2941. sourceBaseReg := RegisterFromIrOperand(irInstruction.op2, Low, currentSourceReg);
  2942. MovIfDifferent(currentTargetReg, targetBaseReg);
  2943. MovIfDifferent(currentSourceReg, sourceBaseReg);
  2944. lastSourceAddress := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32));
  2945. length := RegisterOrImmediateFromIrOperand(irInstruction.op3, Low, lastSourceAddress); (* note that the last source address register is used as hint*)
  2946. Emit3(opADD, lastSourceAddress, sourceBaseReg, length);
  2947. tempReg := GetFreeRegister(IntermediateCode.UnsignedIntegerType(32));
  2948. Emit2WithFlags(opLDR, tempReg, InstructionSet.NewImmediateOffsetMemory(currentSourceReg.register, 1, {InstructionSet.Increment, InstructionSet.PostIndexed}), {InstructionSet.flagB});
  2949. Emit2WithFlags(opSTR, tempReg, InstructionSet.NewImmediateOffsetMemory(currentTargetReg.register, 1, {InstructionSet.Increment, InstructionSet.PostIndexed}), {InstructionSet.flagB});
  2950. Emit2(opCMP, currentSourceReg, lastSourceAddress);
  2951. Emit1WithCondition(opB, InstructionSet.NewImmediate(-20), InstructionSet.conditionLT)
  2952. END EmitCopy;
  2953. PROCEDURE EmitFill(CONST irInstruction: IntermediateCode.Instruction; down: BOOLEAN);
  2954. BEGIN
  2955. HALT(200) (* note that this instruction is not used at the moment *)
  2956. END EmitFill;
  2957. (* PREPARATION OF OPERATIONS *)
  2958. (** swap a pair of IR operands **)
  2959. PROCEDURE SwapIrOperands(VAR left, right: IntermediateCode.Operand);
  2960. VAR
  2961. temp: IntermediateCode.Operand;
  2962. BEGIN
  2963. temp := left;
  2964. left := right;
  2965. right := temp
  2966. END SwapIrOperands;
  2967. PROCEDURE PrepareSingleSourceOp(VAR irInstruction: IntermediateCode.Instruction; part: LONGINT; VAR destinationRegister, sourceOperand: Operand);
  2968. BEGIN
  2969. destinationRegister := AcquireDestinationRegister(irInstruction.op1, part, emptyOperand);
  2970. sourceOperand := RegisterFromIrOperand(irInstruction.op2, part, destinationRegister); (* note that the destination register is used as hint *)
  2971. END PrepareSingleSourceOp;
  2972. PROCEDURE PrepareSingleSourceOpWithImmediate(VAR irInstruction: IntermediateCode.Instruction; part: LONGINT; VAR destinationRegister, sourceOperand: Operand);
  2973. BEGIN
  2974. destinationRegister := AcquireDestinationRegister(irInstruction.op1, part, emptyOperand);
  2975. sourceOperand := RegisterOrImmediateFromIrOperand(irInstruction.op2, part, destinationRegister); (* note that the destination register is used as hint *)
  2976. END PrepareSingleSourceOpWithImmediate;
  2977. PROCEDURE PrepareDoubleSourceOpWithImmediate(CONST irInstruction: IntermediateCode.Instruction; part: LONGINT; VAR destinationRegister, leftSourceOperand, rightSourceOperand: Operand; VAR isSwapped: BOOLEAN);
  2978. VAR
  2979. irDestination, irLeft, irRight: IntermediateCode.Operand;
  2980. BEGIN
  2981. irDestination := irInstruction.op1;
  2982. irLeft := irInstruction.op2;
  2983. irRight := irInstruction.op3;
  2984. destinationRegister:= AcquireDestinationRegister(irDestination, part, emptyOperand);
  2985. (* swap operands such that the right one is an immediate *)
  2986. IF IrOperandIsDirectlyEncodable(irLeft, part) & ~IrOperandIsDirectlyEncodable(irRight, part) THEN
  2987. SwapIrOperands(irLeft, irRight);
  2988. isSwapped := TRUE
  2989. ELSIF IntermediateCode.OperandEquals(irRight, irDestination) THEN
  2990. SwapIrOperands(irLeft, irRight);
  2991. isSwapped := TRUE
  2992. ELSE
  2993. isSwapped := FALSE
  2994. END;
  2995. leftSourceOperand := RegisterFromIrOperand(irLeft, part, destinationRegister); (* the destination register is used as hint *)
  2996. IF IsSameRegister(leftSourceOperand, destinationRegister) THEN
  2997. rightSourceOperand := RegisterOrImmediateFromIrOperand(irRight, part, emptyOperand) (* no hint is provided *)
  2998. ELSE
  2999. rightSourceOperand := RegisterOrImmediateFromIrOperand(irRight, part, destinationRegister) (* the destination register is again used as hint *)
  3000. END
  3001. END PrepareDoubleSourceOpWithImmediate;
  3002. PROCEDURE PrepareDoubleSourceOp(CONST irInstruction: IntermediateCode.Instruction; part: LONGINT; VAR destinationRegister, leftSourceOperand, rightSourceOperand: Operand);
  3003. VAR
  3004. irDestination, irLeft, irRight: IntermediateCode.Operand;
  3005. BEGIN
  3006. irDestination := irInstruction.op1;
  3007. irLeft := irInstruction.op2;
  3008. irRight := irInstruction.op3;
  3009. destinationRegister:= AcquireDestinationRegister(irDestination, part, emptyOperand);
  3010. IF IntermediateCode.OperandEquals(irRight, irDestination) THEN
  3011. leftSourceOperand := RegisterFromIrOperand(irLeft, part, emptyOperand); (* do not use destination register as hint *)
  3012. ELSE
  3013. leftSourceOperand := RegisterFromIrOperand(irLeft, part, destinationRegister); (* the destination register is used as hint *)
  3014. END;
  3015. IF IsSameRegister(leftSourceOperand, destinationRegister) OR IntermediateCode.OperandEquals(irRight, irDestination) THEN
  3016. rightSourceOperand := RegisterFromIrOperand(irRight, part, emptyOperand) (* no hint is provided *)
  3017. ELSE
  3018. rightSourceOperand := RegisterFromIrOperand(irRight, part, destinationRegister) (* the destination register is again used as hint *)
  3019. END
  3020. END PrepareDoubleSourceOp;
  3021. END CodeGeneratorARM;
  3022. BackendARM = OBJECT(IntermediateBackend.IntermediateBackend)
  3023. VAR
  3024. cg: CodeGeneratorARM;
  3025. system: Global.System;
  3026. useFPU32: BOOLEAN;
  3027. useFPU64: BOOLEAN;
  3028. initLocals: BOOLEAN;
  3029. PROCEDURE & InitBackendARM;
  3030. BEGIN
  3031. useFPU32 := FALSE;
  3032. useFPU64 := FALSE;
  3033. InitIntermediateBackend;
  3034. SetRuntimeModuleName(DefaultRuntimeModuleName);
  3035. SetNewObjectFile(TRUE,FALSE);
  3036. system := NIL;
  3037. initLocals := TRUE;
  3038. SetHasLinkRegister;
  3039. SetName("ARM");
  3040. END InitBackendARM;
  3041. PROCEDURE Initialize(diagnostics: Diagnostics.Diagnostics; log: Streams.Writer; flags: SET; checker: SemanticChecker.Checker; system: Global.System);
  3042. BEGIN
  3043. Initialize^(diagnostics, log, flags, checker, system);
  3044. NEW(cg, runtimeModuleName, diagnostics, SELF)
  3045. END Initialize;
  3046. PROCEDURE EnterCustomBuiltins;
  3047. VAR
  3048. procedureType: SyntaxTree.ProcedureType;
  3049. parameter: SyntaxTree.Parameter;
  3050. PROCEDURE New;
  3051. BEGIN procedureType := SyntaxTree.NewProcedureType(-1, NIL)
  3052. END New;
  3053. PROCEDURE BoolRet;
  3054. BEGIN procedureType.SetReturnType(system.booleanType)
  3055. END BoolRet;
  3056. PROCEDURE IntRet;
  3057. BEGIN procedureType.SetReturnType(Global.Integer32)
  3058. END IntRet;
  3059. PROCEDURE IntPar;
  3060. BEGIN
  3061. parameter := SyntaxTree.NewParameter(-1, procedureType, SyntaxTree.NewIdentifier(""), SyntaxTree.ValueParameter);
  3062. parameter.SetType(Global.Integer32); procedureType.AddParameter(parameter)
  3063. END IntPar;
  3064. PROCEDURE AddressPar;
  3065. BEGIN
  3066. parameter := SyntaxTree.NewParameter(-1, procedureType, SyntaxTree.NewIdentifier(""), SyntaxTree.ValueParameter);
  3067. parameter.SetType(Global.Unsigned32); procedureType.AddParameter(parameter)
  3068. END AddressPar;
  3069. PROCEDURE IntVarPar;
  3070. BEGIN
  3071. parameter := SyntaxTree.NewParameter(-1, procedureType, SyntaxTree.NewIdentifier(""), SyntaxTree.VarParameter);
  3072. parameter.SetType(Global.Integer32); procedureType.AddParameter(parameter)
  3073. END IntVarPar;
  3074. PROCEDURE RealVarPar;
  3075. BEGIN
  3076. parameter := SyntaxTree.NewParameter(-1, procedureType, SyntaxTree.NewIdentifier(""), SyntaxTree.VarParameter);
  3077. parameter.SetType(Global.Float32); procedureType.AddParameter(parameter)
  3078. END RealVarPar;
  3079. PROCEDURE Finish(CONST name: ARRAY OF CHAR; number: SHORTINT);
  3080. BEGIN Global.NewCustomBuiltin(name, system.systemScope, number, procedureType);
  3081. END Finish;
  3082. BEGIN
  3083. New; IntRet; Finish("SP", GetSP);
  3084. New; AddressPar; Finish("SetSP", SetSP);
  3085. New; IntRet; Finish("FP", GetFP);
  3086. New; AddressPar; Finish("SetFP", SetFP);
  3087. New; IntRet; Finish("PC", GetPC);
  3088. New; AddressPar; Finish("SetPC", SetPC);
  3089. New; IntRet; Finish("LNK", GetLNK);
  3090. New; AddressPar; Finish("SetLNK", SetLNK);
  3091. New; IntPar; IntPar; Finish("LDPSR", LDPSR);
  3092. New; IntPar; IntVarPar; Finish("STPSR", STPSR);
  3093. New; IntPar; IntPar; IntPar; Finish("LDCPR", LDCPR);
  3094. New; IntPar; IntPar; IntVarPar; Finish("STCPR", STCPR);
  3095. New; IntPar; Finish("FLUSH", FLUSH);
  3096. New; BoolRet; IntPar; Finish("NULL", NULL);
  3097. New; IntRet; IntPar; IntPar; Finish("XOR", XOR);
  3098. New; IntVarPar; IntPar; IntPar; Finish("MULD", MULD);
  3099. New; IntVarPar; IntPar; IntPar; Finish("ADDC", ADDC);
  3100. New; RealVarPar; IntPar; Finish("PACK", PACK);
  3101. New; RealVarPar; IntVarPar; Finish("UNPK", UNPK);
  3102. END EnterCustomBuiltins;
  3103. PROCEDURE GetSystem(): Global.System;
  3104. BEGIN
  3105. (* create system object if not yet existing *)
  3106. IF system = NIL THEN
  3107. (* used stack frame layout:
  3108. param 1
  3109. param 2
  3110. ...
  3111. param n-1
  3112. FP+8 -> param n
  3113. FP+4 -> old LR
  3114. FP -> old FP
  3115. FP-4 -> local 1
  3116. local 2
  3117. ...
  3118. spill 1
  3119. spill 2
  3120. ....
  3121. *)
  3122. (*
  3123. codeUnit, dataUnit = 8, 8
  3124. addressSize = 32
  3125. minVarAlign, maxVarAlign = 32, 32
  3126. minParAlign, maxParAlign = 8, 32
  3127. offsetFirstPar = 32 * 2
  3128. registerParameters = 0
  3129. *)
  3130. NEW(system, 8, 8, 32, (*32*) 8, 32, 8, 32, 32 * 2, cooperative);
  3131. IF oberon07 THEN
  3132. IF Trace THEN D.String("Oberon07"); D.Ln END;
  3133. Global.SetDefaultDeclarations(system, 32) (* each basic type uses at least 32 bits -> INTEGER will be 32 bits long *)
  3134. ELSE
  3135. IF Trace THEN D.String("not Oberon07"); D.Ln END;
  3136. Global.SetDefaultDeclarations(system, 8) (* INTEGER will be 16 bits long *)
  3137. END;
  3138. Global.SetDefaultOperators(system);
  3139. EnterCustomBuiltins
  3140. END;
  3141. RETURN system
  3142. END GetSystem;
  3143. (** whether the code generator can generate code for a certain IR instruction
  3144. if not, where to find the runtime procedure that is to be called instead **)
  3145. PROCEDURE SupportedInstruction(CONST irInstruction: IntermediateCode.Instruction; VAR moduleName, procedureName: ARRAY OF CHAR): BOOLEAN;
  3146. BEGIN
  3147. (* only necessary for binary object file format for symbol / module entry in IntermediateBackend *)
  3148. RETURN cg.Supported(irInstruction, moduleName, procedureName);
  3149. END SupportedInstruction;
  3150. (** whether a certain intermediate code immediate value can be directly appear in code
  3151. if not, the value is stored in a const section and loaded from there **)
  3152. PROCEDURE SupportedImmediate(CONST irImmediateOperand: IntermediateCode.Operand): BOOLEAN;
  3153. VAR
  3154. result: BOOLEAN;
  3155. BEGIN
  3156. (* TODO: remove this *)
  3157. RETURN TRUE; (* tentatively generate all immediates, as symbol fixups are not yet implemented *)
  3158. result := FALSE;
  3159. IF (irImmediateOperand.type.form IN IntermediateCode.Integer) & (irImmediateOperand.type.sizeInBits <= 32) THEN
  3160. (* 32 bit integers *)
  3161. IF cg.ValueIsDirectlyEncodable(LONGINT(irImmediateOperand.intValue)) THEN
  3162. (* the value can be directly encoded as an ARM immediate operand *)
  3163. result := TRUE
  3164. ELSIF cg.ValueComposition(LONGINT(irImmediateOperand.intValue), FALSE, emptyOperand) <= 2 THEN (* TODO: find reasonable limit *)
  3165. (* the value can be generated using a limited amount of intructions *)
  3166. result := TRUE
  3167. END
  3168. END;
  3169. RETURN result
  3170. END SupportedImmediate;
  3171. PROCEDURE GenerateBinary(module: Sections.Module; dump: Streams.Writer);
  3172. VAR
  3173. in: Sections.Section;
  3174. out: BinaryCode.Section;
  3175. name: Basic.SectionName;
  3176. procedure: SyntaxTree.Procedure;
  3177. i, j, initialSectionCount: LONGINT;
  3178. (* recompute fixup positions and assign binary sections *)
  3179. PROCEDURE PatchFixups(section: BinaryCode.Section);
  3180. VAR resolved: BinaryCode.Section; fixup: BinaryCode.Fixup; displacement,symbolOffset: LONGINT; in: IntermediateCode.Section;
  3181. symbol: Sections.Section;
  3182. BEGIN
  3183. fixup := section.fixupList.firstFixup;
  3184. WHILE fixup # NIL DO
  3185. symbol := module.allSections.FindByName(fixup.symbol.name);
  3186. IF (symbol # NIL) & (symbol(IntermediateCode.Section).resolved # NIL) THEN
  3187. resolved := symbol(IntermediateCode.Section).resolved(BinaryCode.Section);
  3188. in := symbol(IntermediateCode.Section);
  3189. symbolOffset := fixup.symbolOffset;
  3190. IF symbolOffset = in.pc THEN
  3191. displacement := resolved.pc
  3192. ELSIF (symbolOffset # 0) THEN
  3193. ASSERT(in.pc > symbolOffset);
  3194. displacement := in.instructions[symbolOffset].pc;
  3195. ELSE
  3196. displacement := 0;
  3197. END;
  3198. fixup.SetSymbol(fixup.symbol.name,fixup.symbol.fingerprint,0,fixup.displacement+displacement);
  3199. END;
  3200. fixup := fixup.nextFixup;
  3201. END;
  3202. END PatchFixups;
  3203. (*
  3204. PROCEDURE Resolve(VAR fixup: BinaryCode.Fixup);
  3205. BEGIN
  3206. IF (fixup.symbol.name # "") & (fixup.resolved = NIL) THEN fixup.resolved := module.allSections.FindByName(fixup.symbol.name) END;
  3207. END Resolve;
  3208. (* recompute fixup positions and assign binary sections *)
  3209. PROCEDURE PatchFixups(section: BinaryCode.Section);
  3210. VAR resolved: BinaryCode.Section; fixup: BinaryCode.Fixup; symbolOffset, offsetWithinSection: LONGINT; in: IntermediateCode.Section;
  3211. BEGIN
  3212. fixup := section.fixupList.firstFixup;
  3213. WHILE fixup # NIL DO
  3214. Resolve(fixup);
  3215. IF (fixup.resolved # NIL) & (fixup.resolved(IntermediateCode.Section).resolved # NIL) THEN
  3216. resolved := fixup.resolved(IntermediateCode.Section).resolved(BinaryCode.Section);
  3217. in := fixup.resolved(IntermediateCode.Section);
  3218. (* TODO: is this correct? *)
  3219. symbolOffset := fixup.symbolOffset;
  3220. ASSERT(fixup.symbolOffset < in.pc);
  3221. IF (fixup.symbolOffset # 0) & (symbolOffset < in.pc) THEN
  3222. offsetWithinSection := in.instructions[fixup.symbolOffset].pc;
  3223. (*
  3224. (* TENTATIVE *)
  3225. D.String("FIXUP PATCH:"); D.Ln;
  3226. D.String(" symbol name: "); fixup.symbol.DumpName(D.Log); D.String("/");
  3227. D.String(" symbol offset: "); D.Int(fixup.symbolOffset, 0); D.Ln;
  3228. D.String(" offsetWithinSection"); D.Int(offsetWithinSection, 0); D.Ln;
  3229. D.String(" fixup.displacement (before)"); D.Int(fixup.displacement, 0); D.Ln; ; D.Ln;
  3230. D.Update;
  3231. *)
  3232. (* remove the fixup's symbol offset (in IR units) and change the displacement (in system units) accordingly: *)
  3233. fixup.SetSymbol(fixup.symbol.name, fixup.symbol.fingerprint, 0, offsetWithinSection + fixup.displacement)
  3234. END
  3235. END;
  3236. fixup := fixup.nextFixup;
  3237. END;
  3238. END PatchFixups;
  3239. *)
  3240. BEGIN
  3241. cg.SetModule(module);
  3242. cg.dump := dump;
  3243. FOR i := 0 TO module.allSections.Length() - 1 DO
  3244. in := module.allSections.GetSection(i);
  3245. IF in.type = Sections.InlineCodeSection THEN
  3246. Basic.SegmentedNameToString(in.name, name);
  3247. out := ResolvedSection(in(IntermediateCode.Section));
  3248. cg.dump := out.comments;
  3249. cg.Section(in(IntermediateCode.Section), out);
  3250. IF in.symbol # NIL THEN
  3251. procedure := in.symbol(SyntaxTree.Procedure);
  3252. procedure.procedureScope.body.code.SetBinaryCode(out.os.bits);
  3253. END;
  3254. END
  3255. END;
  3256. initialSectionCount := 0;
  3257. REPEAT
  3258. j := initialSectionCount;
  3259. initialSectionCount := module.allSections.Length() ;
  3260. FOR i := j TO initialSectionCount - 1 DO
  3261. in := module.allSections.GetSection(i);
  3262. Basic.SegmentedNameToString(in.name, name);
  3263. IF (in.type # Sections.InlineCodeSection) (*& (in(IntermediateCode.Section).resolved = NIL) *) THEN
  3264. out := ResolvedSection(in(IntermediateCode.Section));
  3265. cg.Section(in(IntermediateCode.Section),out);
  3266. END
  3267. END
  3268. UNTIL initialSectionCount = module.allSections.Length(); (* process remaining sections that have been added during traversal of sections *)
  3269. FOR i := 0 TO module.allSections.Length() - 1 DO
  3270. in := module.allSections.GetSection(i);
  3271. Basic.SegmentedNameToString(in.name, name);
  3272. in := module.allSections.GetSection(i);
  3273. PatchFixups(in(IntermediateCode.Section).resolved)
  3274. END;
  3275. IF cg.error THEN Error("", Diagnostics.Invalid, Diagnostics.Invalid, "") END
  3276. END GenerateBinary;
  3277. (** create an ARM code module from an intermediate code module **)
  3278. PROCEDURE ProcessIntermediateCodeModule*(intermediateCodeModule: Formats.GeneratedModule): Formats.GeneratedModule;
  3279. VAR
  3280. result: Formats.GeneratedModule;
  3281. BEGIN
  3282. ASSERT(intermediateCodeModule IS Sections.Module);
  3283. result := ProcessIntermediateCodeModule^(intermediateCodeModule);
  3284. IF ~error THEN
  3285. GenerateBinary(result(Sections.Module), dump);
  3286. IF dump # NIL THEN
  3287. dump.Ln; dump.Ln;
  3288. dump.String("------------------ binary code -------------------"); dump.Ln;
  3289. IF (traceString="") OR (traceString="*") THEN
  3290. result.Dump(dump);
  3291. dump.Update
  3292. ELSE
  3293. Sections.DumpFiltered(dump, result(Sections.Module), traceString);
  3294. dump.Update;
  3295. END
  3296. END;
  3297. END;
  3298. RETURN result
  3299. FINALLY
  3300. IF dump # NIL THEN
  3301. dump.Ln; dump.Ln;
  3302. dump.String("------------------ rescued code (code generation trapped) -------------------"); dump.Ln;
  3303. IF (traceString="") OR (traceString="*") THEN
  3304. result.Dump(dump);
  3305. dump.Update
  3306. ELSE
  3307. Sections.DumpFiltered(dump,result(Sections.Module),traceString);
  3308. dump.Update;
  3309. END
  3310. END;
  3311. RETURN result
  3312. END ProcessIntermediateCodeModule;
  3313. PROCEDURE DefineOptions(options: Options.Options);
  3314. BEGIN
  3315. options.Add(0X, UseFPU32Flag, Options.Flag);
  3316. options.Add(0X, UseFPU64Flag, Options.Flag);
  3317. options.Add(0X, "noInitLocals", Options.Flag);
  3318. DefineOptions^(options);
  3319. END DefineOptions;
  3320. PROCEDURE GetOptions(options: Options.Options);
  3321. BEGIN
  3322. IF options.GetFlag(UseFPU32Flag) THEN useFPU32 := TRUE END;
  3323. IF options.GetFlag(UseFPU64Flag) THEN useFPU64 := TRUE; useFPU32 := TRUE END;
  3324. IF options.GetFlag("noInitLocals") THEN initLocals := FALSE END;
  3325. GetOptions^(options);
  3326. END GetOptions;
  3327. PROCEDURE DefaultObjectFileFormat(): Formats.ObjectFileFormat;
  3328. BEGIN RETURN ObjectFileFormat.Get();
  3329. END DefaultObjectFileFormat;
  3330. PROCEDURE DefaultSymbolFileFormat(): Formats.SymbolFileFormat;
  3331. BEGIN RETURN NIL
  3332. END DefaultSymbolFileFormat;
  3333. (** get the name of the backend **)
  3334. PROCEDURE GetDescription(VAR instructionSet: ARRAY OF CHAR);
  3335. BEGIN instructionSet := "ARM"
  3336. END GetDescription;
  3337. PROCEDURE FindPC(x: SyntaxTree.Module; CONST sectionName: ARRAY OF CHAR; sectionOffset: LONGINT);
  3338. VAR
  3339. section: Sections.Section; binarySection: BinaryCode.Section; label: BinaryCode.LabelList; module: Formats.GeneratedModule;
  3340. i: LONGINT; pooledName: Basic.SegmentedName;
  3341. BEGIN
  3342. module := ProcessSyntaxTreeModule(x);
  3343. Basic.ToSegmentedName(sectionName, pooledName);
  3344. i := 0;
  3345. REPEAT
  3346. section := module(Sections.Module).allSections.GetSection(i);
  3347. INC(i);
  3348. UNTIL (i = module(Sections.Module).allSections.Length()) OR (section.name = pooledName);
  3349. IF section.name # pooledName THEN
  3350. diagnostics.Error(module.module.sourceName,Diagnostics.Invalid,Diagnostics.Invalid," could not locate pc");
  3351. ELSE
  3352. binarySection := section(IntermediateCode.Section).resolved;
  3353. label := binarySection.labels;
  3354. WHILE (label # NIL) & (label.offset >= sectionOffset) DO
  3355. label := label.prev;
  3356. END;
  3357. IF label # NIL THEN
  3358. diagnostics.Information(module.module.sourceName,label.position,Diagnostics.Invalid," pc position");
  3359. ELSE
  3360. diagnostics.Error(module.module.sourceName,Diagnostics.Invalid,Diagnostics.Invalid," could not locate pc");
  3361. END;
  3362. END;
  3363. END FindPC;
  3364. END BackendARM;
  3365. VAR
  3366. emptyOperand: Operand;
  3367. rFixupPattern: ObjectFile.FixupPatterns; (* pattern for an absolute 32-bit fixup *)
  3368. PROCEDURE Assert(condition: BOOLEAN; CONST message: ARRAY OF CHAR);
  3369. BEGIN ASSERT(condition, 100)
  3370. END Assert;
  3371. PROCEDURE Halt(CONST message: ARRAY OF CHAR);
  3372. BEGIN HALT(100)
  3373. END Halt;
  3374. (** get the ARM code section that corresponds to an intermediate code section **)
  3375. PROCEDURE ResolvedSection(irSection: IntermediateCode.Section): BinaryCode.Section;
  3376. VAR
  3377. result: BinaryCode.Section;
  3378. BEGIN
  3379. IF irSection.resolved = NIL THEN
  3380. NEW(result, irSection.type, irSection.priority, 8, irSection.name, irSection.comments # NIL, FALSE);
  3381. (* set fixed position or alignment
  3382. (also make sure that any section has an alignment of at least 4 bytes) *)
  3383. IF ~irSection.fixed & (irSection.positionOrAlignment < 4) THEN
  3384. result.SetAlignment(FALSE, 4)
  3385. ELSE
  3386. result.SetAlignment(irSection.fixed, irSection.positionOrAlignment);
  3387. END;
  3388. irSection.SetResolved(result)
  3389. ELSE
  3390. result := irSection.resolved
  3391. END;
  3392. RETURN result
  3393. END ResolvedSection;
  3394. (** initialize the module **)
  3395. PROCEDURE Init;
  3396. BEGIN
  3397. InstructionSet.InitOperand(emptyOperand);
  3398. NEW(rFixupPattern, 1);
  3399. rFixupPattern[0].offset := 0;
  3400. rFixupPattern[0].bits := 32;
  3401. END Init;
  3402. (** get an instance of the ARM backend **)
  3403. PROCEDURE Get*(): Backend.Backend;
  3404. VAR
  3405. result: BackendARM;
  3406. BEGIN
  3407. NEW(result);
  3408. RETURN result
  3409. END Get;
  3410. (* only for testing purposes *)
  3411. PROCEDURE Test*;
  3412. VAR
  3413. codeGenerator: CodeGeneratorARM;
  3414. value, count: LONGINT;
  3415. BEGIN
  3416. NEW(codeGenerator, "", NIL, NIL);
  3417. FOR value := 0 TO 300 BY 1 DO
  3418. count := codeGenerator.ValueComposition(value, FALSE, emptyOperand);
  3419. D.String("value: "); D.Int(value, 0); D.String(" -> "); D.Int(count, 0); D.String(" instructions"); D.Ln;
  3420. END;
  3421. D.Ln; D.Update
  3422. END Test;
  3423. (* TODO: move this to Debugging.Mod or even Streams.Mod *)
  3424. (** write an integer in binary right-justified in a field of at least ABS(w) characters.
  3425. If w < 0 THEN ABS(w) least significant hex digits of 'value' are written (potentially including leading zeros or ones)
  3426. **)
  3427. PROCEDURE DBin*(value: HUGEINT; numberDigits: LONGINT);
  3428. CONST
  3429. MaxBitSize = SIZEOF(HUGEINT) * 8;
  3430. VAR
  3431. i, firstRelevantPos: LONGINT;
  3432. prefixWithSpaces: BOOLEAN;
  3433. chars: ARRAY MaxBitSize OF CHAR;
  3434. prefixChar: CHAR;
  3435. BEGIN
  3436. prefixWithSpaces := numberDigits >= 0;
  3437. numberDigits := ABS(numberDigits);
  3438. (*
  3439. - calculate an array containing the full bitstring
  3440. - determine the position of the first relevant digit
  3441. *)
  3442. firstRelevantPos := 0;
  3443. FOR i := MaxBitSize - 1 TO 0 BY -1 DO
  3444. IF ODD(value) THEN
  3445. chars[i] := '1';
  3446. firstRelevantPos := i (* occurence of a '1' -> changes the first relevant position *)
  3447. ELSE
  3448. chars[i] := '0'
  3449. END;
  3450. value := value DIV 2
  3451. END;
  3452. (* if space prefixing is enabled, limit the number of digits to the relevant digits *)
  3453. IF prefixWithSpaces THEN numberDigits := MAX(numberDigits, MaxBitSize - firstRelevantPos) END;
  3454. IF numberDigits > MaxBitSize THEN
  3455. IF prefixWithSpaces THEN prefixChar := ' ' ELSE prefixChar := chars[0] END; (* use spaces or sign bit *)
  3456. FOR i := 1 TO numberDigits - MaxBitSize DO D.Char(prefixChar) END;
  3457. numberDigits := MaxBitSize
  3458. END;
  3459. ASSERT((numberDigits >= 0) & (numberDigits <= MaxBitSize));
  3460. FOR i := MaxBitSize - numberDigits TO MaxBitSize - 1 DO
  3461. IF prefixWithSpaces & (i < firstRelevantPos) THEN D.Char(' ') ELSE D.Char(chars[i]) END
  3462. END;
  3463. D.Ln;
  3464. END DBin;
  3465. BEGIN
  3466. Init;
  3467. END FoxARMBackend.
  3468. SystemTools.FreeDownTo FoxARMBackend ~