cgcpu.pas 149 KB

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