cgcpu.pas 213 KB

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