cgcpu.pas 144 KB

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