cgcpu.pas 216 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403
  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. list.concat(taicpu.op_reg_reg(A_MOV,NR_R0,NR_R12));
  2938. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R0);
  2939. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_R0));
  2940. list.concat(taicpu.op_regset(A_POP,R_INTREGISTER,R_SUBWHOLE,[RS_R0]));
  2941. end
  2942. else
  2943. begin
  2944. list.concat(taicpu.op_regset(A_PUSH,R_INTREGISTER,R_SUBWHOLE,[RS_R0,RS_R1]));
  2945. { create consts entry }
  2946. reference_reset(tmpref,4);
  2947. current_asmdata.getjumplabel(l);
  2948. current_procinfo.aktlocaldata.Concat(tai_align.Create(4));
  2949. cg.a_label(current_procinfo.aktlocaldata,l);
  2950. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  2951. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(href.offset));
  2952. tmpref.symbol:=l;
  2953. tmpref.base:=NR_PC;
  2954. list.concat(taicpu.op_reg_ref(A_LDR,NR_R1,tmpref));
  2955. list.concat(taicpu.op_reg_reg(A_MOV,NR_R0,NR_R12));
  2956. href.offset:=0;
  2957. href.base:=NR_R0;
  2958. href.index:=NR_R1;
  2959. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R0);
  2960. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_R0));
  2961. list.concat(taicpu.op_regset(A_POP,R_INTREGISTER,R_SUBWHOLE,[RS_R0,RS_R1]));
  2962. end;
  2963. end
  2964. else
  2965. begin
  2966. reference_reset_base(href,NR_R12,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),sizeof(pint));
  2967. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  2968. end;
  2969. list.concat(taicpu.op_reg(A_BX,NR_R12));
  2970. end;
  2971. var
  2972. make_global : boolean;
  2973. tmpref : treference;
  2974. l : TAsmLabel;
  2975. begin
  2976. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  2977. Internalerror(200006137);
  2978. if not assigned(procdef.struct) or
  2979. (procdef.procoptions*[po_classmethod, po_staticmethod,
  2980. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  2981. Internalerror(200006138);
  2982. if procdef.owner.symtabletype<>ObjectSymtable then
  2983. Internalerror(200109191);
  2984. if GenerateThumbCode or GenerateThumb2Code then
  2985. list.concat(tai_thumb_func.create);
  2986. make_global:=false;
  2987. if (not current_module.is_unit) or
  2988. create_smartlink or
  2989. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  2990. make_global:=true;
  2991. if make_global then
  2992. list.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  2993. else
  2994. list.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  2995. { the wrapper might need aktlocaldata for the additional data to
  2996. load the constant }
  2997. current_procinfo:=cprocinfo.create(nil);
  2998. { set param1 interface to self }
  2999. g_adjust_self_value(list,procdef,ioffset);
  3000. { case 4 }
  3001. if (po_virtualmethod in procdef.procoptions) and
  3002. not is_objectpascal_helper(procdef.struct) then
  3003. begin
  3004. loadvmttor12;
  3005. op_onr12methodaddr;
  3006. end
  3007. { case 0 }
  3008. else if GenerateThumbCode then
  3009. begin
  3010. { bl cannot be used here because it destroys lr }
  3011. list.concat(taicpu.op_regset(A_PUSH,R_INTREGISTER,R_SUBWHOLE,[RS_R0]));
  3012. { create consts entry }
  3013. reference_reset(tmpref,4);
  3014. current_asmdata.getjumplabel(l);
  3015. current_procinfo.aktlocaldata.Concat(tai_align.Create(4));
  3016. cg.a_label(current_procinfo.aktlocaldata,l);
  3017. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  3018. current_procinfo.aktlocaldata.concat(tai_const.Create_sym(current_asmdata.RefAsmSymbol(procdef.mangledname)));
  3019. tmpref.symbol:=l;
  3020. tmpref.base:=NR_PC;
  3021. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,tmpref,NR_R0);
  3022. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_R0));
  3023. list.concat(taicpu.op_regset(A_POP,R_INTREGISTER,R_SUBWHOLE,[RS_R0]));
  3024. list.concat(taicpu.op_reg(A_BX,NR_R12));
  3025. end
  3026. else
  3027. list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname)));
  3028. list.concatlist(current_procinfo.aktlocaldata);
  3029. current_procinfo.Free;
  3030. current_procinfo:=nil;
  3031. list.concat(Tai_symbol_end.Createname(labelname));
  3032. end;
  3033. procedure tbasecgarm.maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  3034. const
  3035. overflowops = [OP_MUL,OP_SHL,OP_ADD,OP_SUB,OP_NEG];
  3036. begin
  3037. if (op in overflowops) and
  3038. (size in [OS_8,OS_S8,OS_16,OS_S16]) then
  3039. a_load_reg_reg(list,OS_32,size,dst,dst);
  3040. end;
  3041. procedure tbasecgarm.safe_mla(list : TAsmList; op1,op2,op3,op4 : TRegister);
  3042. procedure checkreg(var reg : TRegister);
  3043. var
  3044. tmpreg : TRegister;
  3045. begin
  3046. if ((GenerateThumbCode or GenerateThumb2Code) and (getsupreg(reg)=RS_R13)) or
  3047. (getsupreg(reg)=RS_R15) then
  3048. begin
  3049. tmpreg:=getintregister(list,OS_INT);
  3050. a_load_reg_reg(list,OS_INT,OS_INT,reg,tmpreg);
  3051. reg:=tmpreg;
  3052. end;
  3053. end;
  3054. begin
  3055. checkreg(op1);
  3056. checkreg(op2);
  3057. checkreg(op3);
  3058. checkreg(op4);
  3059. list.concat(taicpu.op_reg_reg_reg_reg(A_MLA,op1,op2,op3,op4));
  3060. end;
  3061. procedure tcg64farm.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  3062. begin
  3063. case op of
  3064. OP_NEG:
  3065. begin
  3066. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3067. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  3068. list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
  3069. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  3070. end;
  3071. OP_NOT:
  3072. begin
  3073. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  3074. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  3075. end;
  3076. else
  3077. a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
  3078. end;
  3079. end;
  3080. procedure tcg64farm.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  3081. begin
  3082. a_op64_const_reg_reg(list,op,size,value,reg,reg);
  3083. end;
  3084. procedure tcg64farm.a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);
  3085. var
  3086. ovloc : tlocation;
  3087. begin
  3088. a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,ovloc);
  3089. end;
  3090. procedure tcg64farm.a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
  3091. var
  3092. ovloc : tlocation;
  3093. begin
  3094. a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,ovloc);
  3095. end;
  3096. procedure tcg64farm.a_loadmm_intreg64_reg(list: TAsmList; mmsize: tcgsize; intreg: tregister64; mmreg: tregister);
  3097. begin
  3098. { this code can only be used to transfer raw data, not to perform
  3099. conversions }
  3100. if (mmsize<>OS_F64) then
  3101. internalerror(2009112405);
  3102. list.concat(taicpu.op_reg_reg_reg(A_FMDRR,mmreg,intreg.reglo,intreg.reghi));
  3103. end;
  3104. procedure tcg64farm.a_loadmm_reg_intreg64(list: TAsmList; mmsize: tcgsize; mmreg: tregister; intreg: tregister64);
  3105. begin
  3106. { this code can only be used to transfer raw data, not to perform
  3107. conversions }
  3108. if (mmsize<>OS_F64) then
  3109. internalerror(2009112406);
  3110. list.concat(taicpu.op_reg_reg_reg(A_FMRRD,intreg.reglo,intreg.reghi,mmreg));
  3111. end;
  3112. procedure tcg64farm.a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  3113. var
  3114. tmpreg : tregister;
  3115. b : byte;
  3116. begin
  3117. ovloc.loc:=LOC_VOID;
  3118. case op of
  3119. OP_NEG,
  3120. OP_NOT :
  3121. internalerror(2012022501);
  3122. end;
  3123. if (setflags or tbasecgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  3124. begin
  3125. case op of
  3126. OP_ADD:
  3127. begin
  3128. if is_shifter_const(lo(value),b) then
  3129. begin
  3130. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3131. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  3132. end
  3133. else
  3134. begin
  3135. tmpreg:=cg.getintregister(list,OS_32);
  3136. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  3137. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3138. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  3139. end;
  3140. if is_shifter_const(hi(value),b) then
  3141. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  3142. else
  3143. begin
  3144. tmpreg:=cg.getintregister(list,OS_32);
  3145. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  3146. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  3147. end;
  3148. end;
  3149. OP_SUB:
  3150. begin
  3151. if is_shifter_const(lo(value),b) then
  3152. begin
  3153. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3154. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  3155. end
  3156. else
  3157. begin
  3158. tmpreg:=cg.getintregister(list,OS_32);
  3159. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  3160. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3161. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  3162. end;
  3163. if is_shifter_const(hi(value),b) then
  3164. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))),PF_S))
  3165. else
  3166. begin
  3167. tmpreg:=cg.getintregister(list,OS_32);
  3168. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  3169. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  3170. end;
  3171. end;
  3172. else
  3173. internalerror(200502131);
  3174. end;
  3175. if size=OS_64 then
  3176. begin
  3177. { the arm has an weired opinion how flags for SUB/ADD are handled }
  3178. ovloc.loc:=LOC_FLAGS;
  3179. case op of
  3180. OP_ADD:
  3181. ovloc.resflags:=F_CS;
  3182. OP_SUB:
  3183. ovloc.resflags:=F_CC;
  3184. end;
  3185. end;
  3186. end
  3187. else
  3188. begin
  3189. case op of
  3190. OP_AND,OP_OR,OP_XOR:
  3191. begin
  3192. cg.a_op_const_reg_reg(list,op,OS_32,aint(lo(value)),regsrc.reglo,regdst.reglo);
  3193. cg.a_op_const_reg_reg(list,op,OS_32,aint(hi(value)),regsrc.reghi,regdst.reghi);
  3194. end;
  3195. OP_ADD:
  3196. begin
  3197. if is_shifter_const(aint(lo(value)),b) then
  3198. begin
  3199. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3200. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
  3201. end
  3202. else
  3203. begin
  3204. tmpreg:=cg.getintregister(list,OS_32);
  3205. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  3206. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3207. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  3208. end;
  3209. if is_shifter_const(aint(hi(value)),b) then
  3210. list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,aint(hi(value))))
  3211. else
  3212. begin
  3213. tmpreg:=cg.getintregister(list,OS_32);
  3214. cg.a_load_const_reg(list,OS_32,aint(hi(value)),tmpreg);
  3215. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
  3216. end;
  3217. end;
  3218. OP_SUB:
  3219. begin
  3220. if is_shifter_const(aint(lo(value)),b) then
  3221. begin
  3222. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3223. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
  3224. end
  3225. else
  3226. begin
  3227. tmpreg:=cg.getintregister(list,OS_32);
  3228. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  3229. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3230. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  3231. end;
  3232. if is_shifter_const(aint(hi(value)),b) then
  3233. list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))))
  3234. else
  3235. begin
  3236. tmpreg:=cg.getintregister(list,OS_32);
  3237. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  3238. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
  3239. end;
  3240. end;
  3241. else
  3242. internalerror(2003083101);
  3243. end;
  3244. end;
  3245. end;
  3246. procedure tcg64farm.a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  3247. begin
  3248. ovloc.loc:=LOC_VOID;
  3249. case op of
  3250. OP_NEG,
  3251. OP_NOT :
  3252. internalerror(2012022502);
  3253. end;
  3254. if (setflags or tbasecgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  3255. begin
  3256. case op of
  3257. OP_ADD:
  3258. begin
  3259. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3260. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  3261. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi),PF_S));
  3262. end;
  3263. OP_SUB:
  3264. begin
  3265. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3266. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  3267. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi),PF_S));
  3268. end;
  3269. else
  3270. internalerror(2003083101);
  3271. end;
  3272. if size=OS_64 then
  3273. begin
  3274. { the arm has an weired opinion how flags for SUB/ADD are handled }
  3275. ovloc.loc:=LOC_FLAGS;
  3276. case op of
  3277. OP_ADD:
  3278. ovloc.resflags:=F_CS;
  3279. OP_SUB:
  3280. ovloc.resflags:=F_CC;
  3281. end;
  3282. end;
  3283. end
  3284. else
  3285. begin
  3286. case op of
  3287. OP_AND,OP_OR,OP_XOR:
  3288. begin
  3289. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  3290. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  3291. end;
  3292. OP_ADD:
  3293. begin
  3294. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3295. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  3296. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  3297. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  3298. end;
  3299. OP_SUB:
  3300. begin
  3301. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  3302. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  3303. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
  3304. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  3305. end;
  3306. else
  3307. internalerror(2003083101);
  3308. end;
  3309. end;
  3310. end;
  3311. procedure tthumbcgarm.init_register_allocators;
  3312. begin
  3313. inherited init_register_allocators;
  3314. if assigned(current_procinfo) and (current_procinfo.framepointer=NR_R7) then
  3315. rg[R_INTREGISTER]:=trgintcputhumb.create(R_INTREGISTER,R_SUBWHOLE,
  3316. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6],first_int_imreg,[])
  3317. else
  3318. rg[R_INTREGISTER]:=trgintcputhumb.create(R_INTREGISTER,R_SUBWHOLE,
  3319. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7],first_int_imreg,[]);
  3320. end;
  3321. procedure tthumbcgarm.done_register_allocators;
  3322. begin
  3323. rg[R_INTREGISTER].free;
  3324. rg[R_FPUREGISTER].free;
  3325. rg[R_MMREGISTER].free;
  3326. inherited done_register_allocators;
  3327. end;
  3328. procedure tthumbcgarm.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  3329. var
  3330. ref : treference;
  3331. shift : byte;
  3332. r : byte;
  3333. regs, saveregs : tcpuregisterset;
  3334. r7offset,
  3335. stackmisalignment : pint;
  3336. postfix: toppostfix;
  3337. registerarea,
  3338. imm1, imm2: DWord;
  3339. stack_parameters: Boolean;
  3340. begin
  3341. stack_parameters:=current_procinfo.procdef.stack_tainting_parameter(calleeside);
  3342. LocalSize:=align(LocalSize,4);
  3343. { call instruction does not put anything on the stack }
  3344. stackmisalignment:=0;
  3345. if not(nostackframe) then
  3346. begin
  3347. a_reg_alloc(list,NR_STACK_POINTER_REG);
  3348. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  3349. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  3350. { save int registers }
  3351. reference_reset(ref,4);
  3352. ref.index:=NR_STACK_POINTER_REG;
  3353. ref.addressmode:=AM_PREINDEXED;
  3354. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  3355. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  3356. begin
  3357. //!!!! a_reg_alloc(list,NR_R12);
  3358. //!!!! list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  3359. end;
  3360. { the (old) ARM APCS requires saving both the stack pointer (to
  3361. crawl the stack) and the PC (to identify the function this
  3362. stack frame belongs to) -> also save R12 (= copy of R13 on entry)
  3363. and R15 -- still needs updating for EABI and Darwin, they don't
  3364. need that }
  3365. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  3366. regs:=regs+[RS_R7,RS_R14]
  3367. else
  3368. // if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
  3369. include(regs,RS_R14);
  3370. { safely estimate stack size }
  3371. if localsize+current_settings.alignment.localalignmax+4>508 then
  3372. begin
  3373. include(rg[R_INTREGISTER].used_in_proc,RS_R4);
  3374. include(regs,RS_R4);
  3375. end;
  3376. registerarea:=0;
  3377. if regs<>[] then
  3378. begin
  3379. for r:=RS_R0 to RS_R15 do
  3380. if r in regs then
  3381. inc(registerarea,4);
  3382. list.concat(taicpu.op_regset(A_PUSH,R_INTREGISTER,R_SUBWHOLE,regs));
  3383. end;
  3384. stackmisalignment:=registerarea mod current_settings.alignment.localalignmax;
  3385. if stack_parameters or (LocalSize<>0) or
  3386. ((stackmisalignment<>0) and
  3387. ((pi_do_call in current_procinfo.flags) or
  3388. (po_assembler in current_procinfo.procdef.procoptions))) then
  3389. begin
  3390. { do we access stack parameters?
  3391. if yes, the previously estimated stacksize must be used }
  3392. if stack_parameters then
  3393. begin
  3394. if localsize>tarmprocinfo(current_procinfo).stackframesize then
  3395. begin
  3396. writeln(localsize);
  3397. writeln(tarmprocinfo(current_procinfo).stackframesize);
  3398. internalerror(2013040601);
  3399. end
  3400. else
  3401. localsize:=tarmprocinfo(current_procinfo).stackframesize-registerarea;
  3402. end
  3403. else
  3404. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  3405. if localsize<508 then
  3406. begin
  3407. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  3408. end
  3409. else if localsize<=1016 then
  3410. begin
  3411. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,508));
  3412. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize-508));
  3413. end
  3414. else
  3415. begin
  3416. a_load_const_reg(list,OS_ADDR,-localsize,NR_R4);
  3417. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R4));
  3418. include(regs,RS_R4);
  3419. //!!!! if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  3420. //!!!! a_reg_alloc(list,NR_R12);
  3421. //!!!! a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  3422. //!!!! list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  3423. //!!!! a_reg_dealloc(list,NR_R12);
  3424. end;
  3425. end;
  3426. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  3427. begin
  3428. list.concat(taicpu.op_reg_reg_const(A_ADD,current_procinfo.framepointer,NR_STACK_POINTER_REG,0));
  3429. end;
  3430. end;
  3431. end;
  3432. procedure tthumbcgarm.g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean);
  3433. var
  3434. ref : treference;
  3435. LocalSize : longint;
  3436. r,
  3437. shift : byte;
  3438. saveregs,
  3439. regs : tcpuregisterset;
  3440. registerarea : DWord;
  3441. stackmisalignment: pint;
  3442. imm1, imm2: DWord;
  3443. stack_parameters : Boolean;
  3444. begin
  3445. if not(nostackframe) then
  3446. begin
  3447. stack_parameters:=current_procinfo.procdef.stack_tainting_parameter(calleeside);
  3448. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  3449. include(regs,RS_R15);
  3450. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  3451. include(regs,getsupreg(current_procinfo.framepointer));
  3452. registerarea:=0;
  3453. for r:=RS_R0 to RS_R15 do
  3454. if r in regs then
  3455. inc(registerarea,4);
  3456. stackmisalignment:=registerarea mod current_settings.alignment.localalignmax;
  3457. LocalSize:=current_procinfo.calc_stackframe_size;
  3458. if stack_parameters then
  3459. localsize:=tarmprocinfo(current_procinfo).stackframesize-registerarea
  3460. else
  3461. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  3462. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) or
  3463. (target_info.system in systems_darwin) then
  3464. begin
  3465. if (LocalSize<>0) or
  3466. ((stackmisalignment<>0) and
  3467. ((pi_do_call in current_procinfo.flags) or
  3468. (po_assembler in current_procinfo.procdef.procoptions))) then
  3469. begin
  3470. if LocalSize=0 then
  3471. else if LocalSize<=508 then
  3472. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize))
  3473. else if LocalSize<=1016 then
  3474. begin
  3475. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,508));
  3476. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize-508));
  3477. end
  3478. else
  3479. begin
  3480. a_reg_alloc(list,NR_R3);
  3481. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R3);
  3482. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R3));
  3483. a_reg_dealloc(list,NR_R3);
  3484. end;
  3485. end;
  3486. if regs=[] then
  3487. begin
  3488. if not(CPUARM_HAS_BX in cpu_capabilities[current_settings.cputype]) then
  3489. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14))
  3490. else
  3491. list.concat(taicpu.op_reg(A_BX,NR_R14))
  3492. end
  3493. else
  3494. list.concat(taicpu.op_regset(A_POP,R_INTREGISTER,R_SUBWHOLE,regs));
  3495. end;
  3496. end
  3497. else if not(CPUARM_HAS_BX in cpu_capabilities[current_settings.cputype]) then
  3498. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14))
  3499. else
  3500. list.concat(taicpu.op_reg(A_BX,NR_R14))
  3501. end;
  3502. procedure tthumbcgarm.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  3503. var
  3504. oppostfix:toppostfix;
  3505. usedtmpref: treference;
  3506. tmpreg,tmpreg2 : tregister;
  3507. dir : integer;
  3508. begin
  3509. if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then
  3510. FromSize := ToSize;
  3511. case FromSize of
  3512. { signed integer registers }
  3513. OS_8:
  3514. oppostfix:=PF_B;
  3515. OS_S8:
  3516. oppostfix:=PF_SB;
  3517. OS_16:
  3518. oppostfix:=PF_H;
  3519. OS_S16:
  3520. oppostfix:=PF_SH;
  3521. OS_32,
  3522. OS_S32:
  3523. oppostfix:=PF_None;
  3524. else
  3525. InternalError(200308298);
  3526. end;
  3527. if (ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[fromsize]) then
  3528. begin
  3529. if target_info.endian=endian_big then
  3530. dir:=-1
  3531. else
  3532. dir:=1;
  3533. case FromSize of
  3534. OS_16,OS_S16:
  3535. begin
  3536. { only complicated references need an extra loadaddr }
  3537. if assigned(ref.symbol) or
  3538. (ref.index<>NR_NO) or
  3539. (ref.offset<-124) or
  3540. (ref.offset>124) or
  3541. { sometimes the compiler reused registers }
  3542. (reg=ref.index) or
  3543. (reg=ref.base) then
  3544. begin
  3545. tmpreg2:=getintregister(list,OS_INT);
  3546. a_loadaddr_ref_reg(list,ref,tmpreg2);
  3547. reference_reset_base(usedtmpref,tmpreg2,0,ref.alignment);
  3548. end
  3549. else
  3550. usedtmpref:=ref;
  3551. if target_info.endian=endian_big then
  3552. inc(usedtmpref.offset,1);
  3553. tmpreg:=getintregister(list,OS_INT);
  3554. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  3555. inc(usedtmpref.offset,dir);
  3556. if FromSize=OS_16 then
  3557. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg)
  3558. else
  3559. a_internal_load_ref_reg(list,OS_S8,OS_S8,usedtmpref,tmpreg);
  3560. list.concat(taicpu.op_reg_const(A_LSL,tmpreg,8));
  3561. list.concat(taicpu.op_reg_reg(A_ORR,reg,tmpreg));
  3562. end;
  3563. OS_32,OS_S32:
  3564. begin
  3565. tmpreg:=getintregister(list,OS_INT);
  3566. { only complicated references need an extra loadaddr }
  3567. if assigned(ref.symbol) or
  3568. (ref.index<>NR_NO) or
  3569. (ref.offset<-124) or
  3570. (ref.offset>124) or
  3571. { sometimes the compiler reused registers }
  3572. (reg=ref.index) or
  3573. (reg=ref.base) then
  3574. begin
  3575. tmpreg2:=getintregister(list,OS_INT);
  3576. a_loadaddr_ref_reg(list,ref,tmpreg2);
  3577. reference_reset_base(usedtmpref,tmpreg2,0,ref.alignment);
  3578. end
  3579. else
  3580. usedtmpref:=ref;
  3581. if ref.alignment=2 then
  3582. begin
  3583. if target_info.endian=endian_big then
  3584. inc(usedtmpref.offset,2);
  3585. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,reg);
  3586. inc(usedtmpref.offset,dir*2);
  3587. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,tmpreg);
  3588. list.concat(taicpu.op_reg_const(A_LSL,tmpreg,16));
  3589. list.concat(taicpu.op_reg_reg(A_ORR,reg,tmpreg));
  3590. end
  3591. else
  3592. begin
  3593. if target_info.endian=endian_big then
  3594. inc(usedtmpref.offset,3);
  3595. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  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,8));
  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,16));
  3603. list.concat(taicpu.op_reg_reg(A_ORR,reg,tmpreg));
  3604. inc(usedtmpref.offset,dir);
  3605. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  3606. list.concat(taicpu.op_reg_const(A_LSL,tmpreg,24));
  3607. list.concat(taicpu.op_reg_reg(A_ORR,reg,tmpreg));
  3608. end;
  3609. end
  3610. else
  3611. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  3612. end;
  3613. end
  3614. else
  3615. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  3616. if (fromsize=OS_S8) and (tosize = OS_16) then
  3617. a_load_reg_reg(list,OS_16,OS_32,reg,reg);
  3618. end;
  3619. procedure tthumbcgarm.a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);
  3620. var
  3621. imm_shift : byte;
  3622. l : tasmlabel;
  3623. hr : treference;
  3624. begin
  3625. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  3626. internalerror(2002090902);
  3627. if is_thumb_imm(a) then
  3628. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  3629. else
  3630. begin
  3631. reference_reset(hr,4);
  3632. current_asmdata.getjumplabel(l);
  3633. cg.a_label(current_procinfo.aktlocaldata,l);
  3634. hr.symboldata:=current_procinfo.aktlocaldata.last;
  3635. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
  3636. hr.symbol:=l;
  3637. hr.base:=NR_PC;
  3638. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  3639. end;
  3640. end;
  3641. procedure tthumbcgarm.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);
  3642. var
  3643. hsym : tsym;
  3644. href,
  3645. tmpref : treference;
  3646. paraloc : Pcgparalocation;
  3647. l : TAsmLabel;
  3648. begin
  3649. { calculate the parameter info for the procdef }
  3650. procdef.init_paraloc_info(callerside);
  3651. hsym:=tsym(procdef.parast.Find('self'));
  3652. if not(assigned(hsym) and
  3653. (hsym.typ=paravarsym)) then
  3654. internalerror(200305251);
  3655. paraloc:=tparavarsym(hsym).paraloc[callerside].location;
  3656. while paraloc<>nil do
  3657. with paraloc^ do
  3658. begin
  3659. case loc of
  3660. LOC_REGISTER:
  3661. begin
  3662. if is_thumb_imm(ioffset) then
  3663. a_op_const_reg(list,OP_SUB,size,ioffset,register)
  3664. else
  3665. begin
  3666. list.concat(taicpu.op_regset(A_PUSH,R_INTREGISTER,R_SUBWHOLE,[RS_R4]));
  3667. reference_reset(tmpref,4);
  3668. current_asmdata.getjumplabel(l);
  3669. current_procinfo.aktlocaldata.Concat(tai_align.Create(4));
  3670. cg.a_label(current_procinfo.aktlocaldata,l);
  3671. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  3672. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ioffset));
  3673. tmpref.symbol:=l;
  3674. tmpref.base:=NR_PC;
  3675. list.concat(taicpu.op_reg_ref(A_LDR,NR_R4,tmpref));
  3676. a_op_reg_reg(list,OP_SUB,size,NR_R4,register);
  3677. list.concat(taicpu.op_regset(A_POP,R_INTREGISTER,R_SUBWHOLE,[RS_R4]));
  3678. end;
  3679. end;
  3680. LOC_REFERENCE:
  3681. begin
  3682. { offset in the wrapper needs to be adjusted for the stored
  3683. return address }
  3684. reference_reset_base(href,reference.index,reference.offset+sizeof(aint),sizeof(pint));
  3685. if is_thumb_imm(ioffset) then
  3686. a_op_const_ref(list,OP_SUB,size,ioffset,href)
  3687. else
  3688. begin
  3689. list.concat(taicpu.op_regset(A_PUSH,R_INTREGISTER,R_SUBWHOLE,[RS_R4]));
  3690. reference_reset(tmpref,4);
  3691. current_asmdata.getjumplabel(l);
  3692. current_procinfo.aktlocaldata.Concat(tai_align.Create(4));
  3693. cg.a_label(current_procinfo.aktlocaldata,l);
  3694. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  3695. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ioffset));
  3696. tmpref.symbol:=l;
  3697. tmpref.base:=NR_PC;
  3698. list.concat(taicpu.op_reg_ref(A_LDR,NR_R4,tmpref));
  3699. a_op_reg_ref(list,OP_SUB,size,NR_R4,href);
  3700. list.concat(taicpu.op_regset(A_POP,R_INTREGISTER,R_SUBWHOLE,[RS_R4]));
  3701. end;
  3702. end
  3703. else
  3704. internalerror(200309189);
  3705. end;
  3706. paraloc:=next;
  3707. end;
  3708. end;
  3709. function tthumbcgarm.handle_load_store(list: TAsmList; op: tasmop; oppostfix: toppostfix; reg: tregister; ref: treference): treference;
  3710. var
  3711. href : treference;
  3712. tmpreg : TRegister;
  3713. begin
  3714. href:=ref;
  3715. if (op in [A_STR,A_STRB,A_STRH]) and
  3716. (abs(ref.offset)>124) then
  3717. begin
  3718. tmpreg:=getintregister(list,OS_ADDR);
  3719. a_loadaddr_ref_reg(list,ref,tmpreg);
  3720. reference_reset_base(href,tmpreg,0,ref.alignment);
  3721. end
  3722. else if ((op=A_LDR) and (oppostfix in [PF_None]) and
  3723. (ref.base<>NR_STACK_POINTER_REG) and
  3724. (abs(ref.offset)>124)) or
  3725. { LDRB limitations }
  3726. (
  3727. (((op=A_LDR) and (oppostfix=PF_B)) or
  3728. ((op=A_LDRB) and (oppostfix=PF_None))) and
  3729. ((ref.base=NR_STACK_POINTER_REG) or
  3730. (ref.index=NR_STACK_POINTER_REG) or
  3731. (abs(ref.offset)>31))
  3732. ) then
  3733. begin
  3734. tmpreg:=getintregister(list,OS_ADDR);
  3735. a_loadaddr_ref_reg(list,ref,tmpreg);
  3736. reference_reset_base(href,tmpreg,0,ref.alignment);
  3737. end
  3738. else if (op=A_LDR) and
  3739. (oppostfix in [PF_None]) and
  3740. (ref.base=NR_STACK_POINTER_REG) and
  3741. (abs(ref.offset)>1020) then
  3742. begin
  3743. tmpreg:=getintregister(list,OS_ADDR);
  3744. a_loadaddr_ref_reg(list,ref,tmpreg);
  3745. reference_reset_base(href,tmpreg,0,ref.alignment);
  3746. end
  3747. else if (op=A_LDR) and
  3748. ((oppostfix in [PF_SH,PF_SB]) or
  3749. (abs(ref.offset)>124)) then
  3750. begin
  3751. tmpreg:=getintregister(list,OS_ADDR);
  3752. a_loadaddr_ref_reg(list,ref,tmpreg);
  3753. reference_reset_base(href,tmpreg,0,ref.alignment);
  3754. end;
  3755. Result:=inherited handle_load_store(list, op, oppostfix, reg, href);
  3756. end;
  3757. procedure tthumbcgarm.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  3758. var
  3759. tmpreg,overflowreg : tregister;
  3760. asmop : tasmop;
  3761. begin
  3762. case op of
  3763. OP_NEG:
  3764. list.concat(taicpu.op_reg_reg(A_NEG,dst,src));
  3765. OP_NOT:
  3766. list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
  3767. OP_DIV,OP_IDIV:
  3768. internalerror(200308284);
  3769. OP_ROL:
  3770. begin
  3771. if not(size in [OS_32,OS_S32]) then
  3772. internalerror(2008072801);
  3773. { simulate ROL by ror'ing 32-value }
  3774. tmpreg:=getintregister(list,OS_32);
  3775. a_load_const_reg(list,OS_32,32,tmpreg);
  3776. list.concat(taicpu.op_reg_reg(A_SUB,tmpreg,src));
  3777. list.concat(taicpu.op_reg_reg(A_ROR,dst,src));
  3778. end;
  3779. else
  3780. begin
  3781. a_reg_alloc(list,NR_DEFAULTFLAGS);
  3782. list.concat(setoppostfix(
  3783. taicpu.op_reg_reg(op_reg_opcg2asmop[op],dst,src),op_reg_postfix[op]));
  3784. end;
  3785. end;
  3786. maybeadjustresult(list,op,size,dst);
  3787. end;
  3788. procedure tthumbcgarm.a_op_const_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; dst: tregister);
  3789. var
  3790. tmpreg : tregister;
  3791. so : tshifterop;
  3792. l1 : longint;
  3793. imm1, imm2: DWord;
  3794. begin
  3795. //!!! ovloc.loc:=LOC_VOID;
  3796. if {$ifopt R+}(a<>-2147483648) and{$endif} {!!!!!! not setflags and } is_thumb_imm(-a) then
  3797. case op of
  3798. OP_ADD:
  3799. begin
  3800. op:=OP_SUB;
  3801. a:=aint(dword(-a));
  3802. end;
  3803. OP_SUB:
  3804. begin
  3805. op:=OP_ADD;
  3806. a:=aint(dword(-a));
  3807. end
  3808. end;
  3809. if is_thumb_imm(a) and (op in [OP_ADD,OP_SUB]) then
  3810. begin
  3811. // if cgsetflags or setflags then
  3812. a_reg_alloc(list,NR_DEFAULTFLAGS);
  3813. list.concat(setoppostfix(
  3814. taicpu.op_reg_const(op_reg_opcg2asmop[op],dst,a),op_reg_postfix[op]));
  3815. if (cgsetflags {!!! or setflags }) and (size in [OS_8,OS_16,OS_32]) then
  3816. begin
  3817. //!!! ovloc.loc:=LOC_FLAGS;
  3818. case op of
  3819. OP_ADD:
  3820. //!!! ovloc.resflags:=F_CS;
  3821. ;
  3822. OP_SUB:
  3823. //!!! ovloc.resflags:=F_CC;
  3824. ;
  3825. end;
  3826. end;
  3827. end
  3828. else
  3829. begin
  3830. { there could be added some more sophisticated optimizations }
  3831. if (op in [OP_MUL,OP_IMUL,OP_DIV,OP_IDIV]) and (a=1) then
  3832. a_load_reg_reg(list,size,size,dst,dst)
  3833. else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
  3834. a_load_const_reg(list,size,0,dst)
  3835. else if (op in [OP_IMUL,OP_IDIV]) and (a=-1) then
  3836. a_op_reg_reg(list,OP_NEG,size,dst,dst)
  3837. { we do this here instead in the peephole optimizer because
  3838. it saves us a register }
  3839. {$ifdef DUMMY}
  3840. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) and not(cgsetflags or setflags) then
  3841. a_op_const_reg_reg(list,OP_SHL,size,l1,dst,dst)
  3842. { for example : b=a*5 -> b=a*4+a with add instruction and shl }
  3843. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a-1,l1) and not(cgsetflags or setflags) then
  3844. begin
  3845. if l1>32 then{roozbeh does this ever happen?}
  3846. internalerror(200308296);
  3847. shifterop_reset(so);
  3848. so.shiftmode:=SM_LSL;
  3849. so.shiftimm:=l1;
  3850. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,dst,dst,dst,so));
  3851. end
  3852. { for example : b=a*7 -> b=a*8-a with rsb instruction and shl }
  3853. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a+1,l1) and not(cgsetflags or setflags) then
  3854. begin
  3855. if l1>32 then{does this ever happen?}
  3856. internalerror(201205181);
  3857. shifterop_reset(so);
  3858. so.shiftmode:=SM_LSL;
  3859. so.shiftimm:=l1;
  3860. list.concat(taicpu.op_reg_reg_reg_shifterop(A_RSB,dst,dst,dst,so));
  3861. end
  3862. 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
  3863. begin
  3864. { nothing to do on success }
  3865. end
  3866. {$endif DUMMY}
  3867. { x := y and 0; just clears a register, this sometimes gets generated on 64bit ops.
  3868. Just using mov x, #0 might allow some easier optimizations down the line. }
  3869. else if (op = OP_AND) and (dword(a)=0) then
  3870. list.concat(taicpu.op_reg_const(A_MOV,dst,0))
  3871. { x := y AND $FFFFFFFF just copies the register, so use mov for better optimizations }
  3872. else if (op = OP_AND) and (not(dword(a))=0) then
  3873. // do nothing
  3874. { BIC clears the specified bits, while AND keeps them, using BIC allows to use a
  3875. broader range of shifterconstants.}
  3876. {$ifdef DUMMY}
  3877. else if (op = OP_AND) and is_shifter_const(not(dword(a)),shift) then
  3878. list.concat(taicpu.op_reg_reg_const(A_BIC,dst,dst,not(dword(a))))
  3879. else if (op = OP_AND) and split_into_shifter_const(not(dword(a)), imm1, imm2) then
  3880. begin
  3881. list.concat(taicpu.op_reg_reg_const(A_BIC,dst,dst,imm1));
  3882. list.concat(taicpu.op_reg_reg_const(A_BIC,dst,dst,imm2));
  3883. end
  3884. else if (op in [OP_ADD, OP_SUB, OP_OR]) and
  3885. not(cgsetflags or setflags) and
  3886. split_into_shifter_const(a, imm1, imm2) then
  3887. begin
  3888. list.concat(taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,dst,imm1));
  3889. list.concat(taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,dst,imm2));
  3890. end
  3891. {$endif DUMMY}
  3892. else if (op in [OP_SHL, OP_SHR, OP_SAR]) then
  3893. begin
  3894. list.concat(taicpu.op_reg_reg_const(op_reg_opcg2asmop[op],dst,dst,a));
  3895. end
  3896. else
  3897. begin
  3898. tmpreg:=getintregister(list,size);
  3899. a_load_const_reg(list,size,a,tmpreg);
  3900. a_op_reg_reg(list,op,size,tmpreg,dst);
  3901. end;
  3902. end;
  3903. maybeadjustresult(list,op,size,dst);
  3904. end;
  3905. procedure tthumbcgarm.a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister);
  3906. begin
  3907. if (op=OP_ADD) and (src=NR_R13) and (dst<>NR_R13) and ((a mod 4)=0) and (a>0) and (a<=1020) then
  3908. list.concat(taicpu.op_reg_reg_const(A_ADD,dst,src,a))
  3909. else
  3910. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  3911. end;
  3912. procedure tthumbcgarm.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  3913. var
  3914. l1,l2 : tasmlabel;
  3915. ai : taicpu;
  3916. begin
  3917. current_asmdata.getjumplabel(l1);
  3918. current_asmdata.getjumplabel(l2);
  3919. ai:=setcondition(taicpu.op_sym(A_B,l1),flags_to_cond(f));
  3920. ai.is_jmp:=true;
  3921. list.concat(ai);
  3922. list.concat(taicpu.op_reg_const(A_MOV,reg,0));
  3923. list.concat(taicpu.op_sym(A_B,l2));
  3924. cg.a_label(list,l1);
  3925. list.concat(taicpu.op_reg_const(A_MOV,reg,1));
  3926. a_reg_dealloc(list,NR_DEFAULTFLAGS);
  3927. cg.a_label(list,l2);
  3928. end;
  3929. procedure tthumb2cgarm.init_register_allocators;
  3930. begin
  3931. inherited init_register_allocators;
  3932. { currently, we save R14 always, so we can use it }
  3933. if (target_info.system<>system_arm_darwin) then
  3934. rg[R_INTREGISTER]:=trgintcputhumb2.create(R_INTREGISTER,R_SUBWHOLE,
  3935. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  3936. RS_R9,RS_R10,RS_R12,RS_R14],first_int_imreg,[])
  3937. else
  3938. { r9 is not available on Darwin according to the llvm code generator }
  3939. rg[R_INTREGISTER]:=trgintcputhumb2.create(R_INTREGISTER,R_SUBWHOLE,
  3940. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  3941. RS_R10,RS_R12,RS_R14],first_int_imreg,[]);
  3942. rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
  3943. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7],first_fpu_imreg,[]);
  3944. if current_settings.fputype in [fpu_fpv4_s16,fpu_vfpv3_d16] then
  3945. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBFD,
  3946. [RS_D0,RS_D1,RS_D2,RS_D3,RS_D4,RS_D5,RS_D6,RS_D7,
  3947. RS_D8,RS_D9,RS_D10,RS_D11,RS_D12,RS_D13,RS_D14,RS_D15
  3948. ],first_mm_imreg,[])
  3949. else
  3950. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
  3951. [RS_S0,RS_S1,RS_R2,RS_R3,RS_R4,RS_S31],first_mm_imreg,[]);
  3952. end;
  3953. procedure tthumb2cgarm.done_register_allocators;
  3954. begin
  3955. rg[R_INTREGISTER].free;
  3956. rg[R_FPUREGISTER].free;
  3957. rg[R_MMREGISTER].free;
  3958. inherited done_register_allocators;
  3959. end;
  3960. procedure tthumb2cgarm.a_call_reg(list : TAsmList;reg: tregister);
  3961. begin
  3962. list.concat(taicpu.op_reg(A_BLX, reg));
  3963. {
  3964. the compiler does not properly set this flag anymore in pass 1, and
  3965. for now we only need it after pass 2 (I hope) (JM)
  3966. if not(pi_do_call in current_procinfo.flags) then
  3967. internalerror(2003060703);
  3968. }
  3969. include(current_procinfo.flags,pi_do_call);
  3970. end;
  3971. procedure tthumb2cgarm.a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);
  3972. var
  3973. imm_shift : byte;
  3974. l : tasmlabel;
  3975. hr : treference;
  3976. begin
  3977. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  3978. internalerror(2002090902);
  3979. if is_thumb32_imm(a) then
  3980. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  3981. else if is_thumb32_imm(not(a)) then
  3982. list.concat(taicpu.op_reg_const(A_MVN,reg,not(a)))
  3983. else if (a and $FFFF)=a then
  3984. list.concat(taicpu.op_reg_const(A_MOVW,reg,a))
  3985. else
  3986. begin
  3987. reference_reset(hr,4);
  3988. current_asmdata.getjumplabel(l);
  3989. cg.a_label(current_procinfo.aktlocaldata,l);
  3990. hr.symboldata:=current_procinfo.aktlocaldata.last;
  3991. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
  3992. hr.symbol:=l;
  3993. hr.base:=NR_PC;
  3994. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  3995. end;
  3996. end;
  3997. procedure tthumb2cgarm.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  3998. var
  3999. oppostfix:toppostfix;
  4000. usedtmpref: treference;
  4001. tmpreg,tmpreg2 : tregister;
  4002. so : tshifterop;
  4003. dir : integer;
  4004. begin
  4005. if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then
  4006. FromSize := ToSize;
  4007. case FromSize of
  4008. { signed integer registers }
  4009. OS_8:
  4010. oppostfix:=PF_B;
  4011. OS_S8:
  4012. oppostfix:=PF_SB;
  4013. OS_16:
  4014. oppostfix:=PF_H;
  4015. OS_S16:
  4016. oppostfix:=PF_SH;
  4017. OS_32,
  4018. OS_S32:
  4019. oppostfix:=PF_None;
  4020. else
  4021. InternalError(200308299);
  4022. end;
  4023. if (ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[fromsize]) then
  4024. begin
  4025. if target_info.endian=endian_big then
  4026. dir:=-1
  4027. else
  4028. dir:=1;
  4029. case FromSize of
  4030. OS_16,OS_S16:
  4031. begin
  4032. { only complicated references need an extra loadaddr }
  4033. if assigned(ref.symbol) or
  4034. (ref.index<>NR_NO) or
  4035. (ref.offset<-255) or
  4036. (ref.offset>4094) or
  4037. { sometimes the compiler reused registers }
  4038. (reg=ref.index) or
  4039. (reg=ref.base) then
  4040. begin
  4041. tmpreg2:=getintregister(list,OS_INT);
  4042. a_loadaddr_ref_reg(list,ref,tmpreg2);
  4043. reference_reset_base(usedtmpref,tmpreg2,0,ref.alignment);
  4044. end
  4045. else
  4046. usedtmpref:=ref;
  4047. if target_info.endian=endian_big then
  4048. inc(usedtmpref.offset,1);
  4049. shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8;
  4050. tmpreg:=getintregister(list,OS_INT);
  4051. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  4052. inc(usedtmpref.offset,dir);
  4053. if FromSize=OS_16 then
  4054. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg)
  4055. else
  4056. a_internal_load_ref_reg(list,OS_S8,OS_S8,usedtmpref,tmpreg);
  4057. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  4058. end;
  4059. OS_32,OS_S32:
  4060. begin
  4061. tmpreg:=getintregister(list,OS_INT);
  4062. { only complicated references need an extra loadaddr }
  4063. if assigned(ref.symbol) or
  4064. (ref.index<>NR_NO) or
  4065. (ref.offset<-255) or
  4066. (ref.offset>4092) or
  4067. { sometimes the compiler reused registers }
  4068. (reg=ref.index) or
  4069. (reg=ref.base) then
  4070. begin
  4071. tmpreg2:=getintregister(list,OS_INT);
  4072. a_loadaddr_ref_reg(list,ref,tmpreg2);
  4073. reference_reset_base(usedtmpref,tmpreg2,0,ref.alignment);
  4074. end
  4075. else
  4076. usedtmpref:=ref;
  4077. shifterop_reset(so);so.shiftmode:=SM_LSL;
  4078. if ref.alignment=2 then
  4079. begin
  4080. if target_info.endian=endian_big then
  4081. inc(usedtmpref.offset,2);
  4082. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,reg);
  4083. inc(usedtmpref.offset,dir*2);
  4084. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,tmpreg);
  4085. so.shiftimm:=16;
  4086. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  4087. end
  4088. else
  4089. begin
  4090. if target_info.endian=endian_big then
  4091. inc(usedtmpref.offset,3);
  4092. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  4093. inc(usedtmpref.offset,dir);
  4094. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  4095. so.shiftimm:=8;
  4096. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  4097. inc(usedtmpref.offset,dir);
  4098. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  4099. so.shiftimm:=16;
  4100. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  4101. inc(usedtmpref.offset,dir);
  4102. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  4103. so.shiftimm:=24;
  4104. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  4105. end;
  4106. end
  4107. else
  4108. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  4109. end;
  4110. end
  4111. else
  4112. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  4113. if (fromsize=OS_S8) and (tosize = OS_16) then
  4114. a_load_reg_reg(list,OS_16,OS_32,reg,reg);
  4115. end;
  4116. procedure tthumb2cgarm.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  4117. begin
  4118. if op = OP_NOT then
  4119. begin
  4120. list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
  4121. case size of
  4122. OS_8: list.concat(taicpu.op_reg_reg(A_UXTB,dst,dst));
  4123. OS_S8: list.concat(taicpu.op_reg_reg(A_SXTB,dst,dst));
  4124. OS_16: list.concat(taicpu.op_reg_reg(A_UXTH,dst,dst));
  4125. OS_S16: list.concat(taicpu.op_reg_reg(A_SXTH,dst,dst));
  4126. end;
  4127. end
  4128. else
  4129. inherited a_op_reg_reg(list, op, size, src, dst);
  4130. end;
  4131. procedure tthumb2cgarm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);
  4132. var
  4133. shift, width : byte;
  4134. tmpreg : tregister;
  4135. so : tshifterop;
  4136. l1 : longint;
  4137. begin
  4138. ovloc.loc:=LOC_VOID;
  4139. if {$ifopt R+}(a<>-2147483648) and{$endif} is_shifter_const(-a,shift) then
  4140. case op of
  4141. OP_ADD:
  4142. begin
  4143. op:=OP_SUB;
  4144. a:=aint(dword(-a));
  4145. end;
  4146. OP_SUB:
  4147. begin
  4148. op:=OP_ADD;
  4149. a:=aint(dword(-a));
  4150. end
  4151. end;
  4152. if is_shifter_const(a,shift) and not(op in [OP_IMUL,OP_MUL]) then
  4153. case op of
  4154. OP_NEG,OP_NOT,
  4155. OP_DIV,OP_IDIV:
  4156. internalerror(200308285);
  4157. OP_SHL:
  4158. begin
  4159. if a>32 then
  4160. internalerror(2014020703);
  4161. if a<>0 then
  4162. begin
  4163. shifterop_reset(so);
  4164. so.shiftmode:=SM_LSL;
  4165. so.shiftimm:=a;
  4166. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  4167. end
  4168. else
  4169. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  4170. end;
  4171. OP_ROL:
  4172. begin
  4173. if a>32 then
  4174. internalerror(2014020704);
  4175. if a<>0 then
  4176. begin
  4177. shifterop_reset(so);
  4178. so.shiftmode:=SM_ROR;
  4179. so.shiftimm:=32-a;
  4180. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  4181. end
  4182. else
  4183. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  4184. end;
  4185. OP_ROR:
  4186. begin
  4187. if a>32 then
  4188. internalerror(2014020705);
  4189. if a<>0 then
  4190. begin
  4191. shifterop_reset(so);
  4192. so.shiftmode:=SM_ROR;
  4193. so.shiftimm:=a;
  4194. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  4195. end
  4196. else
  4197. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  4198. end;
  4199. OP_SHR:
  4200. begin
  4201. if a>32 then
  4202. internalerror(200308292);
  4203. shifterop_reset(so);
  4204. if a<>0 then
  4205. begin
  4206. so.shiftmode:=SM_LSR;
  4207. so.shiftimm:=a;
  4208. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  4209. end
  4210. else
  4211. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  4212. end;
  4213. OP_SAR:
  4214. begin
  4215. if a>32 then
  4216. internalerror(200308295);
  4217. if a<>0 then
  4218. begin
  4219. shifterop_reset(so);
  4220. so.shiftmode:=SM_ASR;
  4221. so.shiftimm:=a;
  4222. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  4223. end
  4224. else
  4225. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  4226. end;
  4227. else
  4228. if (op in [OP_SUB, OP_ADD]) and
  4229. ((a < 0) or
  4230. (a > 4095)) then
  4231. begin
  4232. tmpreg:=getintregister(list,size);
  4233. a_load_const_reg(list, size, a, tmpreg);
  4234. if cgsetflags or setflags then
  4235. a_reg_alloc(list,NR_DEFAULTFLAGS);
  4236. list.concat(setoppostfix(
  4237. taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src,tmpreg),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))));
  4238. end
  4239. else
  4240. begin
  4241. if cgsetflags or setflags then
  4242. a_reg_alloc(list,NR_DEFAULTFLAGS);
  4243. list.concat(setoppostfix(
  4244. taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))));
  4245. end;
  4246. if (cgsetflags or setflags) and (size in [OS_8,OS_16,OS_32]) then
  4247. begin
  4248. ovloc.loc:=LOC_FLAGS;
  4249. case op of
  4250. OP_ADD:
  4251. ovloc.resflags:=F_CS;
  4252. OP_SUB:
  4253. ovloc.resflags:=F_CC;
  4254. end;
  4255. end;
  4256. end
  4257. else
  4258. begin
  4259. { there could be added some more sophisticated optimizations }
  4260. if (op in [OP_MUL,OP_IMUL]) and (a=1) then
  4261. a_load_reg_reg(list,size,size,src,dst)
  4262. else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
  4263. a_load_const_reg(list,size,0,dst)
  4264. else if (op in [OP_IMUL]) and (a=-1) then
  4265. a_op_reg_reg(list,OP_NEG,size,src,dst)
  4266. { we do this here instead in the peephole optimizer because
  4267. it saves us a register }
  4268. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) and not(cgsetflags or setflags) then
  4269. a_op_const_reg_reg(list,OP_SHL,size,l1,src,dst)
  4270. { for example : b=a*5 -> b=a*4+a with add instruction and shl }
  4271. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a-1,l1) and not(cgsetflags or setflags) then
  4272. begin
  4273. if l1>32 then{roozbeh does this ever happen?}
  4274. internalerror(200308296);
  4275. shifterop_reset(so);
  4276. so.shiftmode:=SM_LSL;
  4277. so.shiftimm:=l1;
  4278. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,dst,src,src,so));
  4279. end
  4280. { for example : b=a*7 -> b=a*8-a with rsb instruction and shl }
  4281. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a+1,l1) and not(cgsetflags or setflags) then
  4282. begin
  4283. if l1>32 then{does this ever happen?}
  4284. internalerror(201205181);
  4285. shifterop_reset(so);
  4286. so.shiftmode:=SM_LSL;
  4287. so.shiftimm:=l1;
  4288. list.concat(taicpu.op_reg_reg_reg_shifterop(A_RSB,dst,src,src,so));
  4289. end
  4290. 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
  4291. begin
  4292. { nothing to do on success }
  4293. end
  4294. { x := y and 0; just clears a register, this sometimes gets generated on 64bit ops.
  4295. Just using mov x, #0 might allow some easier optimizations down the line. }
  4296. else if (op = OP_AND) and (dword(a)=0) then
  4297. list.concat(taicpu.op_reg_const(A_MOV,dst,0))
  4298. { x := y AND $FFFFFFFF just copies the register, so use mov for better optimizations }
  4299. else if (op = OP_AND) and (not(dword(a))=0) then
  4300. list.concat(taicpu.op_reg_reg(A_MOV,dst,src))
  4301. { BIC clears the specified bits, while AND keeps them, using BIC allows to use a
  4302. broader range of shifterconstants.}
  4303. {else if (op = OP_AND) and is_shifter_const(not(dword(a)),shift) then
  4304. list.concat(taicpu.op_reg_reg_const(A_BIC,dst,src,not(dword(a))))}
  4305. else if (op = OP_AND) and is_thumb32_imm(a) then
  4306. list.concat(taicpu.op_reg_reg_const(A_AND,dst,src,dword(a)))
  4307. else if (op = OP_AND) and (a = $FFFF) then
  4308. list.concat(taicpu.op_reg_reg(A_UXTH,dst,src))
  4309. else if (op = OP_AND) and is_thumb32_imm(not(dword(a))) then
  4310. list.concat(taicpu.op_reg_reg_const(A_BIC,dst,src,not(dword(a))))
  4311. else if (op = OP_AND) and is_continuous_mask(not(a), shift, width) then
  4312. begin
  4313. a_load_reg_reg(list,size,size,src,dst);
  4314. list.concat(taicpu.op_reg_const_const(A_BFC,dst,shift,width))
  4315. end
  4316. else
  4317. begin
  4318. tmpreg:=getintregister(list,size);
  4319. a_load_const_reg(list,size,a,tmpreg);
  4320. a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,setflags,ovloc);
  4321. end;
  4322. end;
  4323. maybeadjustresult(list,op,size,dst);
  4324. end;
  4325. const
  4326. op_reg_reg_opcg2asmopThumb2: array[TOpCG] of tasmop =
  4327. (A_NONE,A_MOV,A_ADD,A_AND,A_UDIV,A_SDIV,A_MUL,A_MUL,A_NONE,A_MVN,A_ORR,
  4328. A_ASR,A_LSL,A_LSR,A_SUB,A_EOR,A_NONE,A_ROR);
  4329. procedure tthumb2cgarm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);
  4330. var
  4331. so : tshifterop;
  4332. tmpreg,overflowreg : tregister;
  4333. asmop : tasmop;
  4334. begin
  4335. ovloc.loc:=LOC_VOID;
  4336. case op of
  4337. OP_NEG,OP_NOT:
  4338. internalerror(200308286);
  4339. OP_ROL:
  4340. begin
  4341. if not(size in [OS_32,OS_S32]) then
  4342. internalerror(2008072801);
  4343. { simulate ROL by ror'ing 32-value }
  4344. tmpreg:=getintregister(list,OS_32);
  4345. list.concat(taicpu.op_reg_const(A_MOV,tmpreg,32));
  4346. list.concat(taicpu.op_reg_reg_reg(A_SUB,src1,tmpreg,src1));
  4347. list.concat(taicpu.op_reg_reg_reg(A_ROR, dst, src2, src1));
  4348. end;
  4349. OP_ROR:
  4350. begin
  4351. if not(size in [OS_32,OS_S32]) then
  4352. internalerror(2008072802);
  4353. list.concat(taicpu.op_reg_reg_reg(A_ROR, dst, src2, src1));
  4354. end;
  4355. OP_IMUL,
  4356. OP_MUL:
  4357. begin
  4358. if cgsetflags or setflags then
  4359. begin
  4360. overflowreg:=getintregister(list,size);
  4361. if op=OP_IMUL then
  4362. asmop:=A_SMULL
  4363. else
  4364. asmop:=A_UMULL;
  4365. { the arm doesn't allow that rd and rm are the same }
  4366. if dst=src2 then
  4367. begin
  4368. if dst<>src1 then
  4369. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src1,src2))
  4370. else
  4371. begin
  4372. tmpreg:=getintregister(list,size);
  4373. a_load_reg_reg(list,size,size,src2,dst);
  4374. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,tmpreg,src1));
  4375. end;
  4376. end
  4377. else
  4378. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src2,src1));
  4379. a_reg_alloc(list,NR_DEFAULTFLAGS);
  4380. if op=OP_IMUL then
  4381. begin
  4382. shifterop_reset(so);
  4383. so.shiftmode:=SM_ASR;
  4384. so.shiftimm:=31;
  4385. list.concat(taicpu.op_reg_reg_shifterop(A_CMP,overflowreg,dst,so));
  4386. end
  4387. else
  4388. list.concat(taicpu.op_reg_const(A_CMP,overflowreg,0));
  4389. ovloc.loc:=LOC_FLAGS;
  4390. ovloc.resflags:=F_NE;
  4391. end
  4392. else
  4393. begin
  4394. { the arm doesn't allow that rd and rm are the same }
  4395. if dst=src2 then
  4396. begin
  4397. if dst<>src1 then
  4398. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
  4399. else
  4400. begin
  4401. tmpreg:=getintregister(list,size);
  4402. a_load_reg_reg(list,size,size,src2,dst);
  4403. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,tmpreg,src1));
  4404. end;
  4405. end
  4406. else
  4407. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
  4408. end;
  4409. end;
  4410. else
  4411. begin
  4412. if cgsetflags or setflags then
  4413. a_reg_alloc(list,NR_DEFAULTFLAGS);
  4414. {$ifdef dummy}
  4415. { R13 is not allowed for certain instruction operands }
  4416. if op_reg_reg_opcg2asmopThumb2[op] in [A_ADD,A_SUB,A_AND,A_BIC,A_EOR] then
  4417. begin
  4418. if getsupreg(dst)=RS_R13 then
  4419. begin
  4420. tmpreg:=getintregister(list,OS_INT);
  4421. a_load_reg_reg(list,OS_INT,OS_INT,dst,tmpreg);
  4422. dst:=tmpreg;
  4423. end;
  4424. if getsupreg(src1)=RS_R13 then
  4425. begin
  4426. tmpreg:=getintregister(list,OS_INT);
  4427. a_load_reg_reg(list,OS_INT,OS_INT,src1,tmpreg);
  4428. src1:=tmpreg;
  4429. end;
  4430. end;
  4431. {$endif}
  4432. list.concat(setoppostfix(
  4433. taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmopThumb2[op],dst,src2,src1),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))));
  4434. end;
  4435. end;
  4436. maybeadjustresult(list,op,size,dst);
  4437. end;
  4438. procedure tthumb2cgarm.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  4439. var item: taicpu;
  4440. begin
  4441. list.concat(taicpu.op_cond(A_ITE, flags_to_cond(f)));
  4442. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
  4443. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond(flags_to_cond(f))));
  4444. end;
  4445. procedure tthumb2cgarm.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  4446. var
  4447. ref : treference;
  4448. shift : byte;
  4449. firstfloatreg,lastfloatreg,
  4450. r : byte;
  4451. regs : tcpuregisterset;
  4452. stackmisalignment: pint;
  4453. begin
  4454. LocalSize:=align(LocalSize,4);
  4455. { call instruction does not put anything on the stack }
  4456. stackmisalignment:=0;
  4457. if not(nostackframe) then
  4458. begin
  4459. firstfloatreg:=RS_NO;
  4460. lastfloatreg:=RS_NO;
  4461. { save floating point registers? }
  4462. for r:=RS_F0 to RS_F7 do
  4463. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  4464. begin
  4465. if firstfloatreg=RS_NO then
  4466. firstfloatreg:=r;
  4467. lastfloatreg:=r;
  4468. inc(stackmisalignment,12);
  4469. end;
  4470. a_reg_alloc(list,NR_STACK_POINTER_REG);
  4471. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  4472. begin
  4473. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  4474. a_reg_alloc(list,NR_R12);
  4475. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  4476. end;
  4477. { save int registers }
  4478. reference_reset(ref,4);
  4479. ref.index:=NR_STACK_POINTER_REG;
  4480. ref.addressmode:=AM_PREINDEXED;
  4481. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  4482. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  4483. regs:=regs+[RS_FRAME_POINTER_REG,RS_R14]
  4484. else if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
  4485. include(regs,RS_R14);
  4486. if regs<>[] then
  4487. begin
  4488. for r:=RS_R0 to RS_R15 do
  4489. if (r in regs) then
  4490. inc(stackmisalignment,4);
  4491. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,R_INTREGISTER,R_SUBWHOLE,regs),PF_FD));
  4492. end;
  4493. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  4494. begin
  4495. { the framepointer now points to the saved R15, so the saved
  4496. framepointer is at R11-12 (for get_caller_frame) }
  4497. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  4498. a_reg_dealloc(list,NR_R12);
  4499. end;
  4500. stackmisalignment:=stackmisalignment mod current_settings.alignment.localalignmax;
  4501. if (LocalSize<>0) or
  4502. ((stackmisalignment<>0) and
  4503. ((pi_do_call in current_procinfo.flags) or
  4504. (po_assembler in current_procinfo.procdef.procoptions))) then
  4505. begin
  4506. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  4507. if not(is_shifter_const(localsize,shift)) then
  4508. begin
  4509. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  4510. a_reg_alloc(list,NR_R12);
  4511. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  4512. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  4513. a_reg_dealloc(list,NR_R12);
  4514. end
  4515. else
  4516. begin
  4517. a_reg_dealloc(list,NR_R12);
  4518. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  4519. end;
  4520. end;
  4521. if firstfloatreg<>RS_NO then
  4522. begin
  4523. reference_reset(ref,4);
  4524. if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
  4525. begin
  4526. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  4527. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  4528. ref.base:=NR_R12;
  4529. end
  4530. else
  4531. begin
  4532. ref.base:=current_procinfo.framepointer;
  4533. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  4534. end;
  4535. list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  4536. lastfloatreg-firstfloatreg+1,ref));
  4537. end;
  4538. end;
  4539. end;
  4540. procedure tthumb2cgarm.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  4541. var
  4542. ref : treference;
  4543. firstfloatreg,lastfloatreg,
  4544. r : byte;
  4545. shift : byte;
  4546. regs : tcpuregisterset;
  4547. LocalSize : longint;
  4548. stackmisalignment: pint;
  4549. begin
  4550. if not(nostackframe) then
  4551. begin
  4552. stackmisalignment:=0;
  4553. { restore floating point register }
  4554. firstfloatreg:=RS_NO;
  4555. lastfloatreg:=RS_NO;
  4556. { save floating point registers? }
  4557. for r:=RS_F0 to RS_F7 do
  4558. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  4559. begin
  4560. if firstfloatreg=RS_NO then
  4561. firstfloatreg:=r;
  4562. lastfloatreg:=r;
  4563. { floating point register space is already included in
  4564. localsize below by calc_stackframe_size
  4565. inc(stackmisalignment,12);
  4566. }
  4567. end;
  4568. if firstfloatreg<>RS_NO then
  4569. begin
  4570. reference_reset(ref,4);
  4571. if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
  4572. begin
  4573. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  4574. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  4575. ref.base:=NR_R12;
  4576. end
  4577. else
  4578. begin
  4579. ref.base:=current_procinfo.framepointer;
  4580. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  4581. end;
  4582. list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  4583. lastfloatreg-firstfloatreg+1,ref));
  4584. end;
  4585. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  4586. if (pi_do_call in current_procinfo.flags) or (regs<>[]) then
  4587. begin
  4588. exclude(regs,RS_R14);
  4589. include(regs,RS_R15);
  4590. end;
  4591. if (current_procinfo.framepointer<>NR_STACK_POINTER_REG) then
  4592. regs:=regs+[RS_FRAME_POINTER_REG,RS_R15];
  4593. for r:=RS_R0 to RS_R15 do
  4594. if (r in regs) then
  4595. inc(stackmisalignment,4);
  4596. stackmisalignment:=stackmisalignment mod current_settings.alignment.localalignmax;
  4597. LocalSize:=current_procinfo.calc_stackframe_size;
  4598. if (LocalSize<>0) or
  4599. ((stackmisalignment<>0) and
  4600. ((pi_do_call in current_procinfo.flags) or
  4601. (po_assembler in current_procinfo.procdef.procoptions))) then
  4602. begin
  4603. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  4604. if not(is_shifter_const(LocalSize,shift)) then
  4605. begin
  4606. a_reg_alloc(list,NR_R12);
  4607. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  4608. list.concat(taicpu.op_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_R12));
  4609. a_reg_dealloc(list,NR_R12);
  4610. end
  4611. else
  4612. begin
  4613. a_reg_dealloc(list,NR_R12);
  4614. list.concat(taicpu.op_reg_const(A_ADD,NR_STACK_POINTER_REG,LocalSize));
  4615. end;
  4616. end;
  4617. if regs=[] then
  4618. list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
  4619. else
  4620. begin
  4621. reference_reset(ref,4);
  4622. ref.index:=NR_STACK_POINTER_REG;
  4623. ref.addressmode:=AM_PREINDEXED;
  4624. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,R_INTREGISTER,R_SUBWHOLE,regs),PF_FD));
  4625. end;
  4626. end
  4627. else
  4628. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14));
  4629. end;
  4630. function tthumb2cgarm.handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference;
  4631. var
  4632. tmpreg : tregister;
  4633. tmpref : treference;
  4634. l : tasmlabel;
  4635. so: tshifterop;
  4636. begin
  4637. tmpreg:=NR_NO;
  4638. { Be sure to have a base register }
  4639. if (ref.base=NR_NO) then
  4640. begin
  4641. if ref.shiftmode<>SM_None then
  4642. internalerror(2014020706);
  4643. ref.base:=ref.index;
  4644. ref.index:=NR_NO;
  4645. end;
  4646. { absolute symbols can't be handled directly, we've to store the symbol reference
  4647. in the text segment and access it pc relative
  4648. For now, we assume that references where base or index equals to PC are already
  4649. relative, all other references are assumed to be absolute and thus they need
  4650. to be handled extra.
  4651. A proper solution would be to change refoptions to a set and store the information
  4652. if the symbol is absolute or relative there.
  4653. }
  4654. if (assigned(ref.symbol) and
  4655. not(is_pc(ref.base)) and
  4656. not(is_pc(ref.index))
  4657. ) or
  4658. { [#xxx] isn't a valid address operand }
  4659. ((ref.base=NR_NO) and (ref.index=NR_NO)) or
  4660. //(ref.offset<-4095) or
  4661. (ref.offset<-255) or
  4662. (ref.offset>4095) or
  4663. ((oppostfix in [PF_SB,PF_H,PF_SH]) and
  4664. ((ref.offset<-255) or
  4665. (ref.offset>255)
  4666. )
  4667. ) or
  4668. (((op in [A_LDF,A_STF,A_FLDS,A_FLDD,A_FSTS,A_FSTD]) or (op=A_VSTR) or (op=A_VLDR)) and
  4669. ((ref.offset<-1020) or
  4670. (ref.offset>1020) or
  4671. ((abs(ref.offset) mod 4)<>0) or
  4672. { the usual pc relative symbol handling assumes possible offsets of +/- 4095 }
  4673. assigned(ref.symbol)
  4674. )
  4675. ) then
  4676. begin
  4677. reference_reset(tmpref,4);
  4678. { load symbol }
  4679. tmpreg:=getintregister(list,OS_INT);
  4680. if assigned(ref.symbol) then
  4681. begin
  4682. current_asmdata.getjumplabel(l);
  4683. cg.a_label(current_procinfo.aktlocaldata,l);
  4684. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  4685. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset));
  4686. { load consts entry }
  4687. tmpref.symbol:=l;
  4688. tmpref.base:=NR_R15;
  4689. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  4690. { in case of LDF/STF, we got rid of the NR_R15 }
  4691. if is_pc(ref.base) then
  4692. ref.base:=NR_NO;
  4693. if is_pc(ref.index) then
  4694. ref.index:=NR_NO;
  4695. end
  4696. else
  4697. a_load_const_reg(list,OS_ADDR,ref.offset,tmpreg);
  4698. if (ref.base<>NR_NO) then
  4699. begin
  4700. if ref.index<>NR_NO then
  4701. begin
  4702. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  4703. ref.base:=tmpreg;
  4704. end
  4705. else
  4706. begin
  4707. ref.index:=tmpreg;
  4708. ref.shiftimm:=0;
  4709. ref.signindex:=1;
  4710. ref.shiftmode:=SM_None;
  4711. end;
  4712. end
  4713. else
  4714. ref.base:=tmpreg;
  4715. ref.offset:=0;
  4716. ref.symbol:=nil;
  4717. end;
  4718. if (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then
  4719. begin
  4720. if tmpreg<>NR_NO then
  4721. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg,tmpreg)
  4722. else
  4723. begin
  4724. tmpreg:=getintregister(list,OS_ADDR);
  4725. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg);
  4726. ref.base:=tmpreg;
  4727. end;
  4728. ref.offset:=0;
  4729. end;
  4730. { Hack? Thumb2 doesn't allow PC indexed addressing modes(although it does in the specification) }
  4731. if (ref.base=NR_R15) and (ref.index<>NR_NO) and (ref.shiftmode <> sm_none) then
  4732. begin
  4733. tmpreg:=getintregister(list,OS_ADDR);
  4734. list.concat(taicpu.op_reg_reg(A_MOV, tmpreg, NR_R15));
  4735. ref.base := tmpreg;
  4736. end;
  4737. { floating point operations have only limited references
  4738. we expect here, that a base is already set }
  4739. 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
  4740. begin
  4741. if ref.shiftmode<>SM_none then
  4742. internalerror(200309121);
  4743. if tmpreg<>NR_NO then
  4744. begin
  4745. if ref.base=tmpreg then
  4746. begin
  4747. if ref.signindex<0 then
  4748. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,tmpreg,ref.index))
  4749. else
  4750. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg,ref.index));
  4751. ref.index:=NR_NO;
  4752. end
  4753. else
  4754. begin
  4755. if ref.index<>tmpreg then
  4756. internalerror(200403161);
  4757. if ref.signindex<0 then
  4758. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,ref.base,tmpreg))
  4759. else
  4760. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  4761. ref.base:=tmpreg;
  4762. ref.index:=NR_NO;
  4763. end;
  4764. end
  4765. else
  4766. begin
  4767. tmpreg:=getintregister(list,OS_ADDR);
  4768. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
  4769. ref.base:=tmpreg;
  4770. ref.index:=NR_NO;
  4771. end;
  4772. end;
  4773. list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
  4774. Result := ref;
  4775. end;
  4776. procedure tthumb2cgarm.a_loadmm_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister; shuffle: pmmshuffle);
  4777. var
  4778. instr: taicpu;
  4779. begin
  4780. if (fromsize=OS_F32) and
  4781. (tosize=OS_F32) then
  4782. begin
  4783. instr:=setoppostfix(taicpu.op_reg_reg(A_VMOV,reg2,reg1), PF_F32);
  4784. list.Concat(instr);
  4785. add_move_instruction(instr);
  4786. end
  4787. else if (fromsize=OS_F64) and
  4788. (tosize=OS_F64) then
  4789. begin
  4790. //list.Concat(setoppostfix(taicpu.op_reg_reg(A_VMOV,tregister(longint(reg2)+1),tregister(longint(reg1)+1)), PF_F32));
  4791. //list.Concat(setoppostfix(taicpu.op_reg_reg(A_VMOV,reg2,reg1), PF_F32));
  4792. end
  4793. else if (fromsize=OS_F32) and
  4794. (tosize=OS_F64) then
  4795. //list.Concat(setoppostfix(taicpu.op_reg_reg(A_VCVT,reg2,reg1), PF_F32))
  4796. begin
  4797. //list.concat(nil);
  4798. end;
  4799. end;
  4800. procedure tthumb2cgarm.a_loadmm_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister; shuffle: pmmshuffle);
  4801. begin
  4802. if fromsize=OS_F32 then
  4803. handle_load_store(list,A_VLDR,PF_F32,reg,ref)
  4804. else
  4805. handle_load_store(list,A_VLDR,PF_F64,reg,ref);
  4806. end;
  4807. procedure tthumb2cgarm.a_loadmm_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference; shuffle: pmmshuffle);
  4808. begin
  4809. if fromsize=OS_F32 then
  4810. handle_load_store(list,A_VSTR,PF_F32,reg,ref)
  4811. else
  4812. handle_load_store(list,A_VSTR,PF_F64,reg,ref);
  4813. end;
  4814. procedure tthumb2cgarm.a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize: tcgsize; intreg, mmreg: tregister; shuffle: pmmshuffle);
  4815. begin
  4816. if //(shuffle=nil) and
  4817. (tosize=OS_F32) then
  4818. list.Concat(taicpu.op_reg_reg(A_VMOV,mmreg,intreg))
  4819. else
  4820. internalerror(2012100813);
  4821. end;
  4822. procedure tthumb2cgarm.a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize: tcgsize; mmreg, intreg: tregister; shuffle: pmmshuffle);
  4823. begin
  4824. if //(shuffle=nil) and
  4825. (fromsize=OS_F32) then
  4826. list.Concat(taicpu.op_reg_reg(A_VMOV,intreg,mmreg))
  4827. else
  4828. internalerror(2012100814);
  4829. end;
  4830. procedure tthumb2cg64farm.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  4831. var tmpreg: tregister;
  4832. begin
  4833. case op of
  4834. OP_NEG:
  4835. begin
  4836. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4837. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  4838. tmpreg:=cg.getintregister(list,OS_32);
  4839. list.concat(taicpu.op_reg_const(A_MOV,tmpreg,0));
  4840. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,tmpreg,regsrc.reghi));
  4841. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  4842. end;
  4843. else
  4844. inherited a_op64_reg_reg(list, op, size, regsrc, regdst);
  4845. end;
  4846. end;
  4847. procedure tthumbcg64farm.a_op64_reg_reg(list: TAsmList; op: TOpCG; size: tcgsize; regsrc, regdst: tregister64);
  4848. begin
  4849. case op of
  4850. OP_NEG:
  4851. begin
  4852. list.concat(taicpu.op_reg_const(A_MOV,regdst.reglo,0));
  4853. list.concat(taicpu.op_reg_const(A_MOV,regdst.reghi,0));
  4854. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4855. list.concat(taicpu.op_reg_reg(A_SUB,regdst.reglo,regsrc.reglo));
  4856. list.concat(taicpu.op_reg_reg(A_SBC,regdst.reghi,regsrc.reghi));
  4857. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  4858. end;
  4859. OP_NOT:
  4860. begin
  4861. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  4862. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  4863. end;
  4864. OP_AND,OP_OR,OP_XOR:
  4865. begin
  4866. cg.a_op_reg_reg(list,op,OS_32,regsrc.reglo,regdst.reglo);
  4867. cg.a_op_reg_reg(list,op,OS_32,regsrc.reghi,regdst.reghi);
  4868. end;
  4869. OP_ADD:
  4870. begin
  4871. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4872. list.concat(taicpu.op_reg_reg(A_ADD,regdst.reglo,regsrc.reglo));
  4873. list.concat(taicpu.op_reg_reg(A_ADC,regdst.reghi,regsrc.reghi));
  4874. end;
  4875. OP_SUB:
  4876. begin
  4877. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4878. list.concat(taicpu.op_reg_reg(A_SUB,regdst.reglo,regsrc.reglo));
  4879. list.concat(taicpu.op_reg_reg(A_SBC,regdst.reghi,regsrc.reghi));
  4880. end;
  4881. else
  4882. internalerror(2003083101);
  4883. end;
  4884. end;
  4885. procedure tthumbcg64farm.a_op64_const_reg(list: TAsmList; op: TOpCG; size: tcgsize; value: int64; reg: tregister64);
  4886. var
  4887. tmpreg : tregister;
  4888. b : byte;
  4889. begin
  4890. case op of
  4891. OP_AND,OP_OR,OP_XOR:
  4892. begin
  4893. cg.a_op_const_reg(list,op,OS_32,aint(lo(value)),reg.reglo);
  4894. cg.a_op_const_reg(list,op,OS_32,aint(hi(value)),reg.reghi);
  4895. end;
  4896. OP_ADD:
  4897. begin
  4898. if (aint(lo(value))>=0) and (aint(lo(value))<=255) then
  4899. begin
  4900. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4901. list.concat(taicpu.op_reg_const(A_ADD,reg.reglo,aint(lo(value))));
  4902. end
  4903. else
  4904. begin
  4905. tmpreg:=cg.getintregister(list,OS_32);
  4906. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  4907. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4908. list.concat(taicpu.op_reg_reg(A_ADD,reg.reglo,tmpreg));
  4909. end;
  4910. tmpreg:=cg.getintregister(list,OS_32);
  4911. cg.a_load_const_reg(list,OS_32,aint(hi(value)),tmpreg);
  4912. list.concat(taicpu.op_reg_reg(A_ADC,reg.reghi,tmpreg));
  4913. end;
  4914. OP_SUB:
  4915. begin
  4916. if (aint(lo(value))>=0) and (aint(lo(value))<=255) then
  4917. begin
  4918. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4919. list.concat(taicpu.op_reg_const(A_SUB,reg.reglo,aint(lo(value))))
  4920. end
  4921. else
  4922. begin
  4923. tmpreg:=cg.getintregister(list,OS_32);
  4924. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  4925. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4926. list.concat(taicpu.op_reg_reg(A_SUB,reg.reglo,tmpreg));
  4927. end;
  4928. tmpreg:=cg.getintregister(list,OS_32);
  4929. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  4930. list.concat(taicpu.op_reg_reg(A_SBC,reg.reghi,tmpreg));
  4931. end;
  4932. else
  4933. internalerror(2003083101);
  4934. end;
  4935. end;
  4936. procedure create_codegen;
  4937. begin
  4938. if GenerateThumb2Code then
  4939. begin
  4940. cg:=tthumb2cgarm.create;
  4941. cg64:=tthumb2cg64farm.create;
  4942. casmoptimizer:=TCpuThumb2AsmOptimizer;
  4943. end
  4944. else if GenerateThumbCode then
  4945. begin
  4946. cg:=tthumbcgarm.create;
  4947. cg64:=tthumbcg64farm.create;
  4948. // casmoptimizer:=TCpuThumbAsmOptimizer;
  4949. end
  4950. else
  4951. begin
  4952. cg:=tarmcgarm.create;
  4953. cg64:=tarmcg64farm.create;
  4954. casmoptimizer:=TCpuAsmOptimizer;
  4955. end;
  4956. end;
  4957. end.