cgcpu.pas 143 KB

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