cgcpu.pas 158 KB

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