cgcpu.pas 144 KB

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