cgcpu.pas 204 KB

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