cgcpu.pas 212 KB

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