cgcpu.pas 213 KB

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