cgcpu.pas 197 KB

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