cgcpu.pas 210 KB

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