cgcpu.pas 219 KB

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