cgcpu.pas 215 KB

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