cgcpu.pas 215 KB

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