cgcpu.pas 149 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813
  1. {
  2. Copyright (c) 2003 by Florian Klaempfl
  3. Member of the Free Pascal development team
  4. This unit implements the code generator for the ARM
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit cgcpu;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. globtype,symtype,symdef,
  23. cgbase,cgutils,cgobj,
  24. aasmbase,aasmcpu,aasmtai,aasmdata,
  25. parabase,
  26. cpubase,cpuinfo,node,cg64f32,rgcpu;
  27. type
  28. tcgarm = class(tcg)
  29. { true, if the next arithmetic operation should modify the flags }
  30. cgsetflags : boolean;
  31. procedure a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const paraloc : TCGPara);override;
  32. procedure a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);override;
  33. procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara);override;
  34. procedure a_call_name(list : TAsmList;const s : string; weak: boolean);override;
  35. procedure a_call_reg(list : TAsmList;reg: tregister);override;
  36. procedure a_call_ref(list : TAsmList;ref: treference);override;
  37. procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override;
  38. procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  39. procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg;
  40. size: tcgsize; a: tcgint; src, dst: tregister); override;
  41. procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg;
  42. size: tcgsize; src1, src2, dst: tregister); override;
  43. procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  44. procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  45. { move instructions }
  46. procedure a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
  47. procedure a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
  48. function a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference;
  49. function a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference;
  50. { fpu move instructions }
  51. procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
  52. procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
  53. procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
  54. procedure a_loadfpu_ref_cgpara(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);override;
  55. { comparison operations }
  56. procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister;
  57. l : tasmlabel);override;
  58. procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  59. procedure a_jmp_name(list : TAsmList;const s : string); override;
  60. procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
  61. procedure a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); override;
  62. procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  63. procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
  64. procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
  65. procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
  66. procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);override;
  67. procedure g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : tcgint);override;
  68. procedure g_concatcopy_move(list : TAsmList;const source,dest : treference;len : tcgint);
  69. procedure g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : tcgint;aligned : boolean);
  70. procedure g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef); override;
  71. procedure g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);override;
  72. procedure g_save_registers(list : TAsmList);override;
  73. procedure g_restore_registers(list : TAsmList);override;
  74. procedure a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  75. procedure fixref(list : TAsmList;var ref : treference);
  76. function handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference; virtual;
  77. procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
  78. procedure g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint); override;
  79. procedure g_stackpointer_alloc(list : TAsmList;size : longint);override;
  80. procedure a_loadmm_reg_reg(list: TAsmList; fromsize, tosize : tcgsize;reg1, reg2: tregister;shuffle : pmmshuffle); override;
  81. procedure a_loadmm_ref_reg(list: TAsmList; fromsize, tosize : tcgsize;const ref: treference; reg: tregister;shuffle : pmmshuffle); override;
  82. procedure a_loadmm_reg_ref(list: TAsmList; fromsize, tosize : tcgsize;reg: tregister; const ref: treference;shuffle : pmmshuffle); override;
  83. procedure a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize : tcgsize;intreg, mmreg: tregister; shuffle: pmmshuffle); override;
  84. procedure a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize : tcgsize;mmreg, intreg: tregister; shuffle : pmmshuffle); override;
  85. procedure a_opmm_reg_reg(list: TAsmList; Op: TOpCG; size : tcgsize;src,dst: tregister;shuffle : pmmshuffle); override;
  86. { Transform unsupported methods into Internal errors }
  87. procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister); override;
  88. private
  89. { clear out potential overflow bits from 8 or 16 bit operations }
  90. { the upper 24/16 bits of a register after an operation }
  91. procedure maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  92. function get_darwin_call_stub(const s: string; weak: boolean): tasmsymbol;
  93. end;
  94. tarmcgarm = class(tcgarm)
  95. procedure init_register_allocators;override;
  96. procedure done_register_allocators;override;
  97. procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);override;
  98. procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  99. end;
  100. tcg64farm = class(tcg64f32)
  101. procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  102. procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
  103. procedure a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);override;
  104. procedure a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);override;
  105. procedure a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
  106. procedure a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
  107. procedure a_loadmm_intreg64_reg(list: TAsmList; mmsize: tcgsize; intreg: tregister64; mmreg: tregister);override;
  108. procedure a_loadmm_reg_intreg64(list: TAsmList; mmsize: tcgsize; mmreg: tregister; intreg: tregister64);override;
  109. end;
  110. Tthumb2cgarm = class(tcgarm)
  111. procedure init_register_allocators;override;
  112. procedure done_register_allocators;override;
  113. procedure a_call_reg(list : TAsmList;reg: tregister);override;
  114. procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);override;
  115. procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  116. procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  117. procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  118. procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  119. procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
  120. procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
  121. function handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference; override;
  122. end;
  123. tthumb2cg64farm = class(tcg64farm)
  124. procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  125. end;
  126. const
  127. OpCmp2AsmCond : Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_GT,
  128. C_LT,C_GE,C_LE,C_NE,C_LS,C_CC,C_CS,C_HI);
  129. winstackpagesize = 4096;
  130. function get_fpu_postfix(def : tdef) : toppostfix;
  131. procedure create_codegen;
  132. implementation
  133. uses
  134. globals,verbose,systems,cutils,
  135. aopt,aoptcpu,
  136. fmodule,
  137. symconst,symsym,
  138. tgobj,
  139. procinfo,cpupi,
  140. paramgr;
  141. function get_fpu_postfix(def : tdef) : toppostfix;
  142. begin
  143. if def.typ=floatdef then
  144. begin
  145. case tfloatdef(def).floattype of
  146. s32real:
  147. result:=PF_S;
  148. s64real:
  149. result:=PF_D;
  150. s80real:
  151. result:=PF_E;
  152. else
  153. internalerror(200401272);
  154. end;
  155. end
  156. else
  157. internalerror(200401271);
  158. end;
  159. procedure tarmcgarm.init_register_allocators;
  160. begin
  161. inherited init_register_allocators;
  162. { currently, we always save R14, so we can use it }
  163. if (target_info.system<>system_arm_darwin) then
  164. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
  165. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R12,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  166. RS_R9,RS_R10,RS_R14],first_int_imreg,[])
  167. else
  168. { r7 is not available on Darwin, it's used as frame pointer (always,
  169. for backtrace support -- also in gcc/clang -> R11 can be used).
  170. r9 is volatile }
  171. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
  172. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R9,RS_R12,RS_R4,RS_R5,RS_R6,RS_R8,
  173. RS_R10,RS_R11,RS_R14],first_int_imreg,[]);
  174. rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
  175. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7],first_fpu_imreg,[]);
  176. { The register allocator currently cannot deal with multiple
  177. non-overlapping subregs per register, so we can only use
  178. half the single precision registers for now (as sub registers of the
  179. double precision ones). }
  180. if current_settings.fputype=fpu_vfpv3 then
  181. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBFD,
  182. [RS_D0,RS_D1,RS_D2,RS_D3,RS_D4,RS_D5,RS_D6,RS_D7,
  183. RS_D16,RS_D17,RS_D18,RS_D19,RS_D20,RS_D21,RS_D22,RS_D23,RS_D24,RS_D25,RS_D26,RS_D27,RS_D28,RS_D29,RS_D30,RS_D31,
  184. RS_D8,RS_D9,RS_D10,RS_D11,RS_D12,RS_D13,RS_D14,RS_D15
  185. ],first_mm_imreg,[])
  186. else
  187. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBFD,
  188. [RS_D0,RS_D1,RS_D2,RS_D3,RS_D4,RS_D5,RS_D6,RS_D7,RS_D8,RS_D9,RS_D10,RS_D11,RS_D12,RS_D13,RS_D14,RS_D15],first_mm_imreg,[]);
  189. end;
  190. procedure tarmcgarm.done_register_allocators;
  191. begin
  192. rg[R_INTREGISTER].free;
  193. rg[R_FPUREGISTER].free;
  194. rg[R_MMREGISTER].free;
  195. inherited done_register_allocators;
  196. end;
  197. procedure tarmcgarm.a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);
  198. var
  199. imm_shift : byte;
  200. l : tasmlabel;
  201. hr : treference;
  202. begin
  203. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  204. internalerror(2002090902);
  205. if is_shifter_const(a,imm_shift) then
  206. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  207. else if is_shifter_const(not(a),imm_shift) then
  208. list.concat(taicpu.op_reg_const(A_MVN,reg,not(a)))
  209. { loading of constants with mov and orr }
  210. else if (is_shifter_const(a-byte(a),imm_shift)) then
  211. begin
  212. list.concat(taicpu.op_reg_const(A_MOV,reg,a-byte(a)));
  213. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,byte(a)));
  214. end
  215. else if (is_shifter_const(a-word(a),imm_shift)) and (is_shifter_const(word(a),imm_shift)) then
  216. begin
  217. list.concat(taicpu.op_reg_const(A_MOV,reg,a-word(a)));
  218. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,word(a)));
  219. end
  220. else if (is_shifter_const(a-(dword(a) shl 8) shr 8,imm_shift)) and (is_shifter_const((dword(a) shl 8) shr 8,imm_shift)) then
  221. begin
  222. list.concat(taicpu.op_reg_const(A_MOV,reg,a-(dword(a) shl 8) shr 8));
  223. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,(dword(a) shl 8) shr 8));
  224. end
  225. else
  226. begin
  227. reference_reset(hr,4);
  228. current_asmdata.getjumplabel(l);
  229. cg.a_label(current_procinfo.aktlocaldata,l);
  230. hr.symboldata:=current_procinfo.aktlocaldata.last;
  231. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
  232. hr.symbol:=l;
  233. hr.base:=NR_PC;
  234. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  235. end;
  236. end;
  237. procedure tarmcgarm.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  238. var
  239. oppostfix:toppostfix;
  240. usedtmpref: treference;
  241. tmpreg,tmpreg2 : tregister;
  242. so : tshifterop;
  243. dir : integer;
  244. begin
  245. if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then
  246. FromSize := ToSize;
  247. case FromSize of
  248. { signed integer registers }
  249. OS_8:
  250. oppostfix:=PF_B;
  251. OS_S8:
  252. oppostfix:=PF_SB;
  253. OS_16:
  254. oppostfix:=PF_H;
  255. OS_S16:
  256. oppostfix:=PF_SH;
  257. OS_32,
  258. OS_S32:
  259. oppostfix:=PF_None;
  260. else
  261. InternalError(200308297);
  262. end;
  263. if (ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[fromsize]) then
  264. begin
  265. if target_info.endian=endian_big then
  266. dir:=-1
  267. else
  268. dir:=1;
  269. case FromSize of
  270. OS_16,OS_S16:
  271. begin
  272. { only complicated references need an extra loadaddr }
  273. if assigned(ref.symbol) or
  274. (ref.index<>NR_NO) or
  275. (ref.offset<-4095) or
  276. (ref.offset>4094) or
  277. { sometimes the compiler reused registers }
  278. (reg=ref.index) or
  279. (reg=ref.base) then
  280. begin
  281. tmpreg2:=getintregister(list,OS_INT);
  282. a_loadaddr_ref_reg(list,ref,tmpreg2);
  283. reference_reset_base(usedtmpref,tmpreg2,0,ref.alignment);
  284. end
  285. else
  286. usedtmpref:=ref;
  287. if target_info.endian=endian_big then
  288. inc(usedtmpref.offset,1);
  289. shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8;
  290. tmpreg:=getintregister(list,OS_INT);
  291. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  292. inc(usedtmpref.offset,dir);
  293. if FromSize=OS_16 then
  294. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg)
  295. else
  296. a_internal_load_ref_reg(list,OS_S8,OS_S8,usedtmpref,tmpreg);
  297. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  298. end;
  299. OS_32,OS_S32:
  300. begin
  301. tmpreg:=getintregister(list,OS_INT);
  302. { only complicated references need an extra loadaddr }
  303. if assigned(ref.symbol) or
  304. (ref.index<>NR_NO) or
  305. (ref.offset<-4095) or
  306. (ref.offset>4092) or
  307. { sometimes the compiler reused registers }
  308. (reg=ref.index) or
  309. (reg=ref.base) then
  310. begin
  311. tmpreg2:=getintregister(list,OS_INT);
  312. a_loadaddr_ref_reg(list,ref,tmpreg2);
  313. reference_reset_base(usedtmpref,tmpreg2,0,ref.alignment);
  314. end
  315. else
  316. usedtmpref:=ref;
  317. shifterop_reset(so);so.shiftmode:=SM_LSL;
  318. if ref.alignment=2 then
  319. begin
  320. if target_info.endian=endian_big then
  321. inc(usedtmpref.offset,2);
  322. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,reg);
  323. inc(usedtmpref.offset,dir*2);
  324. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,tmpreg);
  325. so.shiftimm:=16;
  326. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  327. end
  328. else
  329. begin
  330. if target_info.endian=endian_big then
  331. inc(usedtmpref.offset,3);
  332. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  333. inc(usedtmpref.offset,dir);
  334. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  335. so.shiftimm:=8;
  336. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  337. inc(usedtmpref.offset,dir);
  338. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  339. so.shiftimm:=16;
  340. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  341. inc(usedtmpref.offset,dir);
  342. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  343. so.shiftimm:=24;
  344. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  345. end;
  346. end
  347. else
  348. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  349. end;
  350. end
  351. else
  352. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  353. if (fromsize=OS_S8) and (tosize = OS_16) then
  354. a_load_reg_reg(list,OS_16,OS_32,reg,reg);
  355. end;
  356. procedure tcgarm.a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const paraloc : TCGPara);
  357. var
  358. ref: treference;
  359. begin
  360. paraloc.check_simple_location;
  361. paramanager.allocparaloc(list,paraloc.location);
  362. case paraloc.location^.loc of
  363. LOC_REGISTER,LOC_CREGISTER:
  364. a_load_const_reg(list,size,a,paraloc.location^.register);
  365. LOC_REFERENCE:
  366. begin
  367. reference_reset(ref,paraloc.alignment);
  368. ref.base:=paraloc.location^.reference.index;
  369. ref.offset:=paraloc.location^.reference.offset;
  370. a_load_const_ref(list,size,a,ref);
  371. end;
  372. else
  373. internalerror(2002081101);
  374. end;
  375. end;
  376. procedure tcgarm.a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);
  377. var
  378. tmpref, ref: treference;
  379. location: pcgparalocation;
  380. sizeleft: aint;
  381. begin
  382. location := paraloc.location;
  383. tmpref := r;
  384. sizeleft := paraloc.intsize;
  385. while assigned(location) do
  386. begin
  387. paramanager.allocparaloc(list,location);
  388. case location^.loc of
  389. LOC_REGISTER,LOC_CREGISTER:
  390. a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
  391. LOC_REFERENCE:
  392. begin
  393. reference_reset_base(ref,location^.reference.index,location^.reference.offset,paraloc.alignment);
  394. { doubles in softemu mode have a strange order of registers and references }
  395. if location^.size=OS_32 then
  396. g_concatcopy(list,tmpref,ref,4)
  397. else
  398. begin
  399. g_concatcopy(list,tmpref,ref,sizeleft);
  400. if assigned(location^.next) then
  401. internalerror(2005010710);
  402. end;
  403. end;
  404. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  405. case location^.size of
  406. OS_F32, OS_F64:
  407. a_loadfpu_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
  408. else
  409. internalerror(2002072801);
  410. end;
  411. LOC_VOID:
  412. begin
  413. // nothing to do
  414. end;
  415. else
  416. internalerror(2002081103);
  417. end;
  418. inc(tmpref.offset,tcgsize2size[location^.size]);
  419. dec(sizeleft,tcgsize2size[location^.size]);
  420. location := location^.next;
  421. end;
  422. end;
  423. procedure tcgarm.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara);
  424. var
  425. ref: treference;
  426. tmpreg: tregister;
  427. begin
  428. paraloc.check_simple_location;
  429. paramanager.allocparaloc(list,paraloc.location);
  430. case paraloc.location^.loc of
  431. LOC_REGISTER,LOC_CREGISTER:
  432. a_loadaddr_ref_reg(list,r,paraloc.location^.register);
  433. LOC_REFERENCE:
  434. begin
  435. reference_reset(ref,paraloc.alignment);
  436. ref.base := paraloc.location^.reference.index;
  437. ref.offset := paraloc.location^.reference.offset;
  438. tmpreg := getintregister(list,OS_ADDR);
  439. a_loadaddr_ref_reg(list,r,tmpreg);
  440. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  441. end;
  442. else
  443. internalerror(2002080701);
  444. end;
  445. end;
  446. procedure tcgarm.a_call_name(list : TAsmList;const s : string; weak: boolean);
  447. var
  448. branchopcode: tasmop;
  449. begin
  450. { check not really correct: should only be used for non-Thumb cpus }
  451. if (current_settings.cputype<cpu_armv5) or
  452. (current_settings.cputype in cpu_thumb2) then
  453. branchopcode:=A_BL
  454. else
  455. branchopcode:=A_BLX;
  456. if target_info.system<>system_arm_darwin then
  457. if not weak then
  458. list.concat(taicpu.op_sym(branchopcode,current_asmdata.RefAsmSymbol(s)))
  459. else
  460. list.concat(taicpu.op_sym(branchopcode,current_asmdata.WeakRefAsmSymbol(s)))
  461. else
  462. list.concat(taicpu.op_sym(branchopcode,get_darwin_call_stub(s,weak)));
  463. {
  464. the compiler does not properly set this flag anymore in pass 1, and
  465. for now we only need it after pass 2 (I hope) (JM)
  466. if not(pi_do_call in current_procinfo.flags) then
  467. internalerror(2003060703);
  468. }
  469. include(current_procinfo.flags,pi_do_call);
  470. end;
  471. procedure tcgarm.a_call_reg(list : TAsmList;reg: tregister);
  472. begin
  473. { check not really correct: should only be used for non-Thumb cpus }
  474. if (current_settings.cputype<cpu_armv5) then
  475. begin
  476. list.concat(taicpu.op_reg_reg(A_MOV,NR_R14,NR_PC));
  477. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,reg));
  478. end
  479. else
  480. list.concat(taicpu.op_reg(A_BLX, reg));
  481. {
  482. the compiler does not properly set this flag anymore in pass 1, and
  483. for now we only need it after pass 2 (I hope) (JM)
  484. if not(pi_do_call in current_procinfo.flags) then
  485. internalerror(2003060703);
  486. }
  487. include(current_procinfo.flags,pi_do_call);
  488. end;
  489. procedure tcgarm.a_call_ref(list : TAsmList;ref: treference);
  490. begin
  491. a_reg_alloc(list,NR_R12);
  492. a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,NR_R12);
  493. a_call_reg(list,NR_R12);
  494. a_reg_dealloc(list,NR_R12);
  495. include(current_procinfo.flags,pi_do_call);
  496. end;
  497. procedure tcgarm.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister);
  498. begin
  499. a_op_const_reg_reg(list,op,size,a,reg,reg);
  500. end;
  501. procedure tcgarm.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  502. begin
  503. case op of
  504. OP_NEG:
  505. list.concat(taicpu.op_reg_reg_const(A_RSB,dst,src,0));
  506. OP_NOT:
  507. begin
  508. list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
  509. case size of
  510. OS_8 :
  511. a_op_const_reg_reg(list,OP_AND,OS_INT,$ff,dst,dst);
  512. OS_16 :
  513. a_op_const_reg_reg(list,OP_AND,OS_INT,$ffff,dst,dst);
  514. end;
  515. end
  516. else
  517. a_op_reg_reg_reg(list,op,OS_32,src,dst,dst);
  518. end;
  519. end;
  520. const
  521. op_reg_reg_opcg2asmop: array[TOpCG] of tasmop =
  522. (A_NONE,A_MOV,A_ADD,A_AND,A_NONE,A_NONE,A_MUL,A_MUL,A_NONE,A_NONE,A_ORR,
  523. A_NONE,A_NONE,A_NONE,A_SUB,A_EOR,A_NONE,A_NONE);
  524. procedure tcgarm.a_op_const_reg_reg(list: TAsmList; op: TOpCg;
  525. size: tcgsize; a: tcgint; src, dst: tregister);
  526. var
  527. ovloc : tlocation;
  528. begin
  529. a_op_const_reg_reg_checkoverflow(list,op,size,a,src,dst,false,ovloc);
  530. end;
  531. procedure tcgarm.a_op_reg_reg_reg(list: TAsmList; op: TOpCg;
  532. size: tcgsize; src1, src2, dst: tregister);
  533. var
  534. ovloc : tlocation;
  535. begin
  536. a_op_reg_reg_reg_checkoverflow(list,op,size,src1,src2,dst,false,ovloc);
  537. end;
  538. procedure tcgarm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);
  539. var
  540. shift : byte;
  541. tmpreg : tregister;
  542. so : tshifterop;
  543. l1 : longint;
  544. begin
  545. ovloc.loc:=LOC_VOID;
  546. if {$ifopt R+}(a<>-2147483648) and{$endif} is_shifter_const(-a,shift) then
  547. case op of
  548. OP_ADD:
  549. begin
  550. op:=OP_SUB;
  551. a:=aint(dword(-a));
  552. end;
  553. OP_SUB:
  554. begin
  555. op:=OP_ADD;
  556. a:=aint(dword(-a));
  557. end
  558. end;
  559. if is_shifter_const(a,shift) and not(op in [OP_IMUL,OP_MUL]) then
  560. case op of
  561. OP_NEG,OP_NOT:
  562. internalerror(200308281);
  563. OP_SHL:
  564. begin
  565. if a>32 then
  566. internalerror(200308294);
  567. if a<>0 then
  568. begin
  569. shifterop_reset(so);
  570. so.shiftmode:=SM_LSL;
  571. so.shiftimm:=a;
  572. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  573. end
  574. else
  575. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  576. end;
  577. OP_ROL:
  578. begin
  579. if a>32 then
  580. internalerror(200308294);
  581. if a<>0 then
  582. begin
  583. shifterop_reset(so);
  584. so.shiftmode:=SM_ROR;
  585. so.shiftimm:=32-a;
  586. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  587. end
  588. else
  589. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  590. end;
  591. OP_ROR:
  592. begin
  593. if a>32 then
  594. internalerror(200308294);
  595. if a<>0 then
  596. begin
  597. shifterop_reset(so);
  598. so.shiftmode:=SM_ROR;
  599. so.shiftimm:=a;
  600. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  601. end
  602. else
  603. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  604. end;
  605. OP_SHR:
  606. begin
  607. if a>32 then
  608. internalerror(200308292);
  609. shifterop_reset(so);
  610. if a<>0 then
  611. begin
  612. so.shiftmode:=SM_LSR;
  613. so.shiftimm:=a;
  614. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  615. end
  616. else
  617. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  618. end;
  619. OP_SAR:
  620. begin
  621. if a>32 then
  622. internalerror(200308295);
  623. if a<>0 then
  624. begin
  625. shifterop_reset(so);
  626. so.shiftmode:=SM_ASR;
  627. so.shiftimm:=a;
  628. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  629. end
  630. else
  631. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  632. end;
  633. else
  634. {if (op in [OP_SUB, OP_ADD]) and
  635. ((a < 0) or
  636. (a > 4095)) then
  637. begin
  638. tmpreg:=getintregister(list,size);
  639. list.concat(taicpu.op_reg_const(A_MOVT, tmpreg, (a shr 16) and $FFFF));
  640. list.concat(taicpu.op_reg_const(A_MOV, tmpreg, a and $FFFF));
  641. list.concat(setoppostfix(taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src,tmpreg),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  642. ));
  643. end
  644. else}
  645. list.concat(setoppostfix(
  646. taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  647. ));
  648. if (cgsetflags or setflags) and (size in [OS_8,OS_16,OS_32]) then
  649. begin
  650. ovloc.loc:=LOC_FLAGS;
  651. case op of
  652. OP_ADD:
  653. ovloc.resflags:=F_CS;
  654. OP_SUB:
  655. ovloc.resflags:=F_CC;
  656. end;
  657. end;
  658. end
  659. else
  660. begin
  661. { there could be added some more sophisticated optimizations }
  662. if (op in [OP_MUL,OP_IMUL,OP_DIV,OP_IDIV]) and (a=1) then
  663. a_load_reg_reg(list,size,size,src,dst)
  664. else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
  665. a_load_const_reg(list,size,0,dst)
  666. else if (op in [OP_IMUL,OP_IDIV]) and (a=-1) then
  667. a_op_reg_reg(list,OP_NEG,size,src,dst)
  668. { we do this here instead in the peephole optimizer because
  669. it saves us a register }
  670. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) and not(cgsetflags or setflags) then
  671. a_op_const_reg_reg(list,OP_SHL,size,l1,src,dst)
  672. { for example : b=a*5 -> b=a*4+a with add instruction and shl }
  673. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a-1,l1) and not(cgsetflags or setflags) then
  674. begin
  675. if l1>32 then{roozbeh does this ever happen?}
  676. internalerror(200308296);
  677. shifterop_reset(so);
  678. so.shiftmode:=SM_LSL;
  679. so.shiftimm:=l1;
  680. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,dst,src,src,so));
  681. end
  682. { for example : b=a*7 -> b=a*8-a with rsb instruction and shl }
  683. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a+1,l1) and not(cgsetflags or setflags) then
  684. begin
  685. if l1>32 then{does this ever happen?}
  686. internalerror(201205181);
  687. shifterop_reset(so);
  688. so.shiftmode:=SM_LSL;
  689. so.shiftimm:=l1;
  690. list.concat(taicpu.op_reg_reg_reg_shifterop(A_RSB,dst,src,src,so));
  691. end
  692. else
  693. begin
  694. tmpreg:=getintregister(list,size);
  695. a_load_const_reg(list,size,a,tmpreg);
  696. a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,setflags,ovloc);
  697. end;
  698. end;
  699. maybeadjustresult(list,op,size,dst);
  700. end;
  701. procedure tcgarm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);
  702. var
  703. so : tshifterop;
  704. tmpreg,overflowreg : tregister;
  705. asmop : tasmop;
  706. begin
  707. ovloc.loc:=LOC_VOID;
  708. case op of
  709. OP_NEG,OP_NOT,
  710. OP_DIV,OP_IDIV:
  711. internalerror(200308281);
  712. OP_SHL:
  713. begin
  714. shifterop_reset(so);
  715. so.rs:=src1;
  716. so.shiftmode:=SM_LSL;
  717. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  718. end;
  719. OP_SHR:
  720. begin
  721. shifterop_reset(so);
  722. so.rs:=src1;
  723. so.shiftmode:=SM_LSR;
  724. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  725. end;
  726. OP_SAR:
  727. begin
  728. shifterop_reset(so);
  729. so.rs:=src1;
  730. so.shiftmode:=SM_ASR;
  731. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  732. end;
  733. OP_ROL:
  734. begin
  735. if not(size in [OS_32,OS_S32]) then
  736. internalerror(2008072801);
  737. { simulate ROL by ror'ing 32-value }
  738. tmpreg:=getintregister(list,OS_32);
  739. list.concat(taicpu.op_reg_const(A_MOV,tmpreg,32));
  740. list.concat(taicpu.op_reg_reg_reg(A_SUB,src1,tmpreg,src1));
  741. shifterop_reset(so);
  742. so.rs:=src1;
  743. so.shiftmode:=SM_ROR;
  744. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  745. end;
  746. OP_ROR:
  747. begin
  748. if not(size in [OS_32,OS_S32]) then
  749. internalerror(2008072802);
  750. shifterop_reset(so);
  751. so.rs:=src1;
  752. so.shiftmode:=SM_ROR;
  753. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  754. end;
  755. OP_IMUL,
  756. OP_MUL:
  757. begin
  758. if cgsetflags or setflags then
  759. begin
  760. overflowreg:=getintregister(list,size);
  761. if op=OP_IMUL then
  762. asmop:=A_SMULL
  763. else
  764. asmop:=A_UMULL;
  765. { the arm doesn't allow that rd and rm are the same }
  766. if dst=src2 then
  767. begin
  768. if dst<>src1 then
  769. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src1,src2))
  770. else
  771. begin
  772. tmpreg:=getintregister(list,size);
  773. a_load_reg_reg(list,size,size,src2,dst);
  774. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,tmpreg,src1));
  775. end;
  776. end
  777. else
  778. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src2,src1));
  779. if op=OP_IMUL then
  780. begin
  781. shifterop_reset(so);
  782. so.shiftmode:=SM_ASR;
  783. so.shiftimm:=31;
  784. list.concat(taicpu.op_reg_reg_shifterop(A_CMP,overflowreg,dst,so));
  785. end
  786. else
  787. list.concat(taicpu.op_reg_const(A_CMP,overflowreg,0));
  788. ovloc.loc:=LOC_FLAGS;
  789. ovloc.resflags:=F_NE;
  790. end
  791. else
  792. begin
  793. { the arm doesn't allow that rd and rm are the same }
  794. if dst=src2 then
  795. begin
  796. if dst<>src1 then
  797. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
  798. else
  799. begin
  800. tmpreg:=getintregister(list,size);
  801. a_load_reg_reg(list,size,size,src2,dst);
  802. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,tmpreg,src1));
  803. end;
  804. end
  805. else
  806. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
  807. end;
  808. end;
  809. else
  810. list.concat(setoppostfix(
  811. taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  812. ));
  813. end;
  814. maybeadjustresult(list,op,size,dst);
  815. end;
  816. function tcgarm.handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference;
  817. var
  818. tmpreg : tregister;
  819. tmpref : treference;
  820. l : tasmlabel;
  821. begin
  822. tmpreg:=NR_NO;
  823. { Be sure to have a base register }
  824. if (ref.base=NR_NO) then
  825. begin
  826. if ref.shiftmode<>SM_None then
  827. internalerror(200308294);
  828. ref.base:=ref.index;
  829. ref.index:=NR_NO;
  830. end;
  831. { absolute symbols can't be handled directly, we've to store the symbol reference
  832. in the text segment and access it pc relative
  833. For now, we assume that references where base or index equals to PC are already
  834. relative, all other references are assumed to be absolute and thus they need
  835. to be handled extra.
  836. A proper solution would be to change refoptions to a set and store the information
  837. if the symbol is absolute or relative there.
  838. }
  839. if (assigned(ref.symbol) and
  840. not(is_pc(ref.base)) and
  841. not(is_pc(ref.index))
  842. ) or
  843. { [#xxx] isn't a valid address operand }
  844. ((ref.base=NR_NO) and (ref.index=NR_NO)) or
  845. (ref.offset<-4095) or
  846. (ref.offset>4095) or
  847. ((oppostfix in [PF_SB,PF_H,PF_SH]) and
  848. ((ref.offset<-255) or
  849. (ref.offset>255)
  850. )
  851. ) or
  852. ((op in [A_LDF,A_STF,A_FLDS,A_FLDD,A_FSTS,A_FSTD]) and
  853. ((ref.offset<-1020) or
  854. (ref.offset>1020) or
  855. ((abs(ref.offset) mod 4)<>0) or
  856. { the usual pc relative symbol handling assumes possible offsets of +/- 4095 }
  857. assigned(ref.symbol)
  858. )
  859. ) then
  860. begin
  861. reference_reset(tmpref,4);
  862. { load symbol }
  863. tmpreg:=getintregister(list,OS_INT);
  864. if assigned(ref.symbol) then
  865. begin
  866. current_asmdata.getjumplabel(l);
  867. cg.a_label(current_procinfo.aktlocaldata,l);
  868. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  869. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset));
  870. { load consts entry }
  871. tmpref.symbol:=l;
  872. tmpref.base:=NR_R15;
  873. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  874. { in case of LDF/STF, we got rid of the NR_R15 }
  875. if is_pc(ref.base) then
  876. ref.base:=NR_NO;
  877. if is_pc(ref.index) then
  878. ref.index:=NR_NO;
  879. end
  880. else
  881. a_load_const_reg(list,OS_ADDR,ref.offset,tmpreg);
  882. if (ref.base<>NR_NO) then
  883. begin
  884. if ref.index<>NR_NO then
  885. begin
  886. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  887. ref.base:=tmpreg;
  888. end
  889. else
  890. begin
  891. ref.index:=tmpreg;
  892. ref.shiftimm:=0;
  893. ref.signindex:=1;
  894. ref.shiftmode:=SM_None;
  895. end;
  896. end
  897. else
  898. ref.base:=tmpreg;
  899. ref.offset:=0;
  900. ref.symbol:=nil;
  901. end;
  902. if (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then
  903. begin
  904. if tmpreg<>NR_NO then
  905. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg,tmpreg)
  906. else
  907. begin
  908. tmpreg:=getintregister(list,OS_ADDR);
  909. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg);
  910. ref.base:=tmpreg;
  911. end;
  912. ref.offset:=0;
  913. end;
  914. { floating point operations have only limited references
  915. we expect here, that a base is already set }
  916. if (op in [A_LDF,A_STF,A_FLDS,A_FLDD,A_FSTS,A_FSTD]) and (ref.index<>NR_NO) then
  917. begin
  918. if ref.shiftmode<>SM_none then
  919. internalerror(200309121);
  920. if tmpreg<>NR_NO then
  921. begin
  922. if ref.base=tmpreg then
  923. begin
  924. if ref.signindex<0 then
  925. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,tmpreg,ref.index))
  926. else
  927. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg,ref.index));
  928. ref.index:=NR_NO;
  929. end
  930. else
  931. begin
  932. if ref.index<>tmpreg then
  933. internalerror(200403161);
  934. if ref.signindex<0 then
  935. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,ref.base,tmpreg))
  936. else
  937. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  938. ref.base:=tmpreg;
  939. ref.index:=NR_NO;
  940. end;
  941. end
  942. else
  943. begin
  944. tmpreg:=getintregister(list,OS_ADDR);
  945. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
  946. ref.base:=tmpreg;
  947. ref.index:=NR_NO;
  948. end;
  949. end;
  950. list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
  951. Result := ref;
  952. end;
  953. procedure tcgarm.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  954. var
  955. oppostfix:toppostfix;
  956. usedtmpref: treference;
  957. tmpreg : tregister;
  958. so : tshifterop;
  959. dir : integer;
  960. begin
  961. if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then
  962. FromSize := ToSize;
  963. case ToSize of
  964. { signed integer registers }
  965. OS_8,
  966. OS_S8:
  967. oppostfix:=PF_B;
  968. OS_16,
  969. OS_S16:
  970. oppostfix:=PF_H;
  971. OS_32,
  972. OS_S32,
  973. { for vfp value stored in integer register }
  974. OS_F32:
  975. oppostfix:=PF_None;
  976. else
  977. InternalError(200308295);
  978. end;
  979. if (ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[tosize]) then
  980. begin
  981. if target_info.endian=endian_big then
  982. dir:=-1
  983. else
  984. dir:=1;
  985. case FromSize of
  986. OS_16,OS_S16:
  987. begin
  988. shifterop_reset(so);so.shiftmode:=SM_LSR;so.shiftimm:=8;
  989. tmpreg:=getintregister(list,OS_INT);
  990. usedtmpref:=ref;
  991. if target_info.endian=endian_big then
  992. inc(usedtmpref.offset,1);
  993. usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,usedtmpref);
  994. inc(usedtmpref.offset,dir);
  995. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
  996. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  997. end;
  998. OS_32,OS_S32:
  999. begin
  1000. tmpreg:=getintregister(list,OS_INT);
  1001. usedtmpref:=ref;
  1002. shifterop_reset(so);so.shiftmode:=SM_LSR;
  1003. if ref.alignment=2 then
  1004. begin
  1005. so.shiftimm:=16;
  1006. if target_info.endian=endian_big then
  1007. inc(usedtmpref.offset,2);
  1008. usedtmpref:=a_internal_load_reg_ref(list,OS_16,OS_16,reg,usedtmpref);
  1009. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
  1010. inc(usedtmpref.offset,dir*2);
  1011. a_internal_load_reg_ref(list,OS_16,OS_16,tmpreg,usedtmpref);
  1012. end
  1013. else
  1014. begin
  1015. so.shiftimm:=8;
  1016. if target_info.endian=endian_big then
  1017. inc(usedtmpref.offset,3);
  1018. usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,usedtmpref);
  1019. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
  1020. inc(usedtmpref.offset,dir);
  1021. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  1022. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
  1023. inc(usedtmpref.offset,dir);
  1024. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  1025. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
  1026. inc(usedtmpref.offset,dir);
  1027. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  1028. end;
  1029. end
  1030. else
  1031. handle_load_store(list,A_STR,oppostfix,reg,ref);
  1032. end;
  1033. end
  1034. else
  1035. handle_load_store(list,A_STR,oppostfix,reg,ref);
  1036. end;
  1037. function tcgarm.a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference;
  1038. var
  1039. oppostfix:toppostfix;
  1040. begin
  1041. case ToSize of
  1042. { signed integer registers }
  1043. OS_8,
  1044. OS_S8:
  1045. oppostfix:=PF_B;
  1046. OS_16,
  1047. OS_S16:
  1048. oppostfix:=PF_H;
  1049. OS_32,
  1050. OS_S32:
  1051. oppostfix:=PF_None;
  1052. else
  1053. InternalError(2003082910);
  1054. end;
  1055. result:=handle_load_store(list,A_STR,oppostfix,reg,ref);
  1056. end;
  1057. function tcgarm.a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference;
  1058. var
  1059. oppostfix:toppostfix;
  1060. begin
  1061. case FromSize of
  1062. { signed integer registers }
  1063. OS_8:
  1064. oppostfix:=PF_B;
  1065. OS_S8:
  1066. oppostfix:=PF_SB;
  1067. OS_16:
  1068. oppostfix:=PF_H;
  1069. OS_S16:
  1070. oppostfix:=PF_SH;
  1071. OS_32,
  1072. OS_S32:
  1073. oppostfix:=PF_None;
  1074. else
  1075. InternalError(200308291);
  1076. end;
  1077. result:=handle_load_store(list,A_LDR,oppostfix,reg,ref);
  1078. end;
  1079. procedure tcgarm.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  1080. var
  1081. so : tshifterop;
  1082. procedure do_shift(shiftmode : tshiftmode; shiftimm : byte; reg : tregister);
  1083. begin
  1084. so.shiftmode:=shiftmode;
  1085. so.shiftimm:=shiftimm;
  1086. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg,so));
  1087. end;
  1088. var
  1089. instr: taicpu;
  1090. conv_done: boolean;
  1091. begin
  1092. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1093. internalerror(2002090901);
  1094. conv_done:=false;
  1095. if tosize<>fromsize then
  1096. begin
  1097. shifterop_reset(so);
  1098. conv_done:=true;
  1099. if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  1100. fromsize:=tosize;
  1101. case fromsize of
  1102. OS_8:
  1103. list.concat(taicpu.op_reg_reg_const(A_AND,reg2,reg1,$ff));
  1104. OS_S8:
  1105. begin
  1106. do_shift(SM_LSL,24,reg1);
  1107. if tosize=OS_16 then
  1108. begin
  1109. do_shift(SM_ASR,8,reg2);
  1110. do_shift(SM_LSR,16,reg2);
  1111. end
  1112. else
  1113. do_shift(SM_ASR,24,reg2);
  1114. end;
  1115. OS_16:
  1116. begin
  1117. do_shift(SM_LSL,16,reg1);
  1118. do_shift(SM_LSR,16,reg2);
  1119. end;
  1120. OS_S16:
  1121. begin
  1122. do_shift(SM_LSL,16,reg1);
  1123. do_shift(SM_ASR,16,reg2)
  1124. end;
  1125. else
  1126. conv_done:=false;
  1127. end;
  1128. end;
  1129. if not conv_done and (reg1<>reg2) then
  1130. begin
  1131. { same size, only a register mov required }
  1132. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  1133. list.Concat(instr);
  1134. { Notify the register allocator that we have written a move instruction so
  1135. it can try to eliminate it. }
  1136. add_move_instruction(instr);
  1137. end;
  1138. end;
  1139. procedure tcgarm.a_loadfpu_ref_cgpara(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);
  1140. var
  1141. href,href2 : treference;
  1142. hloc : pcgparalocation;
  1143. begin
  1144. href:=ref;
  1145. hloc:=paraloc.location;
  1146. while assigned(hloc) do
  1147. begin
  1148. case hloc^.loc of
  1149. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  1150. begin
  1151. paramanager.allocparaloc(list,paraloc.location);
  1152. a_loadfpu_ref_reg(list,size,size,ref,hloc^.register);
  1153. end;
  1154. LOC_REGISTER :
  1155. case hloc^.size of
  1156. OS_32,
  1157. OS_F32:
  1158. begin
  1159. paramanager.allocparaloc(list,paraloc.location);
  1160. a_load_ref_reg(list,OS_32,OS_32,href,hloc^.register);
  1161. end;
  1162. OS_64,
  1163. OS_F64:
  1164. cg64.a_load64_ref_cgpara(list,href,paraloc);
  1165. else
  1166. a_load_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
  1167. end;
  1168. LOC_REFERENCE :
  1169. begin
  1170. reference_reset_base(href2,hloc^.reference.index,hloc^.reference.offset,paraloc.alignment);
  1171. { concatcopy should choose the best way to copy the data }
  1172. g_concatcopy(list,href,href2,tcgsize2size[hloc^.size]);
  1173. end;
  1174. else
  1175. internalerror(200408241);
  1176. end;
  1177. inc(href.offset,tcgsize2size[hloc^.size]);
  1178. hloc:=hloc^.next;
  1179. end;
  1180. end;
  1181. procedure tcgarm.a_loadfpu_reg_reg(list: TAsmList; fromsize,tosize: tcgsize; reg1, reg2: tregister);
  1182. begin
  1183. list.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,reg2,reg1),cgsize2fpuoppostfix[tosize]));
  1184. end;
  1185. procedure tcgarm.a_loadfpu_ref_reg(list: TAsmList; fromsize,tosize: tcgsize; const ref: treference; reg: tregister);
  1186. var
  1187. oppostfix:toppostfix;
  1188. begin
  1189. case fromsize of
  1190. OS_32,
  1191. OS_F32:
  1192. oppostfix:=PF_S;
  1193. OS_64,
  1194. OS_F64:
  1195. oppostfix:=PF_D;
  1196. OS_F80:
  1197. oppostfix:=PF_E;
  1198. else
  1199. InternalError(200309021);
  1200. end;
  1201. handle_load_store(list,A_LDF,oppostfix,reg,ref);
  1202. if fromsize<>tosize then
  1203. a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
  1204. end;
  1205. procedure tcgarm.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  1206. var
  1207. oppostfix:toppostfix;
  1208. begin
  1209. case tosize of
  1210. OS_F32:
  1211. oppostfix:=PF_S;
  1212. OS_F64:
  1213. oppostfix:=PF_D;
  1214. OS_F80:
  1215. oppostfix:=PF_E;
  1216. else
  1217. InternalError(200309022);
  1218. end;
  1219. handle_load_store(list,A_STF,oppostfix,reg,ref);
  1220. end;
  1221. { comparison operations }
  1222. procedure tcgarm.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister;
  1223. l : tasmlabel);
  1224. var
  1225. tmpreg : tregister;
  1226. b : byte;
  1227. begin
  1228. if is_shifter_const(a,b) then
  1229. list.concat(taicpu.op_reg_const(A_CMP,reg,a))
  1230. { CMN reg,0 and CMN reg,$80000000 are different from CMP reg,$ffffffff
  1231. and CMP reg,$7fffffff regarding the flags according to the ARM manual }
  1232. else if (a<>$7fffffff) and (a<>-1) and is_shifter_const(-a,b) then
  1233. list.concat(taicpu.op_reg_const(A_CMN,reg,-a))
  1234. else
  1235. begin
  1236. tmpreg:=getintregister(list,size);
  1237. a_load_const_reg(list,size,a,tmpreg);
  1238. list.concat(taicpu.op_reg_reg(A_CMP,reg,tmpreg));
  1239. end;
  1240. a_jmp_cond(list,cmp_op,l);
  1241. end;
  1242. procedure tcgarm.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister);
  1243. begin
  1244. Comment(V_Error,'tcgarm.a_bit_scan_reg_reg method not implemented');
  1245. end;
  1246. procedure tcgarm.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  1247. begin
  1248. list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1));
  1249. a_jmp_cond(list,cmp_op,l);
  1250. end;
  1251. procedure tcgarm.a_jmp_name(list : TAsmList;const s : string);
  1252. var
  1253. ai : taicpu;
  1254. begin
  1255. ai:=taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(s));
  1256. ai.is_jmp:=true;
  1257. list.concat(ai);
  1258. end;
  1259. procedure tcgarm.a_jmp_always(list : TAsmList;l: tasmlabel);
  1260. var
  1261. ai : taicpu;
  1262. begin
  1263. ai:=taicpu.op_sym(A_B,l);
  1264. ai.is_jmp:=true;
  1265. list.concat(ai);
  1266. end;
  1267. procedure tcgarm.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
  1268. var
  1269. ai : taicpu;
  1270. begin
  1271. ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
  1272. ai.is_jmp:=true;
  1273. list.concat(ai);
  1274. end;
  1275. procedure tcgarm.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  1276. begin
  1277. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
  1278. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond(flags_to_cond(f))));
  1279. end;
  1280. procedure tcgarm.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  1281. var
  1282. ref : treference;
  1283. shift : byte;
  1284. firstfloatreg,lastfloatreg,
  1285. r : byte;
  1286. mmregs,
  1287. regs, saveregs : tcpuregisterset;
  1288. r7offset,
  1289. stackmisalignment : pint;
  1290. postfix: toppostfix;
  1291. begin
  1292. LocalSize:=align(LocalSize,4);
  1293. { call instruction does not put anything on the stack }
  1294. stackmisalignment:=0;
  1295. if not(nostackframe) then
  1296. begin
  1297. firstfloatreg:=RS_NO;
  1298. mmregs:=[];
  1299. case current_settings.fputype of
  1300. fpu_fpa,
  1301. fpu_fpa10,
  1302. fpu_fpa11:
  1303. begin
  1304. { save floating point registers? }
  1305. regs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
  1306. for r:=RS_F0 to RS_F7 do
  1307. if r in regs then
  1308. begin
  1309. if firstfloatreg=RS_NO then
  1310. firstfloatreg:=r;
  1311. lastfloatreg:=r;
  1312. inc(stackmisalignment,12);
  1313. end;
  1314. end;
  1315. fpu_vfpv2,
  1316. fpu_vfpv3,
  1317. fpu_vfpv3_d16:
  1318. begin;
  1319. mmregs:=rg[R_MMREGISTER].used_in_proc-paramanager.get_volatile_registers_mm(pocall_stdcall);
  1320. end;
  1321. end;
  1322. a_reg_alloc(list,NR_STACK_POINTER_REG);
  1323. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1324. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  1325. { save int registers }
  1326. reference_reset(ref,4);
  1327. ref.index:=NR_STACK_POINTER_REG;
  1328. ref.addressmode:=AM_PREINDEXED;
  1329. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1330. if not(target_info.system in systems_darwin) then
  1331. begin
  1332. a_reg_alloc(list,NR_STACK_POINTER_REG);
  1333. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1334. begin
  1335. a_reg_alloc(list,NR_R12);
  1336. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  1337. end;
  1338. { the (old) ARM APCS requires saving both the stack pointer (to
  1339. crawl the stack) and the PC (to identify the function this
  1340. stack frame belongs to) -> also save R12 (= copy of R13 on entry)
  1341. and R15 -- still needs updating for EABI and Darwin, they don't
  1342. need that }
  1343. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1344. regs:=regs+[RS_FRAME_POINTER_REG,RS_R12,RS_R14,RS_R15]
  1345. else
  1346. if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
  1347. include(regs,RS_R14);
  1348. if regs<>[] then
  1349. begin
  1350. for r:=RS_R0 to RS_R15 do
  1351. if r in regs then
  1352. inc(stackmisalignment,4);
  1353. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,R_INTREGISTER,R_SUBWHOLE,regs),PF_FD));
  1354. end;
  1355. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1356. begin
  1357. { the framepointer now points to the saved R15, so the saved
  1358. framepointer is at R11-12 (for get_caller_frame) }
  1359. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  1360. a_reg_dealloc(list,NR_R12);
  1361. end;
  1362. end
  1363. else
  1364. begin
  1365. { always save r14 if we use r7 as the framepointer, because
  1366. the parameter offsets are hardcoded in advance and always
  1367. assume that r14 sits on the stack right behind the saved r7
  1368. }
  1369. if current_procinfo.framepointer=NR_FRAME_POINTER_REG then
  1370. include(regs,RS_FRAME_POINTER_REG);
  1371. if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
  1372. include(regs,RS_R14);
  1373. if regs<>[] then
  1374. begin
  1375. { on Darwin, you first have to save [r4-r7,lr], and then
  1376. [r8,r10,r11] and make r7 point to the previously saved
  1377. r7 so that you can perform a stack crawl based on it
  1378. ([r7] is previous stack frame, [r7+4] is return address
  1379. }
  1380. include(regs,RS_FRAME_POINTER_REG);
  1381. saveregs:=regs-[RS_R8,RS_R10,RS_R11];
  1382. r7offset:=0;
  1383. for r:=RS_R0 to RS_R15 do
  1384. if r in saveregs then
  1385. begin
  1386. inc(stackmisalignment,4);
  1387. if r<RS_FRAME_POINTER_REG then
  1388. inc(r7offset,4);
  1389. end;
  1390. { save the registers }
  1391. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,R_INTREGISTER,R_SUBWHOLE,saveregs),PF_FD));
  1392. { make r7 point to the saved r7 (regardless of whether this
  1393. frame uses the framepointer, for backtrace purposes) }
  1394. if r7offset<>0 then
  1395. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_FRAME_POINTER_REG,NR_R13,r7offset))
  1396. else
  1397. list.concat(taicpu.op_reg_reg(A_MOV,NR_R7,NR_R13));
  1398. { now save the rest (if any) }
  1399. saveregs:=regs-saveregs;
  1400. if saveregs<>[] then
  1401. begin
  1402. for r:=RS_R8 to RS_R11 do
  1403. if r in saveregs then
  1404. inc(stackmisalignment,4);
  1405. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,R_INTREGISTER,R_SUBWHOLE,saveregs),PF_FD));
  1406. end;
  1407. end;
  1408. end;
  1409. stackmisalignment:=stackmisalignment mod current_settings.alignment.localalignmax;
  1410. if (LocalSize<>0) or
  1411. ((stackmisalignment<>0) and
  1412. ((pi_do_call in current_procinfo.flags) or
  1413. (po_assembler in current_procinfo.procdef.procoptions))) then
  1414. begin
  1415. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  1416. if not(is_shifter_const(localsize,shift)) then
  1417. begin
  1418. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  1419. a_reg_alloc(list,NR_R12);
  1420. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  1421. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1422. a_reg_dealloc(list,NR_R12);
  1423. end
  1424. else
  1425. begin
  1426. a_reg_dealloc(list,NR_R12);
  1427. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  1428. end;
  1429. end;
  1430. if (mmregs<>[]) or
  1431. (firstfloatreg<>RS_NO) then
  1432. begin
  1433. reference_reset(ref,4);
  1434. if (tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023) or
  1435. (current_settings.fputype in [fpu_vfpv2,fpu_vfpv3,fpu_vfpv3_d16]) then
  1436. begin
  1437. if not is_shifter_const(tarmprocinfo(current_procinfo).floatregstart,shift) then
  1438. begin
  1439. a_reg_alloc(list,NR_R12);
  1440. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  1441. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  1442. a_reg_dealloc(list,NR_R12);
  1443. end
  1444. else
  1445. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_R12,current_procinfo.framepointer,-tarmprocinfo(current_procinfo).floatregstart));
  1446. ref.base:=NR_R12;
  1447. end
  1448. else
  1449. begin
  1450. ref.base:=current_procinfo.framepointer;
  1451. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  1452. end;
  1453. case current_settings.fputype of
  1454. fpu_fpa,
  1455. fpu_fpa10,
  1456. fpu_fpa11:
  1457. begin
  1458. list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  1459. lastfloatreg-firstfloatreg+1,ref));
  1460. end;
  1461. fpu_vfpv2,
  1462. fpu_vfpv3,
  1463. fpu_vfpv3_d16:
  1464. begin
  1465. ref.index:=ref.base;
  1466. ref.base:=NR_NO;
  1467. { FSTMX is deprecated on ARMv6 and later }
  1468. if (current_settings.cputype<cpu_armv6) then
  1469. postfix:=PF_IAX
  1470. else
  1471. postfix:=PF_IAD;
  1472. list.concat(setoppostfix(taicpu.op_ref_regset(A_FSTM,ref,R_MMREGISTER,R_SUBFD,mmregs),postfix));
  1473. end;
  1474. end;
  1475. end;
  1476. end;
  1477. end;
  1478. procedure tcgarm.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  1479. var
  1480. ref : treference;
  1481. LocalSize : longint;
  1482. firstfloatreg,lastfloatreg,
  1483. r,
  1484. shift : byte;
  1485. mmregs,
  1486. saveregs,
  1487. regs : tcpuregisterset;
  1488. stackmisalignment: pint;
  1489. mmpostfix: toppostfix;
  1490. begin
  1491. if not(nostackframe) then
  1492. begin
  1493. stackmisalignment:=0;
  1494. firstfloatreg:=RS_NO;
  1495. mmregs:=[];
  1496. case current_settings.fputype of
  1497. fpu_fpa,
  1498. fpu_fpa10,
  1499. fpu_fpa11:
  1500. begin
  1501. { restore floating point registers? }
  1502. regs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
  1503. for r:=RS_F0 to RS_F7 do
  1504. if r in regs then
  1505. begin
  1506. if firstfloatreg=RS_NO then
  1507. firstfloatreg:=r;
  1508. lastfloatreg:=r;
  1509. { floating point register space is already included in
  1510. localsize below by calc_stackframe_size
  1511. inc(stackmisalignment,12);
  1512. }
  1513. end;
  1514. end;
  1515. fpu_vfpv2,
  1516. fpu_vfpv3,
  1517. fpu_vfpv3_d16:
  1518. begin;
  1519. { restore vfp registers? }
  1520. mmregs:=rg[R_MMREGISTER].used_in_proc-paramanager.get_volatile_registers_mm(pocall_stdcall);
  1521. end;
  1522. end;
  1523. if (firstfloatreg<>RS_NO) or
  1524. (mmregs<>[]) then
  1525. begin
  1526. reference_reset(ref,4);
  1527. if (tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023) or
  1528. (current_settings.fputype in [fpu_vfpv2,fpu_vfpv3,fpu_vfpv3_d16]) then
  1529. begin
  1530. if not is_shifter_const(tarmprocinfo(current_procinfo).floatregstart,shift) then
  1531. begin
  1532. a_reg_alloc(list,NR_R12);
  1533. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  1534. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  1535. a_reg_dealloc(list,NR_R12);
  1536. end
  1537. else
  1538. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_R12,current_procinfo.framepointer,-tarmprocinfo(current_procinfo).floatregstart));
  1539. ref.base:=NR_R12;
  1540. end
  1541. else
  1542. begin
  1543. ref.base:=current_procinfo.framepointer;
  1544. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  1545. end;
  1546. case current_settings.fputype of
  1547. fpu_fpa,
  1548. fpu_fpa10,
  1549. fpu_fpa11:
  1550. begin
  1551. list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  1552. lastfloatreg-firstfloatreg+1,ref));
  1553. end;
  1554. fpu_vfpv2,
  1555. fpu_vfpv3,
  1556. fpu_vfpv3_d16:
  1557. begin
  1558. ref.index:=ref.base;
  1559. ref.base:=NR_NO;
  1560. { FLDMX is deprecated on ARMv6 and later }
  1561. if (current_settings.cputype<cpu_armv6) then
  1562. mmpostfix:=PF_IAX
  1563. else
  1564. mmpostfix:=PF_IAD;
  1565. list.concat(setoppostfix(taicpu.op_ref_regset(A_FLDM,ref,R_MMREGISTER,R_SUBFD,mmregs),mmpostfix));
  1566. end;
  1567. end;
  1568. end;
  1569. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall) ;
  1570. if (pi_do_call in current_procinfo.flags) or
  1571. (regs<>[]) or
  1572. ((target_info.system in systems_darwin) and
  1573. (current_procinfo.framepointer<>NR_STACK_POINTER_REG)) then
  1574. begin
  1575. exclude(regs,RS_R14);
  1576. include(regs,RS_R15);
  1577. if (target_info.system in systems_darwin) then
  1578. include(regs,RS_FRAME_POINTER_REG);
  1579. end;
  1580. if not(target_info.system in systems_darwin) then
  1581. begin
  1582. { restore saved stack pointer to SP (R13) and saved lr to PC (R15).
  1583. The saved PC came after that but is discarded, since we restore
  1584. the stack pointer }
  1585. if (current_procinfo.framepointer<>NR_STACK_POINTER_REG) then
  1586. regs:=regs+[RS_FRAME_POINTER_REG,RS_R13,RS_R15];
  1587. end
  1588. else
  1589. begin
  1590. { restore R8-R11 already if necessary (they've been stored
  1591. before the others) }
  1592. saveregs:=regs*[RS_R8,RS_R10,RS_R11];
  1593. if saveregs<>[] then
  1594. begin
  1595. reference_reset(ref,4);
  1596. ref.index:=NR_STACK_POINTER_REG;
  1597. ref.addressmode:=AM_PREINDEXED;
  1598. for r:=RS_R8 to RS_R11 do
  1599. if r in saveregs then
  1600. inc(stackmisalignment,4);
  1601. regs:=regs-saveregs;
  1602. end;
  1603. end;
  1604. for r:=RS_R0 to RS_R15 do
  1605. if r in regs then
  1606. inc(stackmisalignment,4);
  1607. stackmisalignment:=stackmisalignment mod current_settings.alignment.localalignmax;
  1608. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) or
  1609. (target_info.system in systems_darwin) then
  1610. begin
  1611. LocalSize:=current_procinfo.calc_stackframe_size;
  1612. if (LocalSize<>0) or
  1613. ((stackmisalignment<>0) and
  1614. ((pi_do_call in current_procinfo.flags) or
  1615. (po_assembler in current_procinfo.procdef.procoptions))) then
  1616. begin
  1617. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  1618. if not(is_shifter_const(LocalSize,shift)) then
  1619. begin
  1620. a_reg_alloc(list,NR_R12);
  1621. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  1622. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1623. a_reg_dealloc(list,NR_R12);
  1624. end
  1625. else
  1626. begin
  1627. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  1628. end;
  1629. end;
  1630. if (target_info.system in systems_darwin) and
  1631. (saveregs<>[]) then
  1632. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,R_INTREGISTER,R_SUBWHOLE,saveregs),PF_FD));
  1633. if regs=[] then
  1634. begin
  1635. if (current_settings.cputype<cpu_armv6) then
  1636. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14))
  1637. else
  1638. list.concat(taicpu.op_reg(A_BX,NR_R14))
  1639. end
  1640. else
  1641. begin
  1642. reference_reset(ref,4);
  1643. ref.index:=NR_STACK_POINTER_REG;
  1644. ref.addressmode:=AM_PREINDEXED;
  1645. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,R_INTREGISTER,R_SUBWHOLE,regs),PF_FD));
  1646. end;
  1647. end
  1648. else
  1649. begin
  1650. { restore int registers and return }
  1651. reference_reset(ref,4);
  1652. ref.index:=NR_FRAME_POINTER_REG;
  1653. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,R_INTREGISTER,R_SUBWHOLE,regs),PF_EA));
  1654. end;
  1655. end
  1656. else if (current_settings.cputype<cpu_armv6) then
  1657. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14))
  1658. else
  1659. list.concat(taicpu.op_reg(A_BX,NR_R14))
  1660. end;
  1661. procedure tcgarm.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  1662. var
  1663. b : byte;
  1664. tmpref : treference;
  1665. instr : taicpu;
  1666. begin
  1667. if ref.addressmode<>AM_OFFSET then
  1668. internalerror(200309071);
  1669. tmpref:=ref;
  1670. { Be sure to have a base register }
  1671. if (tmpref.base=NR_NO) then
  1672. begin
  1673. if tmpref.shiftmode<>SM_None then
  1674. internalerror(200308294);
  1675. if tmpref.signindex<0 then
  1676. internalerror(200312023);
  1677. tmpref.base:=tmpref.index;
  1678. tmpref.index:=NR_NO;
  1679. end;
  1680. if assigned(tmpref.symbol) or
  1681. not((is_shifter_const(tmpref.offset,b)) or
  1682. (is_shifter_const(-tmpref.offset,b))
  1683. ) then
  1684. fixref(list,tmpref);
  1685. { expect a base here if there is an index }
  1686. if (tmpref.base=NR_NO) and (tmpref.index<>NR_NO) then
  1687. internalerror(200312022);
  1688. if tmpref.index<>NR_NO then
  1689. begin
  1690. if tmpref.shiftmode<>SM_None then
  1691. internalerror(200312021);
  1692. if tmpref.signindex<0 then
  1693. a_op_reg_reg_reg(list,OP_SUB,OS_ADDR,tmpref.base,tmpref.index,r)
  1694. else
  1695. a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,tmpref.base,tmpref.index,r);
  1696. if tmpref.offset<>0 then
  1697. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,r,r);
  1698. end
  1699. else
  1700. begin
  1701. if tmpref.base=NR_NO then
  1702. a_load_const_reg(list,OS_ADDR,tmpref.offset,r)
  1703. else
  1704. if tmpref.offset<>0 then
  1705. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,tmpref.base,r)
  1706. else
  1707. begin
  1708. instr:=taicpu.op_reg_reg(A_MOV,r,tmpref.base);
  1709. list.concat(instr);
  1710. add_move_instruction(instr);
  1711. end;
  1712. end;
  1713. end;
  1714. procedure tcgarm.fixref(list : TAsmList;var ref : treference);
  1715. var
  1716. tmpreg : tregister;
  1717. tmpref : treference;
  1718. l : tasmlabel;
  1719. begin
  1720. { absolute symbols can't be handled directly, we've to store the symbol reference
  1721. in the text segment and access it pc relative
  1722. For now, we assume that references where base or index equals to PC are already
  1723. relative, all other references are assumed to be absolute and thus they need
  1724. to be handled extra.
  1725. A proper solution would be to change refoptions to a set and store the information
  1726. if the symbol is absolute or relative there.
  1727. }
  1728. { create consts entry }
  1729. reference_reset(tmpref,4);
  1730. current_asmdata.getjumplabel(l);
  1731. cg.a_label(current_procinfo.aktlocaldata,l);
  1732. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  1733. if assigned(ref.symbol) then
  1734. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset))
  1735. else
  1736. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  1737. { load consts entry }
  1738. tmpreg:=getintregister(list,OS_INT);
  1739. tmpref.symbol:=l;
  1740. tmpref.base:=NR_PC;
  1741. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  1742. if (ref.base<>NR_NO) then
  1743. begin
  1744. if ref.index<>NR_NO then
  1745. begin
  1746. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  1747. ref.base:=tmpreg;
  1748. end
  1749. else
  1750. if ref.base<>NR_PC then
  1751. begin
  1752. ref.index:=tmpreg;
  1753. ref.shiftimm:=0;
  1754. ref.signindex:=1;
  1755. ref.shiftmode:=SM_None;
  1756. end
  1757. else
  1758. ref.base:=tmpreg;
  1759. end
  1760. else
  1761. ref.base:=tmpreg;
  1762. ref.offset:=0;
  1763. ref.symbol:=nil;
  1764. end;
  1765. procedure tcgarm.g_concatcopy_move(list : TAsmList;const source,dest : treference;len : tcgint);
  1766. var
  1767. paraloc1,paraloc2,paraloc3 : TCGPara;
  1768. begin
  1769. paraloc1.init;
  1770. paraloc2.init;
  1771. paraloc3.init;
  1772. paramanager.getintparaloc(pocall_default,1,paraloc1);
  1773. paramanager.getintparaloc(pocall_default,2,paraloc2);
  1774. paramanager.getintparaloc(pocall_default,3,paraloc3);
  1775. a_load_const_cgpara(list,OS_INT,len,paraloc3);
  1776. a_loadaddr_ref_cgpara(list,dest,paraloc2);
  1777. a_loadaddr_ref_cgpara(list,source,paraloc1);
  1778. paramanager.freecgpara(list,paraloc3);
  1779. paramanager.freecgpara(list,paraloc2);
  1780. paramanager.freecgpara(list,paraloc1);
  1781. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1782. alloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1783. a_call_name(list,'FPC_MOVE',false);
  1784. dealloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1785. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1786. paraloc3.done;
  1787. paraloc2.done;
  1788. paraloc1.done;
  1789. end;
  1790. procedure tcgarm.g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : tcgint;aligned : boolean);
  1791. const
  1792. maxtmpreg=10;{roozbeh: can be reduced to 8 or lower if might conflick with reserved ones,also +2 is used becouse of regs required for referencing}
  1793. var
  1794. srcref,dstref,usedtmpref,usedtmpref2:treference;
  1795. srcreg,destreg,countreg,r,tmpreg:tregister;
  1796. helpsize:aint;
  1797. copysize:byte;
  1798. cgsize:Tcgsize;
  1799. tmpregisters:array[1..maxtmpreg] of tregister;
  1800. tmpregi,tmpregi2:byte;
  1801. { will never be called with count<=4 }
  1802. procedure genloop(count : aword;size : byte);
  1803. const
  1804. size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
  1805. var
  1806. l : tasmlabel;
  1807. begin
  1808. current_asmdata.getjumplabel(l);
  1809. if count<size then size:=1;
  1810. a_load_const_reg(list,OS_INT,count div size,countreg);
  1811. cg.a_label(list,l);
  1812. srcref.addressmode:=AM_POSTINDEXED;
  1813. dstref.addressmode:=AM_POSTINDEXED;
  1814. srcref.offset:=size;
  1815. dstref.offset:=size;
  1816. r:=getintregister(list,size2opsize[size]);
  1817. a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
  1818. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
  1819. a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
  1820. a_jmp_flags(list,F_NE,l);
  1821. srcref.offset:=1;
  1822. dstref.offset:=1;
  1823. case count mod size of
  1824. 1:
  1825. begin
  1826. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1827. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1828. end;
  1829. 2:
  1830. if aligned then
  1831. begin
  1832. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  1833. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  1834. end
  1835. else
  1836. begin
  1837. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1838. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1839. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1840. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1841. end;
  1842. 3:
  1843. if aligned then
  1844. begin
  1845. srcref.offset:=2;
  1846. dstref.offset:=2;
  1847. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  1848. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  1849. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1850. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1851. end
  1852. else
  1853. begin
  1854. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1855. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1856. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1857. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1858. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1859. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1860. end;
  1861. end;
  1862. { keep the registers alive }
  1863. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  1864. list.concat(taicpu.op_reg_reg(A_MOV,srcreg,srcreg));
  1865. list.concat(taicpu.op_reg_reg(A_MOV,destreg,destreg));
  1866. end;
  1867. begin
  1868. if len=0 then
  1869. exit;
  1870. helpsize:=12+maxtmpreg*4;//52 with maxtmpreg=10
  1871. dstref:=dest;
  1872. srcref:=source;
  1873. if cs_opt_size in current_settings.optimizerswitches then
  1874. helpsize:=8;
  1875. if aligned and (len=4) then
  1876. begin
  1877. tmpreg:=getintregister(list,OS_32);
  1878. a_load_ref_reg(list,OS_32,OS_32,source,tmpreg);
  1879. a_load_reg_ref(list,OS_32,OS_32,tmpreg,dest);
  1880. end
  1881. else if (len<=helpsize) and aligned then
  1882. begin
  1883. tmpregi:=0;
  1884. srcreg:=getintregister(list,OS_ADDR);
  1885. { explicit pc relative addressing, could be
  1886. e.g. a floating point constant }
  1887. if source.base=NR_PC then
  1888. begin
  1889. { ... then we don't need a loadaddr }
  1890. srcref:=source;
  1891. end
  1892. else
  1893. begin
  1894. a_loadaddr_ref_reg(list,source,srcreg);
  1895. reference_reset_base(srcref,srcreg,0,source.alignment);
  1896. end;
  1897. while (len div 4 <> 0) and (tmpregi<maxtmpreg) do
  1898. begin
  1899. inc(tmpregi);
  1900. tmpregisters[tmpregi]:=getintregister(list,OS_32);
  1901. a_load_ref_reg(list,OS_32,OS_32,srcref,tmpregisters[tmpregi]);
  1902. inc(srcref.offset,4);
  1903. dec(len,4);
  1904. end;
  1905. destreg:=getintregister(list,OS_ADDR);
  1906. a_loadaddr_ref_reg(list,dest,destreg);
  1907. reference_reset_base(dstref,destreg,0,dest.alignment);
  1908. tmpregi2:=1;
  1909. while (tmpregi2<=tmpregi) do
  1910. begin
  1911. a_load_reg_ref(list,OS_32,OS_32,tmpregisters[tmpregi2],dstref);
  1912. inc(dstref.offset,4);
  1913. inc(tmpregi2);
  1914. end;
  1915. copysize:=4;
  1916. cgsize:=OS_32;
  1917. while len<>0 do
  1918. begin
  1919. if len<2 then
  1920. begin
  1921. copysize:=1;
  1922. cgsize:=OS_8;
  1923. end
  1924. else if len<4 then
  1925. begin
  1926. copysize:=2;
  1927. cgsize:=OS_16;
  1928. end;
  1929. dec(len,copysize);
  1930. r:=getintregister(list,cgsize);
  1931. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  1932. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  1933. inc(srcref.offset,copysize);
  1934. inc(dstref.offset,copysize);
  1935. end;{end of while}
  1936. end
  1937. else
  1938. begin
  1939. cgsize:=OS_32;
  1940. if (len<=4) then{len<=4 and not aligned}
  1941. begin
  1942. r:=getintregister(list,cgsize);
  1943. usedtmpref:=a_internal_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1944. if Len=1 then
  1945. a_load_reg_ref(list,OS_8,OS_8,r,dstref)
  1946. else
  1947. begin
  1948. tmpreg:=getintregister(list,cgsize);
  1949. usedtmpref2:=a_internal_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1950. inc(usedtmpref.offset,1);
  1951. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1952. inc(usedtmpref2.offset,1);
  1953. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1954. if len>2 then
  1955. begin
  1956. inc(usedtmpref.offset,1);
  1957. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1958. inc(usedtmpref2.offset,1);
  1959. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1960. if len>3 then
  1961. begin
  1962. inc(usedtmpref.offset,1);
  1963. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1964. inc(usedtmpref2.offset,1);
  1965. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1966. end;
  1967. end;
  1968. end;
  1969. end{end of if len<=4}
  1970. else
  1971. begin{unaligned & 4<len<helpsize **or** aligned/unaligned & len>helpsize}
  1972. destreg:=getintregister(list,OS_ADDR);
  1973. a_loadaddr_ref_reg(list,dest,destreg);
  1974. reference_reset_base(dstref,destreg,0,dest.alignment);
  1975. srcreg:=getintregister(list,OS_ADDR);
  1976. a_loadaddr_ref_reg(list,source,srcreg);
  1977. reference_reset_base(srcref,srcreg,0,source.alignment);
  1978. countreg:=getintregister(list,OS_32);
  1979. // if cs_opt_size in current_settings.optimizerswitches then
  1980. { roozbeh : it seems loading 1 byte is faster becouse of caching/fetching(?) }
  1981. {if aligned then
  1982. genloop(len,4)
  1983. else}
  1984. genloop(len,1);
  1985. end;
  1986. end;
  1987. end;
  1988. procedure tcgarm.g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : tcgint);
  1989. begin
  1990. g_concatcopy_internal(list,source,dest,len,false);
  1991. end;
  1992. procedure tcgarm.g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);
  1993. begin
  1994. if (source.alignment in [1..3]) or
  1995. (dest.alignment in [1..3]) then
  1996. g_concatcopy_internal(list,source,dest,len,false)
  1997. else
  1998. g_concatcopy_internal(list,source,dest,len,true);
  1999. end;
  2000. procedure tcgarm.g_overflowCheck(list : TAsmList;const l : tlocation;def : tdef);
  2001. var
  2002. ovloc : tlocation;
  2003. begin
  2004. ovloc.loc:=LOC_VOID;
  2005. g_overflowCheck_loc(list,l,def,ovloc);
  2006. end;
  2007. procedure tcgarm.g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);
  2008. var
  2009. hl : tasmlabel;
  2010. ai:TAiCpu;
  2011. hflags : tresflags;
  2012. begin
  2013. if not(cs_check_overflow in current_settings.localswitches) then
  2014. exit;
  2015. current_asmdata.getjumplabel(hl);
  2016. case ovloc.loc of
  2017. LOC_VOID:
  2018. begin
  2019. ai:=taicpu.op_sym(A_B,hl);
  2020. ai.is_jmp:=true;
  2021. if not((def.typ=pointerdef) or
  2022. ((def.typ=orddef) and
  2023. (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,
  2024. pasbool8,pasbool16,pasbool32,pasbool64]))) then
  2025. ai.SetCondition(C_VC)
  2026. else
  2027. if TAiCpu(List.Last).opcode in [A_RSB,A_RSC,A_SBC,A_SUB] then
  2028. ai.SetCondition(C_CS)
  2029. else
  2030. ai.SetCondition(C_CC);
  2031. list.concat(ai);
  2032. end;
  2033. LOC_FLAGS:
  2034. begin
  2035. hflags:=ovloc.resflags;
  2036. inverse_flags(hflags);
  2037. cg.a_jmp_flags(list,hflags,hl);
  2038. end;
  2039. else
  2040. internalerror(200409281);
  2041. end;
  2042. a_call_name(list,'FPC_OVERFLOW',false);
  2043. a_label(list,hl);
  2044. end;
  2045. procedure tcgarm.g_save_registers(list : TAsmList);
  2046. begin
  2047. { this work is done in g_proc_entry }
  2048. end;
  2049. procedure tcgarm.g_restore_registers(list : TAsmList);
  2050. begin
  2051. { this work is done in g_proc_exit }
  2052. end;
  2053. procedure tcgarm.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  2054. var
  2055. ai : taicpu;
  2056. begin
  2057. ai:=Taicpu.Op_sym(A_B,l);
  2058. ai.SetCondition(OpCmp2AsmCond[cond]);
  2059. ai.is_jmp:=true;
  2060. list.concat(ai);
  2061. end;
  2062. procedure tcgarm.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);
  2063. var
  2064. hsym : tsym;
  2065. href : treference;
  2066. paraloc : Pcgparalocation;
  2067. shift : byte;
  2068. begin
  2069. { calculate the parameter info for the procdef }
  2070. procdef.init_paraloc_info(callerside);
  2071. hsym:=tsym(procdef.parast.Find('self'));
  2072. if not(assigned(hsym) and
  2073. (hsym.typ=paravarsym)) then
  2074. internalerror(200305251);
  2075. paraloc:=tparavarsym(hsym).paraloc[callerside].location;
  2076. while paraloc<>nil do
  2077. with paraloc^ do
  2078. begin
  2079. case loc of
  2080. LOC_REGISTER:
  2081. begin
  2082. if is_shifter_const(ioffset,shift) then
  2083. a_op_const_reg(list,OP_SUB,size,ioffset,register)
  2084. else
  2085. begin
  2086. a_load_const_reg(list,OS_ADDR,ioffset,NR_R12);
  2087. a_op_reg_reg(list,OP_SUB,size,NR_R12,register);
  2088. end;
  2089. end;
  2090. LOC_REFERENCE:
  2091. begin
  2092. { offset in the wrapper needs to be adjusted for the stored
  2093. return address }
  2094. reference_reset_base(href,reference.index,reference.offset+sizeof(aint),sizeof(pint));
  2095. if is_shifter_const(ioffset,shift) then
  2096. a_op_const_ref(list,OP_SUB,size,ioffset,href)
  2097. else
  2098. begin
  2099. a_load_const_reg(list,OS_ADDR,ioffset,NR_R12);
  2100. a_op_reg_ref(list,OP_SUB,size,NR_R12,href);
  2101. end;
  2102. end
  2103. else
  2104. internalerror(200309189);
  2105. end;
  2106. paraloc:=next;
  2107. end;
  2108. end;
  2109. procedure tcgarm.g_stackpointer_alloc(list: TAsmList; size: longint);
  2110. begin
  2111. internalerror(200807237);
  2112. end;
  2113. function get_scalar_mm_op(fromsize,tosize : tcgsize) : tasmop;
  2114. const
  2115. convertop : array[OS_F32..OS_F128,OS_F32..OS_F128] of tasmop = (
  2116. (A_FCPYS,A_FCVTSD,A_NONE,A_NONE,A_NONE),
  2117. (A_FCVTDS,A_FCPYD,A_NONE,A_NONE,A_NONE),
  2118. (A_NONE,A_NONE,A_NONE,A_NONE,A_NONE),
  2119. (A_NONE,A_NONE,A_NONE,A_NONE,A_NONE),
  2120. (A_NONE,A_NONE,A_NONE,A_NONE,A_NONE));
  2121. begin
  2122. result:=convertop[fromsize,tosize];
  2123. if result=A_NONE then
  2124. internalerror(200312205);
  2125. end;
  2126. procedure tcgarm.a_loadmm_reg_reg(list: tasmlist; fromsize,tosize: tcgsize; reg1,reg2: tregister; shuffle: pmmshuffle);
  2127. var
  2128. instr: taicpu;
  2129. begin
  2130. if shuffle=nil then
  2131. begin
  2132. if fromsize=tosize then
  2133. { needs correct size in case of spilling }
  2134. case fromsize of
  2135. OS_F32:
  2136. instr:=taicpu.op_reg_reg(A_FCPYS,reg2,reg1);
  2137. OS_F64:
  2138. instr:=taicpu.op_reg_reg(A_FCPYD,reg2,reg1);
  2139. else
  2140. internalerror(2009112405);
  2141. end
  2142. else
  2143. internalerror(2009112406);
  2144. end
  2145. else if shufflescalar(shuffle) then
  2146. instr:=taicpu.op_reg_reg(get_scalar_mm_op(tosize,fromsize),reg2,reg1)
  2147. else
  2148. internalerror(2009112407);
  2149. list.concat(instr);
  2150. case instr.opcode of
  2151. A_FCPYS,
  2152. A_FCPYD:
  2153. add_move_instruction(instr);
  2154. end;
  2155. end;
  2156. procedure tcgarm.a_loadmm_ref_reg(list: tasmlist; fromsize,tosize: tcgsize; const ref: treference; reg: tregister; shuffle: pmmshuffle);
  2157. var
  2158. intreg,
  2159. tmpmmreg : tregister;
  2160. reg64 : tregister64;
  2161. op : tasmop;
  2162. begin
  2163. if assigned(shuffle) and
  2164. not(shufflescalar(shuffle)) then
  2165. internalerror(2009112413);
  2166. case fromsize of
  2167. OS_32,OS_S32:
  2168. begin
  2169. fromsize:=OS_F32;
  2170. { since we are loading an integer, no conversion may be required }
  2171. if (fromsize<>tosize) then
  2172. internalerror(2009112801);
  2173. end;
  2174. OS_64,OS_S64:
  2175. begin
  2176. fromsize:=OS_F64;
  2177. { since we are loading an integer, no conversion may be required }
  2178. if (fromsize<>tosize) then
  2179. internalerror(2009112901);
  2180. end;
  2181. end;
  2182. if (fromsize<>tosize) then
  2183. tmpmmreg:=getmmregister(list,fromsize)
  2184. else
  2185. tmpmmreg:=reg;
  2186. if (ref.alignment in [1,2]) then
  2187. begin
  2188. case fromsize of
  2189. OS_F32:
  2190. begin
  2191. intreg:=getintregister(list,OS_32);
  2192. a_load_ref_reg(list,OS_32,OS_32,ref,intreg);
  2193. a_loadmm_intreg_reg(list,OS_32,OS_F32,intreg,tmpmmreg,mms_movescalar);
  2194. end;
  2195. OS_F64:
  2196. begin
  2197. reg64.reglo:=getintregister(list,OS_32);
  2198. reg64.reghi:=getintregister(list,OS_32);
  2199. cg64.a_load64_ref_reg(list,ref,reg64);
  2200. cg64.a_loadmm_intreg64_reg(list,OS_F64,reg64,tmpmmreg);
  2201. end;
  2202. else
  2203. internalerror(2009112412);
  2204. end;
  2205. end
  2206. else
  2207. begin
  2208. case fromsize of
  2209. OS_F32:
  2210. op:=A_FLDS;
  2211. OS_F64:
  2212. op:=A_FLDD;
  2213. else
  2214. internalerror(2009112415);
  2215. end;
  2216. handle_load_store(list,op,PF_None,tmpmmreg,ref);
  2217. end;
  2218. if (tmpmmreg<>reg) then
  2219. a_loadmm_reg_reg(list,fromsize,tosize,tmpmmreg,reg,shuffle);
  2220. end;
  2221. procedure tcgarm.a_loadmm_reg_ref(list: tasmlist; fromsize,tosize: tcgsize; reg: tregister; const ref: treference; shuffle: pmmshuffle);
  2222. var
  2223. intreg,
  2224. tmpmmreg : tregister;
  2225. reg64 : tregister64;
  2226. op : tasmop;
  2227. begin
  2228. if assigned(shuffle) and
  2229. not(shufflescalar(shuffle)) then
  2230. internalerror(2009112416);
  2231. case tosize of
  2232. OS_32,OS_S32:
  2233. begin
  2234. tosize:=OS_F32;
  2235. { since we are loading an integer, no conversion may be required }
  2236. if (fromsize<>tosize) then
  2237. internalerror(2009112801);
  2238. end;
  2239. OS_64,OS_S64:
  2240. begin
  2241. tosize:=OS_F64;
  2242. { since we are loading an integer, no conversion may be required }
  2243. if (fromsize<>tosize) then
  2244. internalerror(2009112901);
  2245. end;
  2246. end;
  2247. if (fromsize<>tosize) then
  2248. begin
  2249. tmpmmreg:=getmmregister(list,tosize);
  2250. a_loadmm_reg_reg(list,fromsize,tosize,reg,tmpmmreg,shuffle);
  2251. end
  2252. else
  2253. tmpmmreg:=reg;
  2254. if (ref.alignment in [1,2]) then
  2255. begin
  2256. case tosize of
  2257. OS_F32:
  2258. begin
  2259. intreg:=getintregister(list,OS_32);
  2260. a_loadmm_reg_intreg(list,OS_F32,OS_32,tmpmmreg,intreg,shuffle);
  2261. a_load_reg_ref(list,OS_32,OS_32,intreg,ref);
  2262. end;
  2263. OS_F64:
  2264. begin
  2265. reg64.reglo:=getintregister(list,OS_32);
  2266. reg64.reghi:=getintregister(list,OS_32);
  2267. cg64.a_loadmm_reg_intreg64(list,OS_F64,tmpmmreg,reg64);
  2268. cg64.a_load64_reg_ref(list,reg64,ref);
  2269. end;
  2270. else
  2271. internalerror(2009112417);
  2272. end;
  2273. end
  2274. else
  2275. begin
  2276. case fromsize of
  2277. OS_F32:
  2278. op:=A_FSTS;
  2279. OS_F64:
  2280. op:=A_FSTD;
  2281. else
  2282. internalerror(2009112418);
  2283. end;
  2284. handle_load_store(list,op,PF_None,tmpmmreg,ref);
  2285. end;
  2286. end;
  2287. procedure tcgarm.a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize : tcgsize; intreg, mmreg: tregister; shuffle: pmmshuffle);
  2288. begin
  2289. { this code can only be used to transfer raw data, not to perform
  2290. conversions }
  2291. if (tosize<>OS_F32) then
  2292. internalerror(2009112419);
  2293. if not(fromsize in [OS_32,OS_S32]) then
  2294. internalerror(2009112420);
  2295. if assigned(shuffle) and
  2296. not shufflescalar(shuffle) then
  2297. internalerror(2009112516);
  2298. list.concat(taicpu.op_reg_reg(A_FMSR,mmreg,intreg));
  2299. end;
  2300. procedure tcgarm.a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize : tcgsize; mmreg, intreg: tregister;shuffle : pmmshuffle);
  2301. begin
  2302. { this code can only be used to transfer raw data, not to perform
  2303. conversions }
  2304. if (fromsize<>OS_F32) then
  2305. internalerror(2009112430);
  2306. if not(tosize in [OS_32,OS_S32]) then
  2307. internalerror(2009112420);
  2308. if assigned(shuffle) and
  2309. not shufflescalar(shuffle) then
  2310. internalerror(2009112514);
  2311. list.concat(taicpu.op_reg_reg(A_FMRS,intreg,mmreg));
  2312. end;
  2313. procedure tcgarm.a_opmm_reg_reg(list: tasmlist; op: topcg; size: tcgsize; src, dst: tregister; shuffle: pmmshuffle);
  2314. var
  2315. tmpreg: tregister;
  2316. begin
  2317. { the vfp doesn't support xor nor any other logical operation, but
  2318. this routine is used to initialise global mm regvars. We can
  2319. easily initialise an mm reg with 0 though. }
  2320. case op of
  2321. OP_XOR:
  2322. begin
  2323. if (src<>dst) or
  2324. (reg_cgsize(src)<>size) or
  2325. assigned(shuffle) then
  2326. internalerror(2009112907);
  2327. tmpreg:=getintregister(list,OS_32);
  2328. a_load_const_reg(list,OS_32,0,tmpreg);
  2329. case size of
  2330. OS_F32:
  2331. list.concat(taicpu.op_reg_reg(A_FMSR,dst,tmpreg));
  2332. OS_F64:
  2333. list.concat(taicpu.op_reg_reg_reg(A_FMDRR,dst,tmpreg,tmpreg));
  2334. else
  2335. internalerror(2009112908);
  2336. end;
  2337. end
  2338. else
  2339. internalerror(2009112906);
  2340. end;
  2341. end;
  2342. procedure tcgarm.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  2343. procedure loadvmttor12;
  2344. var
  2345. href : treference;
  2346. begin
  2347. reference_reset_base(href,NR_R0,0,sizeof(pint));
  2348. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  2349. end;
  2350. procedure op_onr12methodaddr;
  2351. var
  2352. href : treference;
  2353. begin
  2354. if (procdef.extnumber=$ffff) then
  2355. Internalerror(200006139);
  2356. { call/jmp vmtoffs(%eax) ; method offs }
  2357. reference_reset_base(href,NR_R12,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),sizeof(pint));
  2358. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  2359. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
  2360. end;
  2361. var
  2362. make_global : boolean;
  2363. begin
  2364. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  2365. Internalerror(200006137);
  2366. if not assigned(procdef.struct) or
  2367. (procdef.procoptions*[po_classmethod, po_staticmethod,
  2368. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  2369. Internalerror(200006138);
  2370. if procdef.owner.symtabletype<>ObjectSymtable then
  2371. Internalerror(200109191);
  2372. make_global:=false;
  2373. if (not current_module.is_unit) or
  2374. create_smartlink or
  2375. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  2376. make_global:=true;
  2377. if make_global then
  2378. list.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  2379. else
  2380. list.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  2381. { the wrapper might need aktlocaldata for the additional data to
  2382. load the constant }
  2383. current_procinfo:=cprocinfo.create(nil);
  2384. { set param1 interface to self }
  2385. g_adjust_self_value(list,procdef,ioffset);
  2386. { case 4 }
  2387. if (po_virtualmethod in procdef.procoptions) and
  2388. not is_objectpascal_helper(procdef.struct) then
  2389. begin
  2390. loadvmttor12;
  2391. op_onr12methodaddr;
  2392. end
  2393. { case 0 }
  2394. else
  2395. list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname)));
  2396. list.concatlist(current_procinfo.aktlocaldata);
  2397. current_procinfo.Free;
  2398. current_procinfo:=nil;
  2399. list.concat(Tai_symbol_end.Createname(labelname));
  2400. end;
  2401. procedure tcgarm.maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  2402. const
  2403. overflowops = [OP_MUL,OP_SHL,OP_ADD,OP_SUB,OP_NOT,OP_NEG];
  2404. begin
  2405. if (op in overflowops) and
  2406. (size in [OS_8,OS_S8,OS_16,OS_S16]) then
  2407. a_load_reg_reg(list,OS_32,size,dst,dst);
  2408. end;
  2409. function tcgarm.get_darwin_call_stub(const s: string; weak: boolean): tasmsymbol;
  2410. var
  2411. stubname: string;
  2412. l1: tasmsymbol;
  2413. href: treference;
  2414. begin
  2415. stubname := 'L'+s+'$stub';
  2416. result := current_asmdata.getasmsymbol(stubname);
  2417. if assigned(result) then
  2418. exit;
  2419. if current_asmdata.asmlists[al_imports]=nil then
  2420. current_asmdata.asmlists[al_imports]:=TAsmList.create;
  2421. new_section(current_asmdata.asmlists[al_imports],sec_stub,'',4);
  2422. result := current_asmdata.RefAsmSymbol(stubname);
  2423. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(result,0));
  2424. { register as a weak symbol if necessary }
  2425. if weak then
  2426. current_asmdata.weakrefasmsymbol(s);
  2427. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_indirect_symbol,s));
  2428. if not(cs_create_pic in current_settings.moduleswitches) then
  2429. begin
  2430. l1 := current_asmdata.RefAsmSymbol('L'+s+'$slp');
  2431. reference_reset_symbol(href,l1,0,sizeof(pint));
  2432. href.refaddr:=addr_full;
  2433. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_ref(A_LDR,NR_R12,href));
  2434. reference_reset_base(href,NR_R12,0,sizeof(pint));
  2435. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_ref(A_LDR,NR_R15,href));
  2436. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(l1,0));
  2437. l1 := current_asmdata.RefAsmSymbol('L'+s+'$lazy_ptr');
  2438. current_asmdata.asmlists[al_imports].concat(tai_const.create_sym(l1));
  2439. end
  2440. else
  2441. internalerror(2008100401);
  2442. new_section(current_asmdata.asmlists[al_imports],sec_data_lazy,'',sizeof(pint));
  2443. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(l1,0));
  2444. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_indirect_symbol,s));
  2445. current_asmdata.asmlists[al_imports].concat(tai_const.createname('dyld_stub_binding_helper',0));
  2446. end;
  2447. procedure tcg64farm.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  2448. begin
  2449. case op of
  2450. OP_NEG:
  2451. begin
  2452. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  2453. list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
  2454. end;
  2455. OP_NOT:
  2456. begin
  2457. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  2458. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  2459. end;
  2460. else
  2461. a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
  2462. end;
  2463. end;
  2464. procedure tcg64farm.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  2465. begin
  2466. a_op64_const_reg_reg(list,op,size,value,reg,reg);
  2467. end;
  2468. procedure tcg64farm.a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);
  2469. var
  2470. ovloc : tlocation;
  2471. begin
  2472. a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,ovloc);
  2473. end;
  2474. procedure tcg64farm.a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
  2475. var
  2476. ovloc : tlocation;
  2477. begin
  2478. a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,ovloc);
  2479. end;
  2480. procedure tcg64farm.a_loadmm_intreg64_reg(list: TAsmList; mmsize: tcgsize; intreg: tregister64; mmreg: tregister);
  2481. begin
  2482. { this code can only be used to transfer raw data, not to perform
  2483. conversions }
  2484. if (mmsize<>OS_F64) then
  2485. internalerror(2009112405);
  2486. list.concat(taicpu.op_reg_reg_reg(A_FMDRR,mmreg,intreg.reglo,intreg.reghi));
  2487. end;
  2488. procedure tcg64farm.a_loadmm_reg_intreg64(list: TAsmList; mmsize: tcgsize; mmreg: tregister; intreg: tregister64);
  2489. begin
  2490. { this code can only be used to transfer raw data, not to perform
  2491. conversions }
  2492. if (mmsize<>OS_F64) then
  2493. internalerror(2009112406);
  2494. list.concat(taicpu.op_reg_reg_reg(A_FMRRD,intreg.reglo,intreg.reghi,mmreg));
  2495. end;
  2496. procedure tcg64farm.a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  2497. var
  2498. tmpreg : tregister;
  2499. b : byte;
  2500. begin
  2501. ovloc.loc:=LOC_VOID;
  2502. case op of
  2503. OP_NEG,
  2504. OP_NOT :
  2505. internalerror(200306017);
  2506. end;
  2507. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  2508. begin
  2509. case op of
  2510. OP_ADD:
  2511. begin
  2512. if is_shifter_const(lo(value),b) then
  2513. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  2514. else
  2515. begin
  2516. tmpreg:=cg.getintregister(list,OS_32);
  2517. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  2518. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  2519. end;
  2520. if is_shifter_const(hi(value),b) then
  2521. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  2522. else
  2523. begin
  2524. tmpreg:=cg.getintregister(list,OS_32);
  2525. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  2526. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  2527. end;
  2528. end;
  2529. OP_SUB:
  2530. begin
  2531. if is_shifter_const(lo(value),b) then
  2532. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  2533. else
  2534. begin
  2535. tmpreg:=cg.getintregister(list,OS_32);
  2536. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  2537. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  2538. end;
  2539. if is_shifter_const(hi(value),b) then
  2540. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))),PF_S))
  2541. else
  2542. begin
  2543. tmpreg:=cg.getintregister(list,OS_32);
  2544. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  2545. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  2546. end;
  2547. end;
  2548. else
  2549. internalerror(200502131);
  2550. end;
  2551. if size=OS_64 then
  2552. begin
  2553. { the arm has an weired opinion how flags for SUB/ADD are handled }
  2554. ovloc.loc:=LOC_FLAGS;
  2555. case op of
  2556. OP_ADD:
  2557. ovloc.resflags:=F_CS;
  2558. OP_SUB:
  2559. ovloc.resflags:=F_CC;
  2560. end;
  2561. end;
  2562. end
  2563. else
  2564. begin
  2565. case op of
  2566. OP_AND,OP_OR,OP_XOR:
  2567. begin
  2568. cg.a_op_const_reg_reg(list,op,OS_32,aint(lo(value)),regsrc.reglo,regdst.reglo);
  2569. cg.a_op_const_reg_reg(list,op,OS_32,aint(hi(value)),regsrc.reghi,regdst.reghi);
  2570. end;
  2571. OP_ADD:
  2572. begin
  2573. if is_shifter_const(aint(lo(value)),b) then
  2574. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
  2575. else
  2576. begin
  2577. tmpreg:=cg.getintregister(list,OS_32);
  2578. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  2579. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  2580. end;
  2581. if is_shifter_const(aint(hi(value)),b) then
  2582. list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,aint(hi(value))))
  2583. else
  2584. begin
  2585. tmpreg:=cg.getintregister(list,OS_32);
  2586. cg.a_load_const_reg(list,OS_32,aint(hi(value)),tmpreg);
  2587. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
  2588. end;
  2589. end;
  2590. OP_SUB:
  2591. begin
  2592. if is_shifter_const(aint(lo(value)),b) then
  2593. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
  2594. else
  2595. begin
  2596. tmpreg:=cg.getintregister(list,OS_32);
  2597. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  2598. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  2599. end;
  2600. if is_shifter_const(aint(hi(value)),b) then
  2601. list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))))
  2602. else
  2603. begin
  2604. tmpreg:=cg.getintregister(list,OS_32);
  2605. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  2606. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
  2607. end;
  2608. end;
  2609. else
  2610. internalerror(2003083101);
  2611. end;
  2612. end;
  2613. end;
  2614. procedure tcg64farm.a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  2615. begin
  2616. ovloc.loc:=LOC_VOID;
  2617. case op of
  2618. OP_NEG,
  2619. OP_NOT :
  2620. internalerror(200306017);
  2621. end;
  2622. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  2623. begin
  2624. case op of
  2625. OP_ADD:
  2626. begin
  2627. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  2628. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi),PF_S));
  2629. end;
  2630. OP_SUB:
  2631. begin
  2632. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  2633. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi),PF_S));
  2634. end;
  2635. else
  2636. internalerror(2003083101);
  2637. end;
  2638. if size=OS_64 then
  2639. begin
  2640. { the arm has an weired opinion how flags for SUB/ADD are handled }
  2641. ovloc.loc:=LOC_FLAGS;
  2642. case op of
  2643. OP_ADD:
  2644. ovloc.resflags:=F_CS;
  2645. OP_SUB:
  2646. ovloc.resflags:=F_CC;
  2647. end;
  2648. end;
  2649. end
  2650. else
  2651. begin
  2652. case op of
  2653. OP_AND,OP_OR,OP_XOR:
  2654. begin
  2655. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  2656. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  2657. end;
  2658. OP_ADD:
  2659. begin
  2660. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  2661. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  2662. end;
  2663. OP_SUB:
  2664. begin
  2665. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  2666. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
  2667. end;
  2668. else
  2669. internalerror(2003083101);
  2670. end;
  2671. end;
  2672. end;
  2673. procedure Tthumb2cgarm.init_register_allocators;
  2674. begin
  2675. inherited init_register_allocators;
  2676. { currently, we save R14 always, so we can use it }
  2677. if (target_info.system<>system_arm_darwin) then
  2678. rg[R_INTREGISTER]:=trgintcputhumb2.create(R_INTREGISTER,R_SUBWHOLE,
  2679. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  2680. RS_R9,RS_R10,RS_R12,RS_R14],first_int_imreg,[])
  2681. else
  2682. { r9 is not available on Darwin according to the llvm code generator }
  2683. rg[R_INTREGISTER]:=trgintcputhumb2.create(R_INTREGISTER,R_SUBWHOLE,
  2684. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  2685. RS_R10,RS_R12,RS_R14],first_int_imreg,[]);
  2686. rg[R_FPUREGISTER]:=trgcputhumb2.create(R_FPUREGISTER,R_SUBNONE,
  2687. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7],first_fpu_imreg,[]);
  2688. rg[R_MMREGISTER]:=trgcputhumb2.create(R_MMREGISTER,R_SUBNONE,
  2689. [RS_S0,RS_S1,RS_R2,RS_R3,RS_R4,RS_S31],first_mm_imreg,[]);
  2690. end;
  2691. procedure Tthumb2cgarm.done_register_allocators;
  2692. begin
  2693. rg[R_INTREGISTER].free;
  2694. rg[R_FPUREGISTER].free;
  2695. rg[R_MMREGISTER].free;
  2696. inherited done_register_allocators;
  2697. end;
  2698. procedure Tthumb2cgarm.a_call_reg(list : TAsmList;reg: tregister);
  2699. begin
  2700. list.concat(taicpu.op_reg(A_BLX, reg));
  2701. {
  2702. the compiler does not properly set this flag anymore in pass 1, and
  2703. for now we only need it after pass 2 (I hope) (JM)
  2704. if not(pi_do_call in current_procinfo.flags) then
  2705. internalerror(2003060703);
  2706. }
  2707. include(current_procinfo.flags,pi_do_call);
  2708. end;
  2709. procedure Tthumb2cgarm.a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);
  2710. var
  2711. imm_shift : byte;
  2712. l : tasmlabel;
  2713. hr : treference;
  2714. begin
  2715. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  2716. internalerror(2002090902);
  2717. if is_shifter_const(a,imm_shift) then
  2718. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  2719. { loading of constants with mov and orr }
  2720. else if (is_shifter_const(a-byte(a),imm_shift)) then
  2721. begin
  2722. list.concat(taicpu.op_reg_const(A_MOV,reg,a-byte(a)));
  2723. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,byte(a)));
  2724. end
  2725. else if (is_shifter_const(a-word(a),imm_shift)) and (is_shifter_const(word(a),imm_shift)) then
  2726. begin
  2727. list.concat(taicpu.op_reg_const(A_MOV,reg,a-word(a)));
  2728. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,word(a)));
  2729. end
  2730. else if (is_shifter_const(a-(dword(a) shl 8) shr 8,imm_shift)) and (is_shifter_const((dword(a) shl 8) shr 8,imm_shift)) then
  2731. begin
  2732. list.concat(taicpu.op_reg_const(A_MOV,reg,a-(dword(a) shl 8) shr 8));
  2733. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,(dword(a) shl 8) shr 8));
  2734. end
  2735. else
  2736. begin
  2737. reference_reset(hr,4);
  2738. current_asmdata.getjumplabel(l);
  2739. cg.a_label(current_procinfo.aktlocaldata,l);
  2740. hr.symboldata:=current_procinfo.aktlocaldata.last;
  2741. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
  2742. hr.symbol:=l;
  2743. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  2744. end;
  2745. end;
  2746. procedure Tthumb2cgarm.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  2747. var
  2748. oppostfix:toppostfix;
  2749. usedtmpref: treference;
  2750. tmpreg,tmpreg2 : tregister;
  2751. so : tshifterop;
  2752. dir : integer;
  2753. begin
  2754. if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then
  2755. FromSize := ToSize;
  2756. case FromSize of
  2757. { signed integer registers }
  2758. OS_8:
  2759. oppostfix:=PF_B;
  2760. OS_S8:
  2761. oppostfix:=PF_SB;
  2762. OS_16:
  2763. oppostfix:=PF_H;
  2764. OS_S16:
  2765. oppostfix:=PF_SH;
  2766. OS_32,
  2767. OS_S32:
  2768. oppostfix:=PF_None;
  2769. else
  2770. InternalError(200308297);
  2771. end;
  2772. if (ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[fromsize]) then
  2773. begin
  2774. if target_info.endian=endian_big then
  2775. dir:=-1
  2776. else
  2777. dir:=1;
  2778. case FromSize of
  2779. OS_16,OS_S16:
  2780. begin
  2781. { only complicated references need an extra loadaddr }
  2782. if assigned(ref.symbol) or
  2783. (ref.index<>NR_NO) or
  2784. (ref.offset<-255) or
  2785. (ref.offset>4094) or
  2786. { sometimes the compiler reused registers }
  2787. (reg=ref.index) or
  2788. (reg=ref.base) then
  2789. begin
  2790. tmpreg2:=getintregister(list,OS_INT);
  2791. a_loadaddr_ref_reg(list,ref,tmpreg2);
  2792. reference_reset_base(usedtmpref,tmpreg2,0,ref.alignment);
  2793. end
  2794. else
  2795. usedtmpref:=ref;
  2796. if target_info.endian=endian_big then
  2797. inc(usedtmpref.offset,1);
  2798. shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8;
  2799. tmpreg:=getintregister(list,OS_INT);
  2800. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  2801. inc(usedtmpref.offset,dir);
  2802. if FromSize=OS_16 then
  2803. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg)
  2804. else
  2805. a_internal_load_ref_reg(list,OS_S8,OS_S8,usedtmpref,tmpreg);
  2806. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  2807. end;
  2808. OS_32,OS_S32:
  2809. begin
  2810. tmpreg:=getintregister(list,OS_INT);
  2811. { only complicated references need an extra loadaddr }
  2812. if assigned(ref.symbol) or
  2813. (ref.index<>NR_NO) or
  2814. (ref.offset<-255) or
  2815. (ref.offset>4092) or
  2816. { sometimes the compiler reused registers }
  2817. (reg=ref.index) or
  2818. (reg=ref.base) then
  2819. begin
  2820. tmpreg2:=getintregister(list,OS_INT);
  2821. a_loadaddr_ref_reg(list,ref,tmpreg2);
  2822. reference_reset_base(usedtmpref,tmpreg2,0,ref.alignment);
  2823. end
  2824. else
  2825. usedtmpref:=ref;
  2826. shifterop_reset(so);so.shiftmode:=SM_LSL;
  2827. if ref.alignment=2 then
  2828. begin
  2829. if target_info.endian=endian_big then
  2830. inc(usedtmpref.offset,2);
  2831. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,reg);
  2832. inc(usedtmpref.offset,dir*2);
  2833. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,tmpreg);
  2834. so.shiftimm:=16;
  2835. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  2836. end
  2837. else
  2838. begin
  2839. if target_info.endian=endian_big then
  2840. inc(usedtmpref.offset,3);
  2841. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  2842. inc(usedtmpref.offset,dir);
  2843. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  2844. so.shiftimm:=8;
  2845. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  2846. inc(usedtmpref.offset,dir);
  2847. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  2848. so.shiftimm:=16;
  2849. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  2850. inc(usedtmpref.offset,dir);
  2851. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  2852. so.shiftimm:=24;
  2853. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  2854. end;
  2855. end
  2856. else
  2857. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  2858. end;
  2859. end
  2860. else
  2861. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  2862. if (fromsize=OS_S8) and (tosize = OS_16) then
  2863. a_load_reg_reg(list,OS_16,OS_32,reg,reg);
  2864. end;
  2865. procedure Tthumb2cgarm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);
  2866. var
  2867. shift : byte;
  2868. tmpreg : tregister;
  2869. so : tshifterop;
  2870. l1 : longint;
  2871. begin
  2872. ovloc.loc:=LOC_VOID;
  2873. if {$ifopt R+}(a<>-2147483648) and{$endif} is_shifter_const(-a,shift) then
  2874. case op of
  2875. OP_ADD:
  2876. begin
  2877. op:=OP_SUB;
  2878. a:=aint(dword(-a));
  2879. end;
  2880. OP_SUB:
  2881. begin
  2882. op:=OP_ADD;
  2883. a:=aint(dword(-a));
  2884. end
  2885. end;
  2886. if is_shifter_const(a,shift) and not(op in [OP_IMUL,OP_MUL]) then
  2887. case op of
  2888. OP_NEG,OP_NOT,
  2889. OP_DIV,OP_IDIV:
  2890. internalerror(200308281);
  2891. OP_SHL:
  2892. begin
  2893. if a>32 then
  2894. internalerror(200308294);
  2895. if a<>0 then
  2896. begin
  2897. shifterop_reset(so);
  2898. so.shiftmode:=SM_LSL;
  2899. so.shiftimm:=a;
  2900. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  2901. end
  2902. else
  2903. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  2904. end;
  2905. OP_ROL:
  2906. begin
  2907. if a>32 then
  2908. internalerror(200308294);
  2909. if a<>0 then
  2910. begin
  2911. shifterop_reset(so);
  2912. so.shiftmode:=SM_ROR;
  2913. so.shiftimm:=32-a;
  2914. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  2915. end
  2916. else
  2917. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  2918. end;
  2919. OP_ROR:
  2920. begin
  2921. if a>32 then
  2922. internalerror(200308294);
  2923. if a<>0 then
  2924. begin
  2925. shifterop_reset(so);
  2926. so.shiftmode:=SM_ROR;
  2927. so.shiftimm:=a;
  2928. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  2929. end
  2930. else
  2931. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  2932. end;
  2933. OP_SHR:
  2934. begin
  2935. if a>32 then
  2936. internalerror(200308292);
  2937. shifterop_reset(so);
  2938. if a<>0 then
  2939. begin
  2940. so.shiftmode:=SM_LSR;
  2941. so.shiftimm:=a;
  2942. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  2943. end
  2944. else
  2945. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  2946. end;
  2947. OP_SAR:
  2948. begin
  2949. if a>32 then
  2950. internalerror(200308295);
  2951. if a<>0 then
  2952. begin
  2953. shifterop_reset(so);
  2954. so.shiftmode:=SM_ASR;
  2955. so.shiftimm:=a;
  2956. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  2957. end
  2958. else
  2959. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  2960. end;
  2961. else
  2962. if (op in [OP_SUB, OP_ADD]) and
  2963. ((a < 0) or
  2964. (a > 4095)) then
  2965. begin
  2966. tmpreg:=getintregister(list,size);
  2967. a_load_const_reg(list, size, a, tmpreg);
  2968. list.concat(setoppostfix(taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src,tmpreg),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  2969. ));
  2970. end
  2971. else
  2972. list.concat(setoppostfix(
  2973. taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  2974. ));
  2975. if (cgsetflags or setflags) and (size in [OS_8,OS_16,OS_32]) then
  2976. begin
  2977. ovloc.loc:=LOC_FLAGS;
  2978. case op of
  2979. OP_ADD:
  2980. ovloc.resflags:=F_CS;
  2981. OP_SUB:
  2982. ovloc.resflags:=F_CC;
  2983. end;
  2984. end;
  2985. end
  2986. else
  2987. begin
  2988. { there could be added some more sophisticated optimizations }
  2989. if (op in [OP_MUL,OP_IMUL]) and (a=1) then
  2990. a_load_reg_reg(list,size,size,src,dst)
  2991. else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
  2992. a_load_const_reg(list,size,0,dst)
  2993. else if (op in [OP_IMUL]) and (a=-1) then
  2994. a_op_reg_reg(list,OP_NEG,size,src,dst)
  2995. { we do this here instead in the peephole optimizer because
  2996. it saves us a register }
  2997. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) and not(cgsetflags or setflags) then
  2998. a_op_const_reg_reg(list,OP_SHL,size,l1,src,dst)
  2999. { for example : b=a*5 -> b=a*4+a with add instruction and shl }
  3000. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a-1,l1) and not(cgsetflags or setflags) then
  3001. begin
  3002. if l1>32 then{roozbeh does this ever happen?}
  3003. internalerror(200308296);
  3004. shifterop_reset(so);
  3005. so.shiftmode:=SM_LSL;
  3006. so.shiftimm:=l1;
  3007. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,dst,src,src,so));
  3008. end
  3009. else
  3010. begin
  3011. tmpreg:=getintregister(list,size);
  3012. a_load_const_reg(list,size,a,tmpreg);
  3013. a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,setflags,ovloc);
  3014. end;
  3015. end;
  3016. maybeadjustresult(list,op,size,dst);
  3017. end;
  3018. const
  3019. op_reg_reg_opcg2asmopThumb2: array[TOpCG] of tasmop =
  3020. (A_NONE,A_MOV,A_ADD,A_AND,A_UDIV,A_SDIV,A_MUL,A_MUL,A_NONE,A_MVN,A_ORR,
  3021. A_ASR,A_LSL,A_LSR,A_SUB,A_EOR,A_NONE,A_ROR);
  3022. procedure Tthumb2cgarm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);
  3023. var
  3024. so : tshifterop;
  3025. tmpreg,overflowreg : tregister;
  3026. asmop : tasmop;
  3027. begin
  3028. ovloc.loc:=LOC_VOID;
  3029. case op of
  3030. OP_NEG,OP_NOT:
  3031. internalerror(200308281);
  3032. OP_ROL:
  3033. begin
  3034. if not(size in [OS_32,OS_S32]) then
  3035. internalerror(2008072801);
  3036. { simulate ROL by ror'ing 32-value }
  3037. tmpreg:=getintregister(list,OS_32);
  3038. list.concat(taicpu.op_reg_const(A_MOV,tmpreg,32));
  3039. list.concat(taicpu.op_reg_reg_reg(A_SUB,src1,tmpreg,src1));
  3040. list.concat(taicpu.op_reg_reg_reg(A_ROR, dst, src2, src1));
  3041. end;
  3042. OP_ROR:
  3043. begin
  3044. if not(size in [OS_32,OS_S32]) then
  3045. internalerror(2008072802);
  3046. list.concat(taicpu.op_reg_reg_reg(A_ROR, dst, src2, src1));
  3047. end;
  3048. OP_IMUL,
  3049. OP_MUL:
  3050. begin
  3051. if cgsetflags or setflags then
  3052. begin
  3053. overflowreg:=getintregister(list,size);
  3054. if op=OP_IMUL then
  3055. asmop:=A_SMULL
  3056. else
  3057. asmop:=A_UMULL;
  3058. { the arm doesn't allow that rd and rm are the same }
  3059. if dst=src2 then
  3060. begin
  3061. if dst<>src1 then
  3062. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src1,src2))
  3063. else
  3064. begin
  3065. tmpreg:=getintregister(list,size);
  3066. a_load_reg_reg(list,size,size,src2,dst);
  3067. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,tmpreg,src1));
  3068. end;
  3069. end
  3070. else
  3071. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src2,src1));
  3072. if op=OP_IMUL then
  3073. begin
  3074. shifterop_reset(so);
  3075. so.shiftmode:=SM_ASR;
  3076. so.shiftimm:=31;
  3077. list.concat(taicpu.op_reg_reg_shifterop(A_CMP,overflowreg,dst,so));
  3078. end
  3079. else
  3080. list.concat(taicpu.op_reg_const(A_CMP,overflowreg,0));
  3081. ovloc.loc:=LOC_FLAGS;
  3082. ovloc.resflags:=F_NE;
  3083. end
  3084. else
  3085. begin
  3086. { the arm doesn't allow that rd and rm are the same }
  3087. if dst=src2 then
  3088. begin
  3089. if dst<>src1 then
  3090. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
  3091. else
  3092. begin
  3093. tmpreg:=getintregister(list,size);
  3094. a_load_reg_reg(list,size,size,src2,dst);
  3095. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,tmpreg,src1));
  3096. end;
  3097. end
  3098. else
  3099. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
  3100. end;
  3101. end;
  3102. else
  3103. list.concat(setoppostfix(
  3104. taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmopThumb2[op],dst,src2,src1),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  3105. ));
  3106. end;
  3107. maybeadjustresult(list,op,size,dst);
  3108. end;
  3109. procedure Tthumb2cgarm.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  3110. var item: taicpu;
  3111. begin
  3112. item := setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f));
  3113. list.concat(item);
  3114. list.insertbefore(taicpu.op_cond(A_IT, flags_to_cond(f)), item);
  3115. item := setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond(flags_to_cond(f)));
  3116. list.concat(item);
  3117. list.insertbefore(taicpu.op_cond(A_IT, inverse_cond(flags_to_cond(f))), item);
  3118. end;
  3119. procedure Tthumb2cgarm.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  3120. var
  3121. ref : treference;
  3122. shift : byte;
  3123. firstfloatreg,lastfloatreg,
  3124. r : byte;
  3125. regs : tcpuregisterset;
  3126. stackmisalignment: pint;
  3127. begin
  3128. LocalSize:=align(LocalSize,4);
  3129. { call instruction does not put anything on the stack }
  3130. stackmisalignment:=0;
  3131. if not(nostackframe) then
  3132. begin
  3133. firstfloatreg:=RS_NO;
  3134. { save floating point registers? }
  3135. for r:=RS_F0 to RS_F7 do
  3136. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  3137. begin
  3138. if firstfloatreg=RS_NO then
  3139. firstfloatreg:=r;
  3140. lastfloatreg:=r;
  3141. inc(stackmisalignment,12);
  3142. end;
  3143. a_reg_alloc(list,NR_STACK_POINTER_REG);
  3144. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  3145. begin
  3146. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  3147. a_reg_alloc(list,NR_R12);
  3148. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  3149. end;
  3150. { save int registers }
  3151. reference_reset(ref,4);
  3152. ref.index:=NR_STACK_POINTER_REG;
  3153. ref.addressmode:=AM_PREINDEXED;
  3154. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  3155. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  3156. regs:=regs+[RS_FRAME_POINTER_REG,RS_R14]
  3157. else if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
  3158. include(regs,RS_R14);
  3159. if regs<>[] then
  3160. begin
  3161. for r:=RS_R0 to RS_R15 do
  3162. if (r in regs) then
  3163. inc(stackmisalignment,4);
  3164. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,R_INTREGISTER,R_SUBWHOLE,regs),PF_FD));
  3165. end;
  3166. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  3167. begin
  3168. { the framepointer now points to the saved R15, so the saved
  3169. framepointer is at R11-12 (for get_caller_frame) }
  3170. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  3171. a_reg_dealloc(list,NR_R12);
  3172. end;
  3173. stackmisalignment:=stackmisalignment mod current_settings.alignment.localalignmax;
  3174. if (LocalSize<>0) or
  3175. ((stackmisalignment<>0) and
  3176. ((pi_do_call in current_procinfo.flags) or
  3177. (po_assembler in current_procinfo.procdef.procoptions))) then
  3178. begin
  3179. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  3180. if not(is_shifter_const(localsize,shift)) then
  3181. begin
  3182. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  3183. a_reg_alloc(list,NR_R12);
  3184. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  3185. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  3186. a_reg_dealloc(list,NR_R12);
  3187. end
  3188. else
  3189. begin
  3190. a_reg_dealloc(list,NR_R12);
  3191. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  3192. end;
  3193. end;
  3194. if firstfloatreg<>RS_NO then
  3195. begin
  3196. reference_reset(ref,4);
  3197. if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
  3198. begin
  3199. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  3200. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  3201. ref.base:=NR_R12;
  3202. end
  3203. else
  3204. begin
  3205. ref.base:=current_procinfo.framepointer;
  3206. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  3207. end;
  3208. list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  3209. lastfloatreg-firstfloatreg+1,ref));
  3210. end;
  3211. end;
  3212. end;
  3213. procedure Tthumb2cgarm.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  3214. var
  3215. ref : treference;
  3216. firstfloatreg,lastfloatreg,
  3217. r : byte;
  3218. shift : byte;
  3219. regs : tcpuregisterset;
  3220. LocalSize : longint;
  3221. stackmisalignment: pint;
  3222. begin
  3223. if not(nostackframe) then
  3224. begin
  3225. stackmisalignment:=0;
  3226. { restore floating point register }
  3227. firstfloatreg:=RS_NO;
  3228. { save floating point registers? }
  3229. for r:=RS_F0 to RS_F7 do
  3230. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  3231. begin
  3232. if firstfloatreg=RS_NO then
  3233. firstfloatreg:=r;
  3234. lastfloatreg:=r;
  3235. { floating point register space is already included in
  3236. localsize below by calc_stackframe_size
  3237. inc(stackmisalignment,12);
  3238. }
  3239. end;
  3240. if firstfloatreg<>RS_NO then
  3241. begin
  3242. reference_reset(ref,4);
  3243. if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
  3244. begin
  3245. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  3246. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  3247. ref.base:=NR_R12;
  3248. end
  3249. else
  3250. begin
  3251. ref.base:=current_procinfo.framepointer;
  3252. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  3253. end;
  3254. list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  3255. lastfloatreg-firstfloatreg+1,ref));
  3256. end;
  3257. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  3258. if (pi_do_call in current_procinfo.flags) or (regs<>[]) then
  3259. begin
  3260. exclude(regs,RS_R14);
  3261. include(regs,RS_R15);
  3262. end;
  3263. if (current_procinfo.framepointer<>NR_STACK_POINTER_REG) then
  3264. regs:=regs+[RS_FRAME_POINTER_REG,RS_R15];
  3265. for r:=RS_R0 to RS_R15 do
  3266. if (r in regs) then
  3267. inc(stackmisalignment,4);
  3268. stackmisalignment:=stackmisalignment mod current_settings.alignment.localalignmax;
  3269. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  3270. begin
  3271. LocalSize:=current_procinfo.calc_stackframe_size;
  3272. if (LocalSize<>0) or
  3273. ((stackmisalignment<>0) and
  3274. ((pi_do_call in current_procinfo.flags) or
  3275. (po_assembler in current_procinfo.procdef.procoptions))) then
  3276. begin
  3277. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  3278. if not(is_shifter_const(LocalSize,shift)) then
  3279. begin
  3280. a_reg_alloc(list,NR_R12);
  3281. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  3282. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  3283. a_reg_dealloc(list,NR_R12);
  3284. end
  3285. else
  3286. begin
  3287. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  3288. end;
  3289. end;
  3290. if regs=[] then
  3291. list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
  3292. else
  3293. begin
  3294. reference_reset(ref,4);
  3295. ref.index:=NR_STACK_POINTER_REG;
  3296. ref.addressmode:=AM_PREINDEXED;
  3297. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,R_INTREGISTER,R_SUBWHOLE,regs),PF_FD));
  3298. end;
  3299. end
  3300. else
  3301. begin
  3302. { restore int registers and return }
  3303. list.concat(taicpu.op_reg_reg(A_MOV, NR_STACK_POINTER_REG, NR_FRAME_POINTER_REG));
  3304. { Add 4 to SP to make it point to an "imaginary PC" which the paramanager assumes is there(for normal ARM) }
  3305. list.concat(taicpu.op_reg_const(A_ADD, NR_STACK_POINTER_REG, 4));
  3306. reference_reset(ref,4);
  3307. ref.index:=NR_STACK_POINTER_REG;
  3308. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,R_INTREGISTER,R_SUBWHOLE,regs),PF_DB));
  3309. end;
  3310. end
  3311. else
  3312. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14));
  3313. end;
  3314. function Tthumb2cgarm.handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference;
  3315. var
  3316. tmpreg : tregister;
  3317. tmpref : treference;
  3318. l : tasmlabel;
  3319. so: tshifterop;
  3320. begin
  3321. tmpreg:=NR_NO;
  3322. { Be sure to have a base register }
  3323. if (ref.base=NR_NO) then
  3324. begin
  3325. if ref.shiftmode<>SM_None then
  3326. internalerror(200308294);
  3327. ref.base:=ref.index;
  3328. ref.index:=NR_NO;
  3329. end;
  3330. { absolute symbols can't be handled directly, we've to store the symbol reference
  3331. in the text segment and access it pc relative
  3332. For now, we assume that references where base or index equals to PC are already
  3333. relative, all other references are assumed to be absolute and thus they need
  3334. to be handled extra.
  3335. A proper solution would be to change refoptions to a set and store the information
  3336. if the symbol is absolute or relative there.
  3337. }
  3338. if (assigned(ref.symbol) and
  3339. not(is_pc(ref.base)) and
  3340. not(is_pc(ref.index))
  3341. ) or
  3342. { [#xxx] isn't a valid address operand }
  3343. ((ref.base=NR_NO) and (ref.index=NR_NO)) or
  3344. //(ref.offset<-4095) or
  3345. (ref.offset<-255) or
  3346. (ref.offset>4095) or
  3347. ((oppostfix in [PF_SB,PF_H,PF_SH]) and
  3348. ((ref.offset<-255) or
  3349. (ref.offset>255)
  3350. )
  3351. ) or
  3352. ((op in [A_LDF,A_STF,A_FLDS,A_FLDD,A_FSTS,A_FSTD]) and
  3353. ((ref.offset<-1020) or
  3354. (ref.offset>1020) or
  3355. { the usual pc relative symbol handling assumes possible offsets of +/- 4095 }
  3356. assigned(ref.symbol)
  3357. )
  3358. ) then
  3359. begin
  3360. reference_reset(tmpref,4);
  3361. { load symbol }
  3362. tmpreg:=getintregister(list,OS_INT);
  3363. if assigned(ref.symbol) then
  3364. begin
  3365. current_asmdata.getjumplabel(l);
  3366. cg.a_label(current_procinfo.aktlocaldata,l);
  3367. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  3368. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset));
  3369. { load consts entry }
  3370. tmpref.symbol:=l;
  3371. tmpref.base:=NR_R15;
  3372. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  3373. { in case of LDF/STF, we got rid of the NR_R15 }
  3374. if is_pc(ref.base) then
  3375. ref.base:=NR_NO;
  3376. if is_pc(ref.index) then
  3377. ref.index:=NR_NO;
  3378. end
  3379. else
  3380. a_load_const_reg(list,OS_ADDR,ref.offset,tmpreg);
  3381. if (ref.base<>NR_NO) then
  3382. begin
  3383. if ref.index<>NR_NO then
  3384. begin
  3385. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  3386. ref.base:=tmpreg;
  3387. end
  3388. else
  3389. begin
  3390. ref.index:=tmpreg;
  3391. ref.shiftimm:=0;
  3392. ref.signindex:=1;
  3393. ref.shiftmode:=SM_None;
  3394. end;
  3395. end
  3396. else
  3397. ref.base:=tmpreg;
  3398. ref.offset:=0;
  3399. ref.symbol:=nil;
  3400. end;
  3401. if (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then
  3402. begin
  3403. if tmpreg<>NR_NO then
  3404. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg,tmpreg)
  3405. else
  3406. begin
  3407. tmpreg:=getintregister(list,OS_ADDR);
  3408. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg);
  3409. ref.base:=tmpreg;
  3410. end;
  3411. ref.offset:=0;
  3412. end;
  3413. { Hack? Thumb2 doesn't allow PC indexed addressing modes(although it does in the specification) }
  3414. if (ref.base=NR_R15) and (ref.index<>NR_NO) and (ref.shiftmode <> sm_none) then
  3415. begin
  3416. tmpreg:=getintregister(list,OS_ADDR);
  3417. list.concat(taicpu.op_reg_reg(A_MOV, tmpreg, NR_R15));
  3418. ref.base := tmpreg;
  3419. end;
  3420. { floating point operations have only limited references
  3421. we expect here, that a base is already set }
  3422. if (op in [A_LDF,A_STF,A_FLDS,A_FLDD,A_FSTS,A_FSTD]) and (ref.index<>NR_NO) then
  3423. begin
  3424. if ref.shiftmode<>SM_none then
  3425. internalerror(200309121);
  3426. if tmpreg<>NR_NO then
  3427. begin
  3428. if ref.base=tmpreg then
  3429. begin
  3430. if ref.signindex<0 then
  3431. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,tmpreg,ref.index))
  3432. else
  3433. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg,ref.index));
  3434. ref.index:=NR_NO;
  3435. end
  3436. else
  3437. begin
  3438. if ref.index<>tmpreg then
  3439. internalerror(200403161);
  3440. if ref.signindex<0 then
  3441. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,ref.base,tmpreg))
  3442. else
  3443. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  3444. ref.base:=tmpreg;
  3445. ref.index:=NR_NO;
  3446. end;
  3447. end
  3448. else
  3449. begin
  3450. tmpreg:=getintregister(list,OS_ADDR);
  3451. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
  3452. ref.base:=tmpreg;
  3453. ref.index:=NR_NO;
  3454. end;
  3455. end;
  3456. list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
  3457. Result := ref;
  3458. end;
  3459. procedure tthumb2cg64farm.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  3460. var tmpreg: tregister;
  3461. begin
  3462. case op of
  3463. OP_NEG:
  3464. begin
  3465. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  3466. tmpreg:=cg.getintregister(list,OS_32);
  3467. list.concat(taicpu.op_reg_const(A_MOV,tmpreg,0));
  3468. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,tmpreg,regsrc.reghi));
  3469. end;
  3470. else
  3471. inherited a_op64_reg_reg(list, op, size, regsrc, regdst);
  3472. end;
  3473. end;
  3474. procedure create_codegen;
  3475. begin
  3476. if current_settings.cputype in cpu_thumb2 then
  3477. begin
  3478. cg:=tthumb2cgarm.create;
  3479. cg64:=tthumb2cg64farm.create;
  3480. casmoptimizer:=TCpuThumb2AsmOptimizer;
  3481. end
  3482. else
  3483. begin
  3484. cg:=tarmcgarm.create;
  3485. cg64:=tcg64farm.create;
  3486. casmoptimizer:=TCpuAsmOptimizer;
  3487. end;
  3488. end;
  3489. end.