cgcpu.pas 165 KB

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