cgcpu.pas 213 KB

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