cgcpu.pas 148 KB

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