cgcpu.pas 197 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939
  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 (len<=helpsize) and aligned then
  2164. begin
  2165. tmpregi:=0;
  2166. srcreg:=getintregister(list,OS_ADDR);
  2167. { explicit pc relative addressing, could be
  2168. e.g. a floating point constant }
  2169. if source.base=NR_PC then
  2170. begin
  2171. { ... then we don't need a loadaddr }
  2172. srcref:=source;
  2173. end
  2174. else
  2175. begin
  2176. a_loadaddr_ref_reg(list,source,srcreg);
  2177. reference_reset_base(srcref,srcreg,0,source.alignment);
  2178. end;
  2179. while (len div 4 <> 0) and (tmpregi<maxtmpreg) do
  2180. begin
  2181. inc(tmpregi);
  2182. tmpregisters[tmpregi]:=getintregister(list,OS_32);
  2183. a_load_ref_reg(list,OS_32,OS_32,srcref,tmpregisters[tmpregi]);
  2184. inc(srcref.offset,4);
  2185. dec(len,4);
  2186. end;
  2187. destreg:=getintregister(list,OS_ADDR);
  2188. a_loadaddr_ref_reg(list,dest,destreg);
  2189. reference_reset_base(dstref,destreg,0,dest.alignment);
  2190. tmpregi2:=1;
  2191. while (tmpregi2<=tmpregi) do
  2192. begin
  2193. a_load_reg_ref(list,OS_32,OS_32,tmpregisters[tmpregi2],dstref);
  2194. inc(dstref.offset,4);
  2195. inc(tmpregi2);
  2196. end;
  2197. copysize:=4;
  2198. cgsize:=OS_32;
  2199. while len<>0 do
  2200. begin
  2201. if len<2 then
  2202. begin
  2203. copysize:=1;
  2204. cgsize:=OS_8;
  2205. end
  2206. else if len<4 then
  2207. begin
  2208. copysize:=2;
  2209. cgsize:=OS_16;
  2210. end;
  2211. dec(len,copysize);
  2212. r:=getintregister(list,cgsize);
  2213. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  2214. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  2215. inc(srcref.offset,copysize);
  2216. inc(dstref.offset,copysize);
  2217. end;{end of while}
  2218. end
  2219. else
  2220. begin
  2221. cgsize:=OS_32;
  2222. if (len<=4) then{len<=4 and not aligned}
  2223. begin
  2224. r:=getintregister(list,cgsize);
  2225. usedtmpref:=a_internal_load_ref_reg(list,OS_8,OS_8,srcref,r);
  2226. if Len=1 then
  2227. a_load_reg_ref(list,OS_8,OS_8,r,dstref)
  2228. else
  2229. begin
  2230. tmpreg:=getintregister(list,cgsize);
  2231. usedtmpref2:=a_internal_load_reg_ref(list,OS_8,OS_8,r,dstref);
  2232. inc(usedtmpref.offset,1);
  2233. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  2234. inc(usedtmpref2.offset,1);
  2235. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  2236. if len>2 then
  2237. begin
  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>3 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. end;
  2249. end;
  2250. end;
  2251. end{end of if len<=4}
  2252. else
  2253. begin{unaligned & 4<len<helpsize **or** aligned/unaligned & len>helpsize}
  2254. destreg:=getintregister(list,OS_ADDR);
  2255. a_loadaddr_ref_reg(list,dest,destreg);
  2256. reference_reset_base(dstref,destreg,0,dest.alignment);
  2257. srcreg:=getintregister(list,OS_ADDR);
  2258. a_loadaddr_ref_reg(list,source,srcreg);
  2259. reference_reset_base(srcref,srcreg,0,source.alignment);
  2260. countreg:=getintregister(list,OS_32);
  2261. // if cs_opt_size in current_settings.optimizerswitches then
  2262. { roozbeh : it seems loading 1 byte is faster becouse of caching/fetching(?) }
  2263. {if aligned then
  2264. genloop(len,4)
  2265. else}
  2266. if current_settings.cputype in cpu_thumb then
  2267. genloop_thumb(len,1)
  2268. else
  2269. genloop(len,1);
  2270. end;
  2271. end;
  2272. end;
  2273. procedure tbasecgarm.g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : tcgint);
  2274. begin
  2275. g_concatcopy_internal(list,source,dest,len,false);
  2276. end;
  2277. procedure tbasecgarm.g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);
  2278. begin
  2279. if (source.alignment in [1..3]) or
  2280. (dest.alignment in [1..3]) then
  2281. g_concatcopy_internal(list,source,dest,len,false)
  2282. else
  2283. g_concatcopy_internal(list,source,dest,len,true);
  2284. end;
  2285. procedure tbasecgarm.g_overflowCheck(list : TAsmList;const l : tlocation;def : tdef);
  2286. var
  2287. ovloc : tlocation;
  2288. begin
  2289. ovloc.loc:=LOC_VOID;
  2290. g_overflowCheck_loc(list,l,def,ovloc);
  2291. end;
  2292. procedure tbasecgarm.g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);
  2293. var
  2294. hl : tasmlabel;
  2295. ai:TAiCpu;
  2296. hflags : tresflags;
  2297. begin
  2298. if not(cs_check_overflow in current_settings.localswitches) then
  2299. exit;
  2300. current_asmdata.getjumplabel(hl);
  2301. case ovloc.loc of
  2302. LOC_VOID:
  2303. begin
  2304. ai:=taicpu.op_sym(A_B,hl);
  2305. ai.is_jmp:=true;
  2306. if not((def.typ=pointerdef) or
  2307. ((def.typ=orddef) and
  2308. (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,
  2309. pasbool8,pasbool16,pasbool32,pasbool64]))) then
  2310. ai.SetCondition(C_VC)
  2311. else
  2312. if TAiCpu(List.Last).opcode in [A_RSB,A_RSC,A_SBC,A_SUB] then
  2313. ai.SetCondition(C_CS)
  2314. else
  2315. ai.SetCondition(C_CC);
  2316. list.concat(ai);
  2317. end;
  2318. LOC_FLAGS:
  2319. begin
  2320. hflags:=ovloc.resflags;
  2321. inverse_flags(hflags);
  2322. cg.a_jmp_flags(list,hflags,hl);
  2323. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2324. end;
  2325. else
  2326. internalerror(200409281);
  2327. end;
  2328. a_call_name(list,'FPC_OVERFLOW',false);
  2329. a_label(list,hl);
  2330. end;
  2331. procedure tbasecgarm.g_save_registers(list : TAsmList);
  2332. begin
  2333. { this work is done in g_proc_entry }
  2334. end;
  2335. procedure tbasecgarm.g_restore_registers(list : TAsmList);
  2336. begin
  2337. { this work is done in g_proc_exit }
  2338. end;
  2339. procedure tbasecgarm.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  2340. var
  2341. ai : taicpu;
  2342. begin
  2343. ai:=Taicpu.Op_sym(A_B,l);
  2344. ai.SetCondition(OpCmp2AsmCond[cond]);
  2345. ai.is_jmp:=true;
  2346. list.concat(ai);
  2347. end;
  2348. procedure tbasecgarm.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);
  2349. var
  2350. hsym : tsym;
  2351. href : treference;
  2352. paraloc : Pcgparalocation;
  2353. shift : byte;
  2354. begin
  2355. { calculate the parameter info for the procdef }
  2356. procdef.init_paraloc_info(callerside);
  2357. hsym:=tsym(procdef.parast.Find('self'));
  2358. if not(assigned(hsym) and
  2359. (hsym.typ=paravarsym)) then
  2360. internalerror(200305251);
  2361. paraloc:=tparavarsym(hsym).paraloc[callerside].location;
  2362. while paraloc<>nil do
  2363. with paraloc^ do
  2364. begin
  2365. case loc of
  2366. LOC_REGISTER:
  2367. begin
  2368. if is_shifter_const(ioffset,shift) then
  2369. a_op_const_reg(list,OP_SUB,size,ioffset,register)
  2370. else
  2371. begin
  2372. a_load_const_reg(list,OS_ADDR,ioffset,NR_R12);
  2373. a_op_reg_reg(list,OP_SUB,size,NR_R12,register);
  2374. end;
  2375. end;
  2376. LOC_REFERENCE:
  2377. begin
  2378. { offset in the wrapper needs to be adjusted for the stored
  2379. return address }
  2380. reference_reset_base(href,reference.index,reference.offset+sizeof(aint),sizeof(pint));
  2381. if is_shifter_const(ioffset,shift) then
  2382. a_op_const_ref(list,OP_SUB,size,ioffset,href)
  2383. else
  2384. begin
  2385. a_load_const_reg(list,OS_ADDR,ioffset,NR_R12);
  2386. a_op_reg_ref(list,OP_SUB,size,NR_R12,href);
  2387. end;
  2388. end
  2389. else
  2390. internalerror(200309189);
  2391. end;
  2392. paraloc:=next;
  2393. end;
  2394. end;
  2395. procedure tbasecgarm.g_stackpointer_alloc(list: TAsmList; size: longint);
  2396. begin
  2397. internalerror(200807237);
  2398. end;
  2399. function get_scalar_mm_op(fromsize,tosize : tcgsize) : tasmop;
  2400. const
  2401. convertop : array[OS_F32..OS_F128,OS_F32..OS_F128] of tasmop = (
  2402. (A_FCPYS,A_FCVTSD,A_NONE,A_NONE,A_NONE),
  2403. (A_FCVTDS,A_FCPYD,A_NONE,A_NONE,A_NONE),
  2404. (A_NONE,A_NONE,A_NONE,A_NONE,A_NONE),
  2405. (A_NONE,A_NONE,A_NONE,A_NONE,A_NONE),
  2406. (A_NONE,A_NONE,A_NONE,A_NONE,A_NONE));
  2407. begin
  2408. result:=convertop[fromsize,tosize];
  2409. if result=A_NONE then
  2410. internalerror(200312205);
  2411. end;
  2412. procedure tbasecgarm.a_loadmm_reg_reg(list: tasmlist; fromsize,tosize: tcgsize; reg1,reg2: tregister; shuffle: pmmshuffle);
  2413. var
  2414. instr: taicpu;
  2415. begin
  2416. if shuffle=nil then
  2417. begin
  2418. if fromsize=tosize then
  2419. { needs correct size in case of spilling }
  2420. case fromsize of
  2421. OS_F32:
  2422. instr:=taicpu.op_reg_reg(A_FCPYS,reg2,reg1);
  2423. OS_F64:
  2424. instr:=taicpu.op_reg_reg(A_FCPYD,reg2,reg1);
  2425. else
  2426. internalerror(2009112405);
  2427. end
  2428. else
  2429. internalerror(2009112406);
  2430. end
  2431. else if shufflescalar(shuffle) then
  2432. instr:=taicpu.op_reg_reg(get_scalar_mm_op(tosize,fromsize),reg2,reg1)
  2433. else
  2434. internalerror(2009112407);
  2435. list.concat(instr);
  2436. case instr.opcode of
  2437. A_FCPYS,
  2438. A_FCPYD:
  2439. add_move_instruction(instr);
  2440. end;
  2441. end;
  2442. procedure tbasecgarm.a_loadmm_ref_reg(list: tasmlist; fromsize,tosize: tcgsize; const ref: treference; reg: tregister; shuffle: pmmshuffle);
  2443. var
  2444. intreg,
  2445. tmpmmreg : tregister;
  2446. reg64 : tregister64;
  2447. op : tasmop;
  2448. begin
  2449. if assigned(shuffle) and
  2450. not(shufflescalar(shuffle)) then
  2451. internalerror(2009112413);
  2452. case fromsize of
  2453. OS_32,OS_S32:
  2454. begin
  2455. fromsize:=OS_F32;
  2456. { since we are loading an integer, no conversion may be required }
  2457. if (fromsize<>tosize) then
  2458. internalerror(2009112801);
  2459. end;
  2460. OS_64,OS_S64:
  2461. begin
  2462. fromsize:=OS_F64;
  2463. { since we are loading an integer, no conversion may be required }
  2464. if (fromsize<>tosize) then
  2465. internalerror(2009112901);
  2466. end;
  2467. end;
  2468. if (fromsize<>tosize) then
  2469. tmpmmreg:=getmmregister(list,fromsize)
  2470. else
  2471. tmpmmreg:=reg;
  2472. if (ref.alignment in [1,2]) then
  2473. begin
  2474. case fromsize of
  2475. OS_F32:
  2476. begin
  2477. intreg:=getintregister(list,OS_32);
  2478. a_load_ref_reg(list,OS_32,OS_32,ref,intreg);
  2479. a_loadmm_intreg_reg(list,OS_32,OS_F32,intreg,tmpmmreg,mms_movescalar);
  2480. end;
  2481. OS_F64:
  2482. begin
  2483. reg64.reglo:=getintregister(list,OS_32);
  2484. reg64.reghi:=getintregister(list,OS_32);
  2485. cg64.a_load64_ref_reg(list,ref,reg64);
  2486. cg64.a_loadmm_intreg64_reg(list,OS_F64,reg64,tmpmmreg);
  2487. end;
  2488. else
  2489. internalerror(2009112412);
  2490. end;
  2491. end
  2492. else
  2493. begin
  2494. case fromsize of
  2495. OS_F32:
  2496. op:=A_FLDS;
  2497. OS_F64:
  2498. op:=A_FLDD;
  2499. else
  2500. internalerror(2009112415);
  2501. end;
  2502. handle_load_store(list,op,PF_None,tmpmmreg,ref);
  2503. end;
  2504. if (tmpmmreg<>reg) then
  2505. a_loadmm_reg_reg(list,fromsize,tosize,tmpmmreg,reg,shuffle);
  2506. end;
  2507. procedure tbasecgarm.a_loadmm_reg_ref(list: tasmlist; fromsize,tosize: tcgsize; reg: tregister; const ref: treference; shuffle: pmmshuffle);
  2508. var
  2509. intreg,
  2510. tmpmmreg : tregister;
  2511. reg64 : tregister64;
  2512. op : tasmop;
  2513. begin
  2514. if assigned(shuffle) and
  2515. not(shufflescalar(shuffle)) then
  2516. internalerror(2009112416);
  2517. case tosize of
  2518. OS_32,OS_S32:
  2519. begin
  2520. tosize:=OS_F32;
  2521. { since we are loading an integer, no conversion may be required }
  2522. if (fromsize<>tosize) then
  2523. internalerror(2009112801);
  2524. end;
  2525. OS_64,OS_S64:
  2526. begin
  2527. tosize:=OS_F64;
  2528. { since we are loading an integer, no conversion may be required }
  2529. if (fromsize<>tosize) then
  2530. internalerror(2009112901);
  2531. end;
  2532. end;
  2533. if (fromsize<>tosize) then
  2534. begin
  2535. tmpmmreg:=getmmregister(list,tosize);
  2536. a_loadmm_reg_reg(list,fromsize,tosize,reg,tmpmmreg,shuffle);
  2537. end
  2538. else
  2539. tmpmmreg:=reg;
  2540. if (ref.alignment in [1,2]) then
  2541. begin
  2542. case tosize of
  2543. OS_F32:
  2544. begin
  2545. intreg:=getintregister(list,OS_32);
  2546. a_loadmm_reg_intreg(list,OS_F32,OS_32,tmpmmreg,intreg,shuffle);
  2547. a_load_reg_ref(list,OS_32,OS_32,intreg,ref);
  2548. end;
  2549. OS_F64:
  2550. begin
  2551. reg64.reglo:=getintregister(list,OS_32);
  2552. reg64.reghi:=getintregister(list,OS_32);
  2553. cg64.a_loadmm_reg_intreg64(list,OS_F64,tmpmmreg,reg64);
  2554. cg64.a_load64_reg_ref(list,reg64,ref);
  2555. end;
  2556. else
  2557. internalerror(2009112417);
  2558. end;
  2559. end
  2560. else
  2561. begin
  2562. case fromsize of
  2563. OS_F32:
  2564. op:=A_FSTS;
  2565. OS_F64:
  2566. op:=A_FSTD;
  2567. else
  2568. internalerror(2009112418);
  2569. end;
  2570. handle_load_store(list,op,PF_None,tmpmmreg,ref);
  2571. end;
  2572. end;
  2573. procedure tbasecgarm.a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize : tcgsize; intreg, mmreg: tregister; shuffle: pmmshuffle);
  2574. begin
  2575. { this code can only be used to transfer raw data, not to perform
  2576. conversions }
  2577. if (tosize<>OS_F32) then
  2578. internalerror(2009112419);
  2579. if not(fromsize in [OS_32,OS_S32]) then
  2580. internalerror(2009112420);
  2581. if assigned(shuffle) and
  2582. not shufflescalar(shuffle) then
  2583. internalerror(2009112516);
  2584. list.concat(taicpu.op_reg_reg(A_FMSR,mmreg,intreg));
  2585. end;
  2586. procedure tbasecgarm.a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize : tcgsize; mmreg, intreg: tregister;shuffle : pmmshuffle);
  2587. begin
  2588. { this code can only be used to transfer raw data, not to perform
  2589. conversions }
  2590. if (fromsize<>OS_F32) then
  2591. internalerror(2009112430);
  2592. if not(tosize in [OS_32,OS_S32]) then
  2593. internalerror(2009112420);
  2594. if assigned(shuffle) and
  2595. not shufflescalar(shuffle) then
  2596. internalerror(2009112514);
  2597. list.concat(taicpu.op_reg_reg(A_FMRS,intreg,mmreg));
  2598. end;
  2599. procedure tbasecgarm.a_opmm_reg_reg(list: tasmlist; op: topcg; size: tcgsize; src, dst: tregister; shuffle: pmmshuffle);
  2600. var
  2601. tmpreg: tregister;
  2602. begin
  2603. { the vfp doesn't support xor nor any other logical operation, but
  2604. this routine is used to initialise global mm regvars. We can
  2605. easily initialise an mm reg with 0 though. }
  2606. case op of
  2607. OP_XOR:
  2608. begin
  2609. if (src<>dst) or
  2610. (reg_cgsize(src)<>size) or
  2611. assigned(shuffle) then
  2612. internalerror(2009112907);
  2613. tmpreg:=getintregister(list,OS_32);
  2614. a_load_const_reg(list,OS_32,0,tmpreg);
  2615. case size of
  2616. OS_F32:
  2617. list.concat(taicpu.op_reg_reg(A_FMSR,dst,tmpreg));
  2618. OS_F64:
  2619. list.concat(taicpu.op_reg_reg_reg(A_FMDRR,dst,tmpreg,tmpreg));
  2620. else
  2621. internalerror(2009112908);
  2622. end;
  2623. end
  2624. else
  2625. internalerror(2009112906);
  2626. end;
  2627. end;
  2628. procedure tbasecgarm.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  2629. procedure loadvmttor12;
  2630. var
  2631. href : treference;
  2632. begin
  2633. reference_reset_base(href,NR_R0,0,sizeof(pint));
  2634. if current_settings.cputype in cpu_thumb then
  2635. begin
  2636. list.concat(taicpu.op_regset(A_PUSH,R_INTREGISTER,R_SUBWHOLE,[RS_R0]));
  2637. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R0);
  2638. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_R0));
  2639. list.concat(taicpu.op_regset(A_POP,R_INTREGISTER,R_SUBWHOLE,[RS_R0]));
  2640. end
  2641. else
  2642. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  2643. end;
  2644. procedure op_onr12methodaddr;
  2645. var
  2646. href : treference;
  2647. begin
  2648. if (procdef.extnumber=$ffff) then
  2649. Internalerror(200006139);
  2650. if current_settings.cputype in cpu_thumb then
  2651. begin
  2652. reference_reset_base(href,NR_R0,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),sizeof(pint));
  2653. list.concat(taicpu.op_regset(A_PUSH,R_INTREGISTER,R_SUBWHOLE,[RS_R0]));
  2654. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R0);
  2655. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_R0));
  2656. list.concat(taicpu.op_regset(A_POP,R_INTREGISTER,R_SUBWHOLE,[RS_R0]));
  2657. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
  2658. end
  2659. else
  2660. begin
  2661. reference_reset_base(href,NR_R12,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),sizeof(pint));
  2662. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  2663. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
  2664. end;
  2665. end;
  2666. var
  2667. make_global : boolean;
  2668. begin
  2669. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  2670. Internalerror(200006137);
  2671. if not assigned(procdef.struct) or
  2672. (procdef.procoptions*[po_classmethod, po_staticmethod,
  2673. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  2674. Internalerror(200006138);
  2675. if procdef.owner.symtabletype<>ObjectSymtable then
  2676. Internalerror(200109191);
  2677. make_global:=false;
  2678. if (not current_module.is_unit) or
  2679. create_smartlink or
  2680. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  2681. make_global:=true;
  2682. if make_global then
  2683. list.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  2684. else
  2685. list.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  2686. { the wrapper might need aktlocaldata for the additional data to
  2687. load the constant }
  2688. current_procinfo:=cprocinfo.create(nil);
  2689. { set param1 interface to self }
  2690. g_adjust_self_value(list,procdef,ioffset);
  2691. { case 4 }
  2692. if (po_virtualmethod in procdef.procoptions) and
  2693. not is_objectpascal_helper(procdef.struct) then
  2694. begin
  2695. loadvmttor12;
  2696. op_onr12methodaddr;
  2697. end
  2698. { case 0 }
  2699. else
  2700. list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname)));
  2701. list.concatlist(current_procinfo.aktlocaldata);
  2702. current_procinfo.Free;
  2703. current_procinfo:=nil;
  2704. list.concat(Tai_symbol_end.Createname(labelname));
  2705. end;
  2706. procedure tbasecgarm.maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  2707. const
  2708. overflowops = [OP_MUL,OP_SHL,OP_ADD,OP_SUB,OP_NEG];
  2709. begin
  2710. if (op in overflowops) and
  2711. (size in [OS_8,OS_S8,OS_16,OS_S16]) then
  2712. a_load_reg_reg(list,OS_32,size,dst,dst);
  2713. end;
  2714. function tbasecgarm.get_darwin_call_stub(const s: string; weak: boolean): tasmsymbol;
  2715. var
  2716. stubname: string;
  2717. l1: tasmsymbol;
  2718. href: treference;
  2719. begin
  2720. stubname := 'L'+s+'$stub';
  2721. result := current_asmdata.getasmsymbol(stubname);
  2722. if assigned(result) then
  2723. exit;
  2724. if current_asmdata.asmlists[al_imports]=nil then
  2725. current_asmdata.asmlists[al_imports]:=TAsmList.create;
  2726. new_section(current_asmdata.asmlists[al_imports],sec_stub,'',4);
  2727. result := current_asmdata.RefAsmSymbol(stubname);
  2728. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(result,0));
  2729. { register as a weak symbol if necessary }
  2730. if weak then
  2731. current_asmdata.weakrefasmsymbol(s);
  2732. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_indirect_symbol,s));
  2733. if not(cs_create_pic in current_settings.moduleswitches) then
  2734. begin
  2735. l1 := current_asmdata.RefAsmSymbol('L'+s+'$slp');
  2736. reference_reset_symbol(href,l1,0,sizeof(pint));
  2737. href.refaddr:=addr_full;
  2738. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_ref(A_LDR,NR_R12,href));
  2739. reference_reset_base(href,NR_R12,0,sizeof(pint));
  2740. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_ref(A_LDR,NR_R15,href));
  2741. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(l1,0));
  2742. l1 := current_asmdata.RefAsmSymbol('L'+s+'$lazy_ptr');
  2743. current_asmdata.asmlists[al_imports].concat(tai_const.create_sym(l1));
  2744. end
  2745. else
  2746. internalerror(2008100401);
  2747. new_section(current_asmdata.asmlists[al_imports],sec_data_lazy,'',sizeof(pint));
  2748. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(l1,0));
  2749. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_indirect_symbol,s));
  2750. current_asmdata.asmlists[al_imports].concat(tai_const.createname('dyld_stub_binding_helper',0));
  2751. end;
  2752. procedure tcg64farm.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  2753. begin
  2754. case op of
  2755. OP_NEG:
  2756. begin
  2757. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2758. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  2759. list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
  2760. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2761. end;
  2762. OP_NOT:
  2763. begin
  2764. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  2765. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  2766. end;
  2767. else
  2768. a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
  2769. end;
  2770. end;
  2771. procedure tcg64farm.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  2772. begin
  2773. a_op64_const_reg_reg(list,op,size,value,reg,reg);
  2774. end;
  2775. procedure tcg64farm.a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);
  2776. var
  2777. ovloc : tlocation;
  2778. begin
  2779. a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,ovloc);
  2780. end;
  2781. procedure tcg64farm.a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
  2782. var
  2783. ovloc : tlocation;
  2784. begin
  2785. a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,ovloc);
  2786. end;
  2787. procedure tcg64farm.a_loadmm_intreg64_reg(list: TAsmList; mmsize: tcgsize; intreg: tregister64; mmreg: tregister);
  2788. begin
  2789. { this code can only be used to transfer raw data, not to perform
  2790. conversions }
  2791. if (mmsize<>OS_F64) then
  2792. internalerror(2009112405);
  2793. list.concat(taicpu.op_reg_reg_reg(A_FMDRR,mmreg,intreg.reglo,intreg.reghi));
  2794. end;
  2795. procedure tcg64farm.a_loadmm_reg_intreg64(list: TAsmList; mmsize: tcgsize; mmreg: tregister; intreg: tregister64);
  2796. begin
  2797. { this code can only be used to transfer raw data, not to perform
  2798. conversions }
  2799. if (mmsize<>OS_F64) then
  2800. internalerror(2009112406);
  2801. list.concat(taicpu.op_reg_reg_reg(A_FMRRD,intreg.reglo,intreg.reghi,mmreg));
  2802. end;
  2803. procedure tcg64farm.a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  2804. var
  2805. tmpreg : tregister;
  2806. b : byte;
  2807. begin
  2808. ovloc.loc:=LOC_VOID;
  2809. case op of
  2810. OP_NEG,
  2811. OP_NOT :
  2812. internalerror(2012022501);
  2813. end;
  2814. if (setflags or tbasecgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  2815. begin
  2816. case op of
  2817. OP_ADD:
  2818. begin
  2819. if is_shifter_const(lo(value),b) then
  2820. begin
  2821. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2822. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  2823. end
  2824. else
  2825. begin
  2826. tmpreg:=cg.getintregister(list,OS_32);
  2827. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  2828. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2829. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  2830. end;
  2831. if is_shifter_const(hi(value),b) then
  2832. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  2833. else
  2834. begin
  2835. tmpreg:=cg.getintregister(list,OS_32);
  2836. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  2837. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  2838. end;
  2839. end;
  2840. OP_SUB:
  2841. begin
  2842. if is_shifter_const(lo(value),b) then
  2843. begin
  2844. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2845. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  2846. end
  2847. else
  2848. begin
  2849. tmpreg:=cg.getintregister(list,OS_32);
  2850. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  2851. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2852. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  2853. end;
  2854. if is_shifter_const(hi(value),b) then
  2855. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))),PF_S))
  2856. else
  2857. begin
  2858. tmpreg:=cg.getintregister(list,OS_32);
  2859. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  2860. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  2861. end;
  2862. end;
  2863. else
  2864. internalerror(200502131);
  2865. end;
  2866. if size=OS_64 then
  2867. begin
  2868. { the arm has an weired opinion how flags for SUB/ADD are handled }
  2869. ovloc.loc:=LOC_FLAGS;
  2870. case op of
  2871. OP_ADD:
  2872. ovloc.resflags:=F_CS;
  2873. OP_SUB:
  2874. ovloc.resflags:=F_CC;
  2875. end;
  2876. end;
  2877. end
  2878. else
  2879. begin
  2880. case op of
  2881. OP_AND,OP_OR,OP_XOR:
  2882. begin
  2883. cg.a_op_const_reg_reg(list,op,OS_32,aint(lo(value)),regsrc.reglo,regdst.reglo);
  2884. cg.a_op_const_reg_reg(list,op,OS_32,aint(hi(value)),regsrc.reghi,regdst.reghi);
  2885. end;
  2886. OP_ADD:
  2887. begin
  2888. if is_shifter_const(aint(lo(value)),b) then
  2889. begin
  2890. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2891. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
  2892. end
  2893. else
  2894. begin
  2895. tmpreg:=cg.getintregister(list,OS_32);
  2896. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  2897. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2898. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  2899. end;
  2900. if is_shifter_const(aint(hi(value)),b) then
  2901. list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,aint(hi(value))))
  2902. else
  2903. begin
  2904. tmpreg:=cg.getintregister(list,OS_32);
  2905. cg.a_load_const_reg(list,OS_32,aint(hi(value)),tmpreg);
  2906. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
  2907. end;
  2908. end;
  2909. OP_SUB:
  2910. begin
  2911. if is_shifter_const(aint(lo(value)),b) then
  2912. begin
  2913. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2914. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
  2915. end
  2916. else
  2917. begin
  2918. tmpreg:=cg.getintregister(list,OS_32);
  2919. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  2920. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2921. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  2922. end;
  2923. if is_shifter_const(aint(hi(value)),b) then
  2924. list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))))
  2925. else
  2926. begin
  2927. tmpreg:=cg.getintregister(list,OS_32);
  2928. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  2929. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
  2930. end;
  2931. end;
  2932. else
  2933. internalerror(2003083101);
  2934. end;
  2935. end;
  2936. end;
  2937. procedure tcg64farm.a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  2938. begin
  2939. ovloc.loc:=LOC_VOID;
  2940. case op of
  2941. OP_NEG,
  2942. OP_NOT :
  2943. internalerror(2012022502);
  2944. end;
  2945. if (setflags or tbasecgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  2946. begin
  2947. case op of
  2948. OP_ADD:
  2949. begin
  2950. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2951. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  2952. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi),PF_S));
  2953. end;
  2954. OP_SUB:
  2955. begin
  2956. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2957. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  2958. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi),PF_S));
  2959. end;
  2960. else
  2961. internalerror(2003083101);
  2962. end;
  2963. if size=OS_64 then
  2964. begin
  2965. { the arm has an weired opinion how flags for SUB/ADD are handled }
  2966. ovloc.loc:=LOC_FLAGS;
  2967. case op of
  2968. OP_ADD:
  2969. ovloc.resflags:=F_CS;
  2970. OP_SUB:
  2971. ovloc.resflags:=F_CC;
  2972. end;
  2973. end;
  2974. end
  2975. else
  2976. begin
  2977. case op of
  2978. OP_AND,OP_OR,OP_XOR:
  2979. begin
  2980. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  2981. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  2982. end;
  2983. OP_ADD:
  2984. begin
  2985. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2986. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  2987. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  2988. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2989. end;
  2990. OP_SUB:
  2991. begin
  2992. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2993. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  2994. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
  2995. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  2996. end;
  2997. else
  2998. internalerror(2003083101);
  2999. end;
  3000. end;
  3001. end;
  3002. procedure tthumbcgarm.init_register_allocators;
  3003. begin
  3004. inherited init_register_allocators;
  3005. rg[R_INTREGISTER]:=trgintcputhumb2.create(R_INTREGISTER,R_SUBWHOLE,
  3006. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7],first_int_imreg,[]);
  3007. { rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
  3008. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7],first_fpu_imreg,[]);
  3009. if current_settings.fputype=fpu_fpv4_s16 then
  3010. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBFD,
  3011. [RS_D0,RS_D1,RS_D2,RS_D3,RS_D4,RS_D5,RS_D6,RS_D7,
  3012. RS_D8,RS_D9,RS_D10,RS_D11,RS_D12,RS_D13,RS_D14,RS_D15
  3013. ],first_mm_imreg,[])
  3014. else
  3015. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
  3016. [RS_S0,RS_S1,RS_R2,RS_R3,RS_R4,RS_S31],first_mm_imreg,[]);
  3017. }
  3018. end;
  3019. procedure tthumbcgarm.done_register_allocators;
  3020. begin
  3021. rg[R_INTREGISTER].free;
  3022. rg[R_FPUREGISTER].free;
  3023. rg[R_MMREGISTER].free;
  3024. inherited done_register_allocators;
  3025. end;
  3026. procedure tthumbcgarm.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  3027. var
  3028. ref : treference;
  3029. shift : byte;
  3030. r : byte;
  3031. regs, saveregs : tcpuregisterset;
  3032. r7offset,
  3033. stackmisalignment : pint;
  3034. postfix: toppostfix;
  3035. imm1, imm2: DWord;
  3036. begin
  3037. LocalSize:=align(LocalSize,4);
  3038. { call instruction does not put anything on the stack }
  3039. stackmisalignment:=0;
  3040. if not(nostackframe) then
  3041. begin
  3042. a_reg_alloc(list,NR_STACK_POINTER_REG);
  3043. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  3044. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  3045. { save int registers }
  3046. reference_reset(ref,4);
  3047. ref.index:=NR_STACK_POINTER_REG;
  3048. ref.addressmode:=AM_PREINDEXED;
  3049. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  3050. a_reg_alloc(list,NR_STACK_POINTER_REG);
  3051. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  3052. begin
  3053. //!!!! a_reg_alloc(list,NR_R12);
  3054. //!!!! list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  3055. end;
  3056. { the (old) ARM APCS requires saving both the stack pointer (to
  3057. crawl the stack) and the PC (to identify the function this
  3058. stack frame belongs to) -> also save R12 (= copy of R13 on entry)
  3059. and R15 -- still needs updating for EABI and Darwin, they don't
  3060. need that }
  3061. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  3062. regs:=regs+[RS_R7,RS_R14]
  3063. else
  3064. if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
  3065. include(regs,RS_R14);
  3066. if regs<>[] then
  3067. begin
  3068. for r:=RS_R0 to RS_R15 do
  3069. if r in regs then
  3070. inc(stackmisalignment,4);
  3071. list.concat(taicpu.op_regset(A_PUSH,R_INTREGISTER,R_SUBWHOLE,regs));
  3072. end;
  3073. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  3074. begin
  3075. { the framepointer now points to the saved R15, so the saved
  3076. framepointer is at R11-12 (for get_caller_frame) }
  3077. //!!! list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  3078. //!!! a_reg_dealloc(list,NR_R12);
  3079. end;
  3080. stackmisalignment:=stackmisalignment mod current_settings.alignment.localalignmax;
  3081. if (LocalSize<>0) or
  3082. ((stackmisalignment<>0) and
  3083. ((pi_do_call in current_procinfo.flags) or
  3084. (po_assembler in current_procinfo.procdef.procoptions))) then
  3085. begin
  3086. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  3087. if is_shifter_const(localsize,shift) then
  3088. begin
  3089. a_reg_dealloc(list,NR_R12);
  3090. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  3091. end
  3092. else if split_into_shifter_const(localsize, imm1, imm2) then
  3093. begin
  3094. a_reg_dealloc(list,NR_R12);
  3095. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,imm1));
  3096. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,imm2));
  3097. end
  3098. else
  3099. begin
  3100. //!!!! if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  3101. //!!!! a_reg_alloc(list,NR_R12);
  3102. //!!!! a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  3103. //!!!! list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  3104. //!!!! a_reg_dealloc(list,NR_R12);
  3105. end;
  3106. end;
  3107. end;
  3108. end;
  3109. procedure tthumbcgarm.g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean);
  3110. var
  3111. ref : treference;
  3112. LocalSize : longint;
  3113. r,
  3114. shift : byte;
  3115. saveregs,
  3116. regs : tcpuregisterset;
  3117. stackmisalignment: pint;
  3118. imm1, imm2: DWord;
  3119. begin
  3120. if not(nostackframe) then
  3121. begin
  3122. stackmisalignment:=0;
  3123. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall) ;
  3124. include(regs,RS_R15);
  3125. for r:=RS_R0 to RS_R15 do
  3126. if r in regs then
  3127. inc(stackmisalignment,4);
  3128. stackmisalignment:=stackmisalignment mod current_settings.alignment.localalignmax;
  3129. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) or
  3130. (target_info.system in systems_darwin) then
  3131. begin
  3132. LocalSize:=current_procinfo.calc_stackframe_size;
  3133. if (LocalSize<>0) or
  3134. ((stackmisalignment<>0) and
  3135. ((pi_do_call in current_procinfo.flags) or
  3136. (po_assembler in current_procinfo.procdef.procoptions))) then
  3137. begin
  3138. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  3139. if is_shifter_const(LocalSize,shift) then
  3140. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize))
  3141. else if split_into_shifter_const(localsize, imm1, imm2) then
  3142. begin
  3143. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,imm1));
  3144. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,imm2));
  3145. end
  3146. else
  3147. begin
  3148. a_reg_alloc(list,NR_R12);
  3149. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  3150. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  3151. a_reg_dealloc(list,NR_R12);
  3152. end;
  3153. end;
  3154. if regs=[] then
  3155. begin
  3156. if not(CPUARM_HAS_BX in cpu_capabilities[current_settings.cputype]) then
  3157. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14))
  3158. else
  3159. list.concat(taicpu.op_reg(A_BX,NR_R14))
  3160. end
  3161. else
  3162. begin
  3163. reference_reset(ref,4);
  3164. ref.index:=NR_STACK_POINTER_REG;
  3165. ref.addressmode:=AM_PREINDEXED;
  3166. list.concat(taicpu.op_regset(A_POP,R_INTREGISTER,R_SUBWHOLE,regs));
  3167. end;
  3168. end
  3169. else
  3170. begin
  3171. { restore int registers and return }
  3172. reference_reset(ref,4);
  3173. ref.index:=NR_FRAME_POINTER_REG;
  3174. list.concat(taicpu.op_regset(A_POP,R_INTREGISTER,R_SUBWHOLE,regs));
  3175. end;
  3176. end
  3177. else if not(CPUARM_HAS_BX in cpu_capabilities[current_settings.cputype]) then
  3178. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14))
  3179. else
  3180. list.concat(taicpu.op_reg(A_BX,NR_R14))
  3181. end;
  3182. procedure tthumbcgarm.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  3183. var
  3184. oppostfix:toppostfix;
  3185. usedtmpref: treference;
  3186. tmpreg,tmpreg2 : tregister;
  3187. dir : integer;
  3188. begin
  3189. if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then
  3190. FromSize := ToSize;
  3191. case FromSize of
  3192. { signed integer registers }
  3193. OS_8:
  3194. oppostfix:=PF_B;
  3195. OS_S8:
  3196. oppostfix:=PF_SB;
  3197. OS_16:
  3198. oppostfix:=PF_H;
  3199. OS_S16:
  3200. oppostfix:=PF_SH;
  3201. OS_32,
  3202. OS_S32:
  3203. oppostfix:=PF_None;
  3204. else
  3205. InternalError(200308297);
  3206. end;
  3207. if (ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[fromsize]) then
  3208. begin
  3209. if target_info.endian=endian_big then
  3210. dir:=-1
  3211. else
  3212. dir:=1;
  3213. case FromSize of
  3214. OS_16,OS_S16:
  3215. begin
  3216. { only complicated references need an extra loadaddr }
  3217. if assigned(ref.symbol) or
  3218. (ref.index<>NR_NO) or
  3219. (ref.offset<-255) or
  3220. (ref.offset>4094) or
  3221. { sometimes the compiler reused registers }
  3222. (reg=ref.index) or
  3223. (reg=ref.base) then
  3224. begin
  3225. tmpreg2:=getintregister(list,OS_INT);
  3226. a_loadaddr_ref_reg(list,ref,tmpreg2);
  3227. reference_reset_base(usedtmpref,tmpreg2,0,ref.alignment);
  3228. end
  3229. else
  3230. usedtmpref:=ref;
  3231. if target_info.endian=endian_big then
  3232. inc(usedtmpref.offset,1);
  3233. tmpreg:=getintregister(list,OS_INT);
  3234. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  3235. inc(usedtmpref.offset,dir);
  3236. if FromSize=OS_16 then
  3237. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg)
  3238. else
  3239. a_internal_load_ref_reg(list,OS_S8,OS_S8,usedtmpref,tmpreg);
  3240. list.concat(taicpu.op_reg_const(A_LSL,tmpreg,8));
  3241. list.concat(taicpu.op_reg_reg(A_ORR,reg,tmpreg));
  3242. end;
  3243. OS_32,OS_S32:
  3244. begin
  3245. tmpreg:=getintregister(list,OS_INT);
  3246. { only complicated references need an extra loadaddr }
  3247. if assigned(ref.symbol) or
  3248. (ref.index<>NR_NO) or
  3249. (ref.offset<-255) or
  3250. (ref.offset>4092) or
  3251. { sometimes the compiler reused registers }
  3252. (reg=ref.index) or
  3253. (reg=ref.base) then
  3254. begin
  3255. tmpreg2:=getintregister(list,OS_INT);
  3256. a_loadaddr_ref_reg(list,ref,tmpreg2);
  3257. reference_reset_base(usedtmpref,tmpreg2,0,ref.alignment);
  3258. end
  3259. else
  3260. usedtmpref:=ref;
  3261. if ref.alignment=2 then
  3262. begin
  3263. if target_info.endian=endian_big then
  3264. inc(usedtmpref.offset,2);
  3265. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,reg);
  3266. inc(usedtmpref.offset,dir*2);
  3267. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,tmpreg);
  3268. list.concat(taicpu.op_reg_const(A_LSL,tmpreg,16));
  3269. list.concat(taicpu.op_reg_reg(A_ORR,reg,tmpreg));
  3270. end
  3271. else
  3272. begin
  3273. if target_info.endian=endian_big then
  3274. inc(usedtmpref.offset,3);
  3275. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  3276. inc(usedtmpref.offset,dir);
  3277. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  3278. list.concat(taicpu.op_reg_const(A_LSL,tmpreg,8));
  3279. list.concat(taicpu.op_reg_reg(A_ORR,reg,tmpreg));
  3280. inc(usedtmpref.offset,dir);
  3281. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  3282. list.concat(taicpu.op_reg_const(A_LSL,tmpreg,16));
  3283. list.concat(taicpu.op_reg_reg(A_ORR,reg,tmpreg));
  3284. inc(usedtmpref.offset,dir);
  3285. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  3286. list.concat(taicpu.op_reg_const(A_LSL,tmpreg,24));
  3287. list.concat(taicpu.op_reg_reg(A_ORR,reg,tmpreg));
  3288. end;
  3289. end
  3290. else
  3291. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  3292. end;
  3293. end
  3294. else
  3295. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  3296. if (fromsize=OS_S8) and (tosize = OS_16) then
  3297. a_load_reg_reg(list,OS_16,OS_32,reg,reg);
  3298. end;
  3299. procedure tthumbcgarm.a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);
  3300. var
  3301. imm_shift : byte;
  3302. l : tasmlabel;
  3303. hr : treference;
  3304. begin
  3305. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  3306. internalerror(2002090902);
  3307. if is_thumb_imm(a) then
  3308. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  3309. else
  3310. begin
  3311. reference_reset(hr,4);
  3312. current_asmdata.getjumplabel(l);
  3313. cg.a_label(current_procinfo.aktlocaldata,l);
  3314. hr.symboldata:=current_procinfo.aktlocaldata.last;
  3315. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
  3316. hr.symbol:=l;
  3317. hr.base:=NR_PC;
  3318. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  3319. end;
  3320. end;
  3321. procedure tthumbcgarm.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  3322. var
  3323. tmpreg,overflowreg : tregister;
  3324. asmop : tasmop;
  3325. begin
  3326. case op of
  3327. OP_NEG:
  3328. list.concat(taicpu.op_reg_reg(A_NEG,dst,src));
  3329. OP_NOT:
  3330. list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
  3331. OP_DIV,OP_IDIV:
  3332. internalerror(200308281);
  3333. OP_ROL:
  3334. begin
  3335. if not(size in [OS_32,OS_S32]) then
  3336. internalerror(2008072801);
  3337. { simulate ROL by ror'ing 32-value }
  3338. tmpreg:=getintregister(list,OS_32);
  3339. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,tmpreg,src,32),PF_S));
  3340. list.concat(taicpu.op_reg_reg(A_ROR,dst,src));
  3341. end;
  3342. else
  3343. begin
  3344. a_reg_alloc(list,NR_DEFAULTFLAGS);
  3345. list.concat(setoppostfix(
  3346. taicpu.op_reg_reg(op_reg_opcg2asmop[op],dst,src),op_reg_postfix[op]));
  3347. end;
  3348. end;
  3349. maybeadjustresult(list,op,size,dst);
  3350. end;
  3351. procedure tthumbcgarm.a_op_const_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; dst: tregister);
  3352. var
  3353. tmpreg : tregister;
  3354. so : tshifterop;
  3355. l1 : longint;
  3356. imm1, imm2: DWord;
  3357. begin
  3358. //!!! ovloc.loc:=LOC_VOID;
  3359. if {$ifopt R+}(a<>-2147483648) and{$endif} {!!!!!! not setflags and } is_thumb_imm(-a) then
  3360. case op of
  3361. OP_ADD:
  3362. begin
  3363. op:=OP_SUB;
  3364. a:=aint(dword(-a));
  3365. end;
  3366. OP_SUB:
  3367. begin
  3368. op:=OP_ADD;
  3369. a:=aint(dword(-a));
  3370. end
  3371. end;
  3372. if is_thumb_imm(a) and not(op in [OP_IMUL,OP_MUL,OP_AND,OP_OR,OP_XOR]) then
  3373. case op of
  3374. OP_NEG:
  3375. list.concat(taicpu.op_reg_const(A_NEG,dst,a));
  3376. OP_NOT:
  3377. list.concat(taicpu.op_reg_const(A_MVN,dst,a));
  3378. OP_ROL:
  3379. begin
  3380. if not(size in [OS_32,OS_S32]) then
  3381. internalerror(2008072801);
  3382. list.concat(taicpu.op_reg_const(A_ROR,dst,a));
  3383. end;
  3384. else
  3385. begin
  3386. // if cgsetflags or setflags then
  3387. a_reg_alloc(list,NR_DEFAULTFLAGS);
  3388. list.concat(setoppostfix(
  3389. taicpu.op_reg_const(op_reg_opcg2asmop[op],dst,a),op_reg_postfix[op]));
  3390. end;
  3391. if (cgsetflags {!!! or setflags }) and (size in [OS_8,OS_16,OS_32]) then
  3392. begin
  3393. //!!! ovloc.loc:=LOC_FLAGS;
  3394. case op of
  3395. OP_ADD:
  3396. //!!! ovloc.resflags:=F_CS;
  3397. ;
  3398. OP_SUB:
  3399. //!!! ovloc.resflags:=F_CC;
  3400. ;
  3401. end;
  3402. end;
  3403. end
  3404. else
  3405. begin
  3406. { there could be added some more sophisticated optimizations }
  3407. if (op in [OP_MUL,OP_IMUL,OP_DIV,OP_IDIV]) and (a=1) then
  3408. a_load_reg_reg(list,size,size,dst,dst)
  3409. else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
  3410. a_load_const_reg(list,size,0,dst)
  3411. else if (op in [OP_IMUL,OP_IDIV]) and (a=-1) then
  3412. a_op_reg_reg(list,OP_NEG,size,dst,dst)
  3413. { we do this here instead in the peephole optimizer because
  3414. it saves us a register }
  3415. {$ifdef DUMMY}
  3416. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) and not(cgsetflags or setflags) then
  3417. a_op_const_reg_reg(list,OP_SHL,size,l1,src,dst)
  3418. { for example : b=a*5 -> b=a*4+a with add instruction and shl }
  3419. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a-1,l1) and not(cgsetflags or setflags) then
  3420. begin
  3421. if l1>32 then{roozbeh does this ever happen?}
  3422. internalerror(200308296);
  3423. shifterop_reset(so);
  3424. so.shiftmode:=SM_LSL;
  3425. so.shiftimm:=l1;
  3426. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,dst,src,src,so));
  3427. end
  3428. { for example : b=a*7 -> b=a*8-a with rsb instruction and shl }
  3429. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a+1,l1) and not(cgsetflags or setflags) then
  3430. begin
  3431. if l1>32 then{does this ever happen?}
  3432. internalerror(201205181);
  3433. shifterop_reset(so);
  3434. so.shiftmode:=SM_LSL;
  3435. so.shiftimm:=l1;
  3436. list.concat(taicpu.op_reg_reg_reg_shifterop(A_RSB,dst,src,src,so));
  3437. end
  3438. 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
  3439. begin
  3440. { nothing to do on success }
  3441. end
  3442. {$endif DUMMY}
  3443. { x := y and 0; just clears a register, this sometimes gets generated on 64bit ops.
  3444. Just using mov x, #0 might allow some easier optimizations down the line. }
  3445. else if (op = OP_AND) and (dword(a)=0) then
  3446. list.concat(taicpu.op_reg_const(A_MOV,dst,0))
  3447. { x := y AND $FFFFFFFF just copies the register, so use mov for better optimizations }
  3448. else if (op = OP_AND) and (not(dword(a))=0) then
  3449. // do nothing
  3450. { BIC clears the specified bits, while AND keeps them, using BIC allows to use a
  3451. broader range of shifterconstants.}
  3452. {$ifdef DUMMY}
  3453. else if (op = OP_AND) and is_shifter_const(not(dword(a)),shift) then
  3454. list.concat(taicpu.op_reg_reg_const(A_BIC,dst,src,not(dword(a))))
  3455. else if (op = OP_AND) and split_into_shifter_const(not(dword(a)), imm1, imm2) then
  3456. begin
  3457. list.concat(taicpu.op_reg_reg_const(A_BIC,dst,src,imm1));
  3458. list.concat(taicpu.op_reg_reg_const(A_BIC,dst,dst,imm2));
  3459. end
  3460. else if (op in [OP_ADD, OP_SUB, OP_OR]) and
  3461. not(cgsetflags or setflags) and
  3462. split_into_shifter_const(a, imm1, imm2) then
  3463. begin
  3464. list.concat(taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,imm1));
  3465. list.concat(taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,dst,imm2));
  3466. end
  3467. {$endif DUMMY}
  3468. else
  3469. begin
  3470. tmpreg:=getintregister(list,size);
  3471. a_load_const_reg(list,size,a,tmpreg);
  3472. a_op_reg_reg(list,op,size,tmpreg,dst);
  3473. end;
  3474. end;
  3475. maybeadjustresult(list,op,size,dst);
  3476. end;
  3477. procedure tthumbcgarm.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  3478. var
  3479. l : tasmlabel;
  3480. ai : taicpu;
  3481. begin
  3482. current_asmdata.getjumplabel(l);
  3483. list.concat(taicpu.op_reg_const(A_MOV,reg,1));
  3484. ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
  3485. ai.is_jmp:=true;
  3486. list.concat(ai);
  3487. list.concat(taicpu.op_reg_const(A_MOV,reg,0));
  3488. a_reg_dealloc(list,NR_DEFAULTFLAGS);
  3489. cg.a_label(list,l);
  3490. end;
  3491. procedure tthumb2cgarm.init_register_allocators;
  3492. begin
  3493. inherited init_register_allocators;
  3494. { currently, we save R14 always, so we can use it }
  3495. if (target_info.system<>system_arm_darwin) then
  3496. rg[R_INTREGISTER]:=trgintcputhumb2.create(R_INTREGISTER,R_SUBWHOLE,
  3497. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  3498. RS_R9,RS_R10,RS_R12,RS_R14],first_int_imreg,[])
  3499. else
  3500. { r9 is not available on Darwin according to the llvm code generator }
  3501. rg[R_INTREGISTER]:=trgintcputhumb2.create(R_INTREGISTER,R_SUBWHOLE,
  3502. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  3503. RS_R10,RS_R12,RS_R14],first_int_imreg,[]);
  3504. rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
  3505. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7],first_fpu_imreg,[]);
  3506. if current_settings.fputype=fpu_fpv4_s16 then
  3507. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBFD,
  3508. [RS_D0,RS_D1,RS_D2,RS_D3,RS_D4,RS_D5,RS_D6,RS_D7,
  3509. RS_D8,RS_D9,RS_D10,RS_D11,RS_D12,RS_D13,RS_D14,RS_D15
  3510. ],first_mm_imreg,[])
  3511. else
  3512. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
  3513. [RS_S0,RS_S1,RS_R2,RS_R3,RS_R4,RS_S31],first_mm_imreg,[]);
  3514. end;
  3515. procedure tthumb2cgarm.done_register_allocators;
  3516. begin
  3517. rg[R_INTREGISTER].free;
  3518. rg[R_FPUREGISTER].free;
  3519. rg[R_MMREGISTER].free;
  3520. inherited done_register_allocators;
  3521. end;
  3522. procedure tthumb2cgarm.a_call_reg(list : TAsmList;reg: tregister);
  3523. begin
  3524. list.concat(taicpu.op_reg(A_BLX, reg));
  3525. {
  3526. the compiler does not properly set this flag anymore in pass 1, and
  3527. for now we only need it after pass 2 (I hope) (JM)
  3528. if not(pi_do_call in current_procinfo.flags) then
  3529. internalerror(2003060703);
  3530. }
  3531. include(current_procinfo.flags,pi_do_call);
  3532. end;
  3533. procedure tthumb2cgarm.a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);
  3534. var
  3535. imm_shift : byte;
  3536. l : tasmlabel;
  3537. hr : treference;
  3538. begin
  3539. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  3540. internalerror(2002090902);
  3541. if is_thumb32_imm(a) then
  3542. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  3543. else if is_thumb32_imm(not(a)) then
  3544. list.concat(taicpu.op_reg_const(A_MVN,reg,not(a)))
  3545. else if (a and $FFFF)=a then
  3546. list.concat(taicpu.op_reg_const(A_MOVW,reg,a))
  3547. else
  3548. begin
  3549. reference_reset(hr,4);
  3550. current_asmdata.getjumplabel(l);
  3551. cg.a_label(current_procinfo.aktlocaldata,l);
  3552. hr.symboldata:=current_procinfo.aktlocaldata.last;
  3553. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
  3554. hr.symbol:=l;
  3555. hr.base:=NR_PC;
  3556. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  3557. end;
  3558. end;
  3559. procedure tthumb2cgarm.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  3560. var
  3561. oppostfix:toppostfix;
  3562. usedtmpref: treference;
  3563. tmpreg,tmpreg2 : tregister;
  3564. so : tshifterop;
  3565. dir : integer;
  3566. begin
  3567. if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then
  3568. FromSize := ToSize;
  3569. case FromSize of
  3570. { signed integer registers }
  3571. OS_8:
  3572. oppostfix:=PF_B;
  3573. OS_S8:
  3574. oppostfix:=PF_SB;
  3575. OS_16:
  3576. oppostfix:=PF_H;
  3577. OS_S16:
  3578. oppostfix:=PF_SH;
  3579. OS_32,
  3580. OS_S32:
  3581. oppostfix:=PF_None;
  3582. else
  3583. InternalError(200308297);
  3584. end;
  3585. if (ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[fromsize]) then
  3586. begin
  3587. if target_info.endian=endian_big then
  3588. dir:=-1
  3589. else
  3590. dir:=1;
  3591. case FromSize of
  3592. OS_16,OS_S16:
  3593. begin
  3594. { only complicated references need an extra loadaddr }
  3595. if assigned(ref.symbol) or
  3596. (ref.index<>NR_NO) or
  3597. (ref.offset<-255) or
  3598. (ref.offset>4094) or
  3599. { sometimes the compiler reused registers }
  3600. (reg=ref.index) or
  3601. (reg=ref.base) then
  3602. begin
  3603. tmpreg2:=getintregister(list,OS_INT);
  3604. a_loadaddr_ref_reg(list,ref,tmpreg2);
  3605. reference_reset_base(usedtmpref,tmpreg2,0,ref.alignment);
  3606. end
  3607. else
  3608. usedtmpref:=ref;
  3609. if target_info.endian=endian_big then
  3610. inc(usedtmpref.offset,1);
  3611. shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8;
  3612. tmpreg:=getintregister(list,OS_INT);
  3613. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  3614. inc(usedtmpref.offset,dir);
  3615. if FromSize=OS_16 then
  3616. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg)
  3617. else
  3618. a_internal_load_ref_reg(list,OS_S8,OS_S8,usedtmpref,tmpreg);
  3619. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  3620. end;
  3621. OS_32,OS_S32:
  3622. begin
  3623. tmpreg:=getintregister(list,OS_INT);
  3624. { only complicated references need an extra loadaddr }
  3625. if assigned(ref.symbol) or
  3626. (ref.index<>NR_NO) or
  3627. (ref.offset<-255) or
  3628. (ref.offset>4092) or
  3629. { sometimes the compiler reused registers }
  3630. (reg=ref.index) or
  3631. (reg=ref.base) then
  3632. begin
  3633. tmpreg2:=getintregister(list,OS_INT);
  3634. a_loadaddr_ref_reg(list,ref,tmpreg2);
  3635. reference_reset_base(usedtmpref,tmpreg2,0,ref.alignment);
  3636. end
  3637. else
  3638. usedtmpref:=ref;
  3639. shifterop_reset(so);so.shiftmode:=SM_LSL;
  3640. if ref.alignment=2 then
  3641. begin
  3642. if target_info.endian=endian_big then
  3643. inc(usedtmpref.offset,2);
  3644. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,reg);
  3645. inc(usedtmpref.offset,dir*2);
  3646. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,tmpreg);
  3647. so.shiftimm:=16;
  3648. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  3649. end
  3650. else
  3651. begin
  3652. if target_info.endian=endian_big then
  3653. inc(usedtmpref.offset,3);
  3654. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  3655. inc(usedtmpref.offset,dir);
  3656. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  3657. so.shiftimm:=8;
  3658. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  3659. inc(usedtmpref.offset,dir);
  3660. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  3661. so.shiftimm:=16;
  3662. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  3663. inc(usedtmpref.offset,dir);
  3664. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  3665. so.shiftimm:=24;
  3666. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  3667. end;
  3668. end
  3669. else
  3670. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  3671. end;
  3672. end
  3673. else
  3674. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  3675. if (fromsize=OS_S8) and (tosize = OS_16) then
  3676. a_load_reg_reg(list,OS_16,OS_32,reg,reg);
  3677. end;
  3678. procedure tthumb2cgarm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);
  3679. var
  3680. shift : byte;
  3681. tmpreg : tregister;
  3682. so : tshifterop;
  3683. l1 : longint;
  3684. begin
  3685. ovloc.loc:=LOC_VOID;
  3686. if {$ifopt R+}(a<>-2147483648) and{$endif} is_shifter_const(-a,shift) then
  3687. case op of
  3688. OP_ADD:
  3689. begin
  3690. op:=OP_SUB;
  3691. a:=aint(dword(-a));
  3692. end;
  3693. OP_SUB:
  3694. begin
  3695. op:=OP_ADD;
  3696. a:=aint(dword(-a));
  3697. end
  3698. end;
  3699. if is_shifter_const(a,shift) and not(op in [OP_IMUL,OP_MUL]) then
  3700. case op of
  3701. OP_NEG,OP_NOT,
  3702. OP_DIV,OP_IDIV:
  3703. internalerror(200308281);
  3704. OP_SHL:
  3705. begin
  3706. if a>32 then
  3707. internalerror(200308294);
  3708. if a<>0 then
  3709. begin
  3710. shifterop_reset(so);
  3711. so.shiftmode:=SM_LSL;
  3712. so.shiftimm:=a;
  3713. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  3714. end
  3715. else
  3716. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  3717. end;
  3718. OP_ROL:
  3719. begin
  3720. if a>32 then
  3721. internalerror(200308294);
  3722. if a<>0 then
  3723. begin
  3724. shifterop_reset(so);
  3725. so.shiftmode:=SM_ROR;
  3726. so.shiftimm:=32-a;
  3727. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  3728. end
  3729. else
  3730. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  3731. end;
  3732. OP_ROR:
  3733. begin
  3734. if a>32 then
  3735. internalerror(200308294);
  3736. if a<>0 then
  3737. begin
  3738. shifterop_reset(so);
  3739. so.shiftmode:=SM_ROR;
  3740. so.shiftimm:=a;
  3741. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  3742. end
  3743. else
  3744. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  3745. end;
  3746. OP_SHR:
  3747. begin
  3748. if a>32 then
  3749. internalerror(200308292);
  3750. shifterop_reset(so);
  3751. if a<>0 then
  3752. begin
  3753. so.shiftmode:=SM_LSR;
  3754. so.shiftimm:=a;
  3755. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  3756. end
  3757. else
  3758. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  3759. end;
  3760. OP_SAR:
  3761. begin
  3762. if a>32 then
  3763. internalerror(200308295);
  3764. if a<>0 then
  3765. begin
  3766. shifterop_reset(so);
  3767. so.shiftmode:=SM_ASR;
  3768. so.shiftimm:=a;
  3769. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  3770. end
  3771. else
  3772. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  3773. end;
  3774. else
  3775. if (op in [OP_SUB, OP_ADD]) and
  3776. ((a < 0) or
  3777. (a > 4095)) then
  3778. begin
  3779. tmpreg:=getintregister(list,size);
  3780. a_load_const_reg(list, size, a, tmpreg);
  3781. if cgsetflags or setflags then
  3782. a_reg_alloc(list,NR_DEFAULTFLAGS);
  3783. list.concat(setoppostfix(
  3784. taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src,tmpreg),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))));
  3785. end
  3786. else
  3787. begin
  3788. if cgsetflags or setflags then
  3789. a_reg_alloc(list,NR_DEFAULTFLAGS);
  3790. list.concat(setoppostfix(
  3791. taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))));
  3792. end;
  3793. if (cgsetflags or setflags) and (size in [OS_8,OS_16,OS_32]) then
  3794. begin
  3795. ovloc.loc:=LOC_FLAGS;
  3796. case op of
  3797. OP_ADD:
  3798. ovloc.resflags:=F_CS;
  3799. OP_SUB:
  3800. ovloc.resflags:=F_CC;
  3801. end;
  3802. end;
  3803. end
  3804. else
  3805. begin
  3806. { there could be added some more sophisticated optimizations }
  3807. if (op in [OP_MUL,OP_IMUL]) and (a=1) then
  3808. a_load_reg_reg(list,size,size,src,dst)
  3809. else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
  3810. a_load_const_reg(list,size,0,dst)
  3811. else if (op in [OP_IMUL]) and (a=-1) then
  3812. a_op_reg_reg(list,OP_NEG,size,src,dst)
  3813. { we do this here instead in the peephole optimizer because
  3814. it saves us a register }
  3815. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) and not(cgsetflags or setflags) then
  3816. a_op_const_reg_reg(list,OP_SHL,size,l1,src,dst)
  3817. { for example : b=a*5 -> b=a*4+a with add instruction and shl }
  3818. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a-1,l1) and not(cgsetflags or setflags) then
  3819. begin
  3820. if l1>32 then{roozbeh does this ever happen?}
  3821. internalerror(200308296);
  3822. shifterop_reset(so);
  3823. so.shiftmode:=SM_LSL;
  3824. so.shiftimm:=l1;
  3825. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,dst,src,src,so));
  3826. end
  3827. { for example : b=a*7 -> b=a*8-a with rsb instruction and shl }
  3828. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a+1,l1) and not(cgsetflags or setflags) then
  3829. begin
  3830. if l1>32 then{does this ever happen?}
  3831. internalerror(201205181);
  3832. shifterop_reset(so);
  3833. so.shiftmode:=SM_LSL;
  3834. so.shiftimm:=l1;
  3835. list.concat(taicpu.op_reg_reg_reg_shifterop(A_RSB,dst,src,src,so));
  3836. end
  3837. 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
  3838. begin
  3839. { nothing to do on success }
  3840. end
  3841. { x := y and 0; just clears a register, this sometimes gets generated on 64bit ops.
  3842. Just using mov x, #0 might allow some easier optimizations down the line. }
  3843. else if (op = OP_AND) and (dword(a)=0) then
  3844. list.concat(taicpu.op_reg_const(A_MOV,dst,0))
  3845. { x := y AND $FFFFFFFF just copies the register, so use mov for better optimizations }
  3846. else if (op = OP_AND) and (not(dword(a))=0) then
  3847. list.concat(taicpu.op_reg_reg(A_MOV,dst,src))
  3848. { BIC clears the specified bits, while AND keeps them, using BIC allows to use a
  3849. broader range of shifterconstants.}
  3850. {else if (op = OP_AND) and is_shifter_const(not(dword(a)),shift) then
  3851. list.concat(taicpu.op_reg_reg_const(A_BIC,dst,src,not(dword(a))))}
  3852. else if (op = OP_AND) and is_thumb32_imm(a) then
  3853. list.concat(taicpu.op_reg_reg_const(A_MOV,dst,src,dword(a)))
  3854. else if (op = OP_AND) and is_thumb32_imm(not(dword(a))) then
  3855. list.concat(taicpu.op_reg_reg_const(A_BIC,dst,src,not(dword(a))))
  3856. else
  3857. begin
  3858. tmpreg:=getintregister(list,size);
  3859. a_load_const_reg(list,size,a,tmpreg);
  3860. a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,setflags,ovloc);
  3861. end;
  3862. end;
  3863. maybeadjustresult(list,op,size,dst);
  3864. end;
  3865. const
  3866. op_reg_reg_opcg2asmopThumb2: array[TOpCG] of tasmop =
  3867. (A_NONE,A_MOV,A_ADD,A_AND,A_UDIV,A_SDIV,A_MUL,A_MUL,A_NONE,A_MVN,A_ORR,
  3868. A_ASR,A_LSL,A_LSR,A_SUB,A_EOR,A_NONE,A_ROR);
  3869. procedure tthumb2cgarm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);
  3870. var
  3871. so : tshifterop;
  3872. tmpreg,overflowreg : tregister;
  3873. asmop : tasmop;
  3874. begin
  3875. ovloc.loc:=LOC_VOID;
  3876. case op of
  3877. OP_NEG,OP_NOT:
  3878. internalerror(200308281);
  3879. OP_ROL:
  3880. begin
  3881. if not(size in [OS_32,OS_S32]) then
  3882. internalerror(2008072801);
  3883. { simulate ROL by ror'ing 32-value }
  3884. tmpreg:=getintregister(list,OS_32);
  3885. list.concat(taicpu.op_reg_const(A_MOV,tmpreg,32));
  3886. list.concat(taicpu.op_reg_reg_reg(A_SUB,src1,tmpreg,src1));
  3887. list.concat(taicpu.op_reg_reg_reg(A_ROR, dst, src2, src1));
  3888. end;
  3889. OP_ROR:
  3890. begin
  3891. if not(size in [OS_32,OS_S32]) then
  3892. internalerror(2008072802);
  3893. list.concat(taicpu.op_reg_reg_reg(A_ROR, dst, src2, src1));
  3894. end;
  3895. OP_IMUL,
  3896. OP_MUL:
  3897. begin
  3898. if cgsetflags or setflags then
  3899. begin
  3900. overflowreg:=getintregister(list,size);
  3901. if op=OP_IMUL then
  3902. asmop:=A_SMULL
  3903. else
  3904. asmop:=A_UMULL;
  3905. { the arm doesn't allow that rd and rm are the same }
  3906. if dst=src2 then
  3907. begin
  3908. if dst<>src1 then
  3909. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src1,src2))
  3910. else
  3911. begin
  3912. tmpreg:=getintregister(list,size);
  3913. a_load_reg_reg(list,size,size,src2,dst);
  3914. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,tmpreg,src1));
  3915. end;
  3916. end
  3917. else
  3918. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src2,src1));
  3919. a_reg_alloc(list,NR_DEFAULTFLAGS);
  3920. if op=OP_IMUL then
  3921. begin
  3922. shifterop_reset(so);
  3923. so.shiftmode:=SM_ASR;
  3924. so.shiftimm:=31;
  3925. list.concat(taicpu.op_reg_reg_shifterop(A_CMP,overflowreg,dst,so));
  3926. end
  3927. else
  3928. list.concat(taicpu.op_reg_const(A_CMP,overflowreg,0));
  3929. ovloc.loc:=LOC_FLAGS;
  3930. ovloc.resflags:=F_NE;
  3931. end
  3932. else
  3933. begin
  3934. { the arm doesn't allow that rd and rm are the same }
  3935. if dst=src2 then
  3936. begin
  3937. if dst<>src1 then
  3938. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
  3939. else
  3940. begin
  3941. tmpreg:=getintregister(list,size);
  3942. a_load_reg_reg(list,size,size,src2,dst);
  3943. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,tmpreg,src1));
  3944. end;
  3945. end
  3946. else
  3947. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
  3948. end;
  3949. end;
  3950. else
  3951. begin
  3952. if cgsetflags or setflags then
  3953. a_reg_alloc(list,NR_DEFAULTFLAGS);
  3954. list.concat(setoppostfix(
  3955. taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmopThumb2[op],dst,src2,src1),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))));
  3956. end;
  3957. end;
  3958. maybeadjustresult(list,op,size,dst);
  3959. end;
  3960. procedure tthumb2cgarm.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  3961. var item: taicpu;
  3962. begin
  3963. list.concat(taicpu.op_cond(A_ITE, flags_to_cond(f)));
  3964. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
  3965. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond(flags_to_cond(f))));
  3966. end;
  3967. procedure tthumb2cgarm.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  3968. var
  3969. ref : treference;
  3970. shift : byte;
  3971. firstfloatreg,lastfloatreg,
  3972. r : byte;
  3973. regs : tcpuregisterset;
  3974. stackmisalignment: pint;
  3975. begin
  3976. LocalSize:=align(LocalSize,4);
  3977. { call instruction does not put anything on the stack }
  3978. stackmisalignment:=0;
  3979. if not(nostackframe) then
  3980. begin
  3981. firstfloatreg:=RS_NO;
  3982. { save floating point registers? }
  3983. for r:=RS_F0 to RS_F7 do
  3984. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  3985. begin
  3986. if firstfloatreg=RS_NO then
  3987. firstfloatreg:=r;
  3988. lastfloatreg:=r;
  3989. inc(stackmisalignment,12);
  3990. end;
  3991. a_reg_alloc(list,NR_STACK_POINTER_REG);
  3992. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  3993. begin
  3994. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  3995. a_reg_alloc(list,NR_R12);
  3996. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  3997. end;
  3998. { save int registers }
  3999. reference_reset(ref,4);
  4000. ref.index:=NR_STACK_POINTER_REG;
  4001. ref.addressmode:=AM_PREINDEXED;
  4002. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  4003. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  4004. regs:=regs+[RS_FRAME_POINTER_REG,RS_R14]
  4005. else if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
  4006. include(regs,RS_R14);
  4007. if regs<>[] then
  4008. begin
  4009. for r:=RS_R0 to RS_R15 do
  4010. if (r in regs) then
  4011. inc(stackmisalignment,4);
  4012. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,R_INTREGISTER,R_SUBWHOLE,regs),PF_FD));
  4013. end;
  4014. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  4015. begin
  4016. { the framepointer now points to the saved R15, so the saved
  4017. framepointer is at R11-12 (for get_caller_frame) }
  4018. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  4019. a_reg_dealloc(list,NR_R12);
  4020. end;
  4021. stackmisalignment:=stackmisalignment mod current_settings.alignment.localalignmax;
  4022. if (LocalSize<>0) or
  4023. ((stackmisalignment<>0) and
  4024. ((pi_do_call in current_procinfo.flags) or
  4025. (po_assembler in current_procinfo.procdef.procoptions))) then
  4026. begin
  4027. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  4028. if not(is_shifter_const(localsize,shift)) then
  4029. begin
  4030. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  4031. a_reg_alloc(list,NR_R12);
  4032. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  4033. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  4034. a_reg_dealloc(list,NR_R12);
  4035. end
  4036. else
  4037. begin
  4038. a_reg_dealloc(list,NR_R12);
  4039. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  4040. end;
  4041. end;
  4042. if firstfloatreg<>RS_NO then
  4043. begin
  4044. reference_reset(ref,4);
  4045. if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
  4046. begin
  4047. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  4048. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  4049. ref.base:=NR_R12;
  4050. end
  4051. else
  4052. begin
  4053. ref.base:=current_procinfo.framepointer;
  4054. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  4055. end;
  4056. list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  4057. lastfloatreg-firstfloatreg+1,ref));
  4058. end;
  4059. end;
  4060. end;
  4061. procedure tthumb2cgarm.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  4062. var
  4063. ref : treference;
  4064. firstfloatreg,lastfloatreg,
  4065. r : byte;
  4066. shift : byte;
  4067. regs : tcpuregisterset;
  4068. LocalSize : longint;
  4069. stackmisalignment: pint;
  4070. begin
  4071. if not(nostackframe) then
  4072. begin
  4073. stackmisalignment:=0;
  4074. { restore floating point register }
  4075. firstfloatreg:=RS_NO;
  4076. { save floating point registers? }
  4077. for r:=RS_F0 to RS_F7 do
  4078. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  4079. begin
  4080. if firstfloatreg=RS_NO then
  4081. firstfloatreg:=r;
  4082. lastfloatreg:=r;
  4083. { floating point register space is already included in
  4084. localsize below by calc_stackframe_size
  4085. inc(stackmisalignment,12);
  4086. }
  4087. end;
  4088. if firstfloatreg<>RS_NO then
  4089. begin
  4090. reference_reset(ref,4);
  4091. if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
  4092. begin
  4093. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  4094. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  4095. ref.base:=NR_R12;
  4096. end
  4097. else
  4098. begin
  4099. ref.base:=current_procinfo.framepointer;
  4100. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  4101. end;
  4102. list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  4103. lastfloatreg-firstfloatreg+1,ref));
  4104. end;
  4105. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  4106. if (pi_do_call in current_procinfo.flags) or (regs<>[]) then
  4107. begin
  4108. exclude(regs,RS_R14);
  4109. include(regs,RS_R15);
  4110. end;
  4111. if (current_procinfo.framepointer<>NR_STACK_POINTER_REG) then
  4112. regs:=regs+[RS_FRAME_POINTER_REG,RS_R15];
  4113. for r:=RS_R0 to RS_R15 do
  4114. if (r in regs) then
  4115. inc(stackmisalignment,4);
  4116. stackmisalignment:=stackmisalignment mod current_settings.alignment.localalignmax;
  4117. LocalSize:=current_procinfo.calc_stackframe_size;
  4118. if (LocalSize<>0) or
  4119. ((stackmisalignment<>0) and
  4120. ((pi_do_call in current_procinfo.flags) or
  4121. (po_assembler in current_procinfo.procdef.procoptions))) then
  4122. begin
  4123. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  4124. if not(is_shifter_const(LocalSize,shift)) then
  4125. begin
  4126. a_reg_alloc(list,NR_R12);
  4127. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  4128. list.concat(taicpu.op_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_R12));
  4129. a_reg_dealloc(list,NR_R12);
  4130. end
  4131. else
  4132. begin
  4133. a_reg_dealloc(list,NR_R12);
  4134. list.concat(taicpu.op_reg_const(A_ADD,NR_STACK_POINTER_REG,LocalSize));
  4135. end;
  4136. end;
  4137. if regs=[] then
  4138. list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
  4139. else
  4140. begin
  4141. reference_reset(ref,4);
  4142. ref.index:=NR_STACK_POINTER_REG;
  4143. ref.addressmode:=AM_PREINDEXED;
  4144. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,R_INTREGISTER,R_SUBWHOLE,regs),PF_FD));
  4145. end;
  4146. end
  4147. else
  4148. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14));
  4149. end;
  4150. function tthumb2cgarm.handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference;
  4151. var
  4152. tmpreg : tregister;
  4153. tmpref : treference;
  4154. l : tasmlabel;
  4155. so: tshifterop;
  4156. begin
  4157. tmpreg:=NR_NO;
  4158. { Be sure to have a base register }
  4159. if (ref.base=NR_NO) then
  4160. begin
  4161. if ref.shiftmode<>SM_None then
  4162. internalerror(200308294);
  4163. ref.base:=ref.index;
  4164. ref.index:=NR_NO;
  4165. end;
  4166. { absolute symbols can't be handled directly, we've to store the symbol reference
  4167. in the text segment and access it pc relative
  4168. For now, we assume that references where base or index equals to PC are already
  4169. relative, all other references are assumed to be absolute and thus they need
  4170. to be handled extra.
  4171. A proper solution would be to change refoptions to a set and store the information
  4172. if the symbol is absolute or relative there.
  4173. }
  4174. if (assigned(ref.symbol) and
  4175. not(is_pc(ref.base)) and
  4176. not(is_pc(ref.index))
  4177. ) or
  4178. { [#xxx] isn't a valid address operand }
  4179. ((ref.base=NR_NO) and (ref.index=NR_NO)) or
  4180. //(ref.offset<-4095) or
  4181. (ref.offset<-255) or
  4182. (ref.offset>4095) or
  4183. ((oppostfix in [PF_SB,PF_H,PF_SH]) and
  4184. ((ref.offset<-255) or
  4185. (ref.offset>255)
  4186. )
  4187. ) or
  4188. ((op in [A_LDF,A_STF,A_FLDS,A_FLDD,A_FSTS,A_FSTD]) and
  4189. ((ref.offset<-1020) or
  4190. (ref.offset>1020) or
  4191. { the usual pc relative symbol handling assumes possible offsets of +/- 4095 }
  4192. assigned(ref.symbol)
  4193. )
  4194. ) then
  4195. begin
  4196. reference_reset(tmpref,4);
  4197. { load symbol }
  4198. tmpreg:=getintregister(list,OS_INT);
  4199. if assigned(ref.symbol) then
  4200. begin
  4201. current_asmdata.getjumplabel(l);
  4202. cg.a_label(current_procinfo.aktlocaldata,l);
  4203. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  4204. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset));
  4205. { load consts entry }
  4206. tmpref.symbol:=l;
  4207. tmpref.base:=NR_R15;
  4208. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  4209. { in case of LDF/STF, we got rid of the NR_R15 }
  4210. if is_pc(ref.base) then
  4211. ref.base:=NR_NO;
  4212. if is_pc(ref.index) then
  4213. ref.index:=NR_NO;
  4214. end
  4215. else
  4216. a_load_const_reg(list,OS_ADDR,ref.offset,tmpreg);
  4217. if (ref.base<>NR_NO) then
  4218. begin
  4219. if ref.index<>NR_NO then
  4220. begin
  4221. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  4222. ref.base:=tmpreg;
  4223. end
  4224. else
  4225. begin
  4226. ref.index:=tmpreg;
  4227. ref.shiftimm:=0;
  4228. ref.signindex:=1;
  4229. ref.shiftmode:=SM_None;
  4230. end;
  4231. end
  4232. else
  4233. ref.base:=tmpreg;
  4234. ref.offset:=0;
  4235. ref.symbol:=nil;
  4236. end;
  4237. if (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then
  4238. begin
  4239. if tmpreg<>NR_NO then
  4240. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg,tmpreg)
  4241. else
  4242. begin
  4243. tmpreg:=getintregister(list,OS_ADDR);
  4244. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg);
  4245. ref.base:=tmpreg;
  4246. end;
  4247. ref.offset:=0;
  4248. end;
  4249. { Hack? Thumb2 doesn't allow PC indexed addressing modes(although it does in the specification) }
  4250. if (ref.base=NR_R15) and (ref.index<>NR_NO) and (ref.shiftmode <> sm_none) then
  4251. begin
  4252. tmpreg:=getintregister(list,OS_ADDR);
  4253. list.concat(taicpu.op_reg_reg(A_MOV, tmpreg, NR_R15));
  4254. ref.base := tmpreg;
  4255. end;
  4256. { floating point operations have only limited references
  4257. we expect here, that a base is already set }
  4258. if (op in [A_LDF,A_STF,A_FLDS,A_FLDD,A_FSTS,A_FSTD]) and (ref.index<>NR_NO) then
  4259. begin
  4260. if ref.shiftmode<>SM_none then
  4261. internalerror(200309121);
  4262. if tmpreg<>NR_NO then
  4263. begin
  4264. if ref.base=tmpreg then
  4265. begin
  4266. if ref.signindex<0 then
  4267. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,tmpreg,ref.index))
  4268. else
  4269. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg,ref.index));
  4270. ref.index:=NR_NO;
  4271. end
  4272. else
  4273. begin
  4274. if ref.index<>tmpreg then
  4275. internalerror(200403161);
  4276. if ref.signindex<0 then
  4277. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,ref.base,tmpreg))
  4278. else
  4279. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  4280. ref.base:=tmpreg;
  4281. ref.index:=NR_NO;
  4282. end;
  4283. end
  4284. else
  4285. begin
  4286. tmpreg:=getintregister(list,OS_ADDR);
  4287. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
  4288. ref.base:=tmpreg;
  4289. ref.index:=NR_NO;
  4290. end;
  4291. end;
  4292. list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
  4293. Result := ref;
  4294. end;
  4295. procedure tthumb2cgarm.a_loadmm_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister; shuffle: pmmshuffle);
  4296. var
  4297. instr: taicpu;
  4298. begin
  4299. if (fromsize=OS_F32) and
  4300. (tosize=OS_F32) then
  4301. begin
  4302. instr:=setoppostfix(taicpu.op_reg_reg(A_VMOV,reg2,reg1), PF_F32);
  4303. list.Concat(instr);
  4304. add_move_instruction(instr);
  4305. end
  4306. else if (fromsize=OS_F64) and
  4307. (tosize=OS_F64) then
  4308. begin
  4309. //list.Concat(setoppostfix(taicpu.op_reg_reg(A_VMOV,tregister(longint(reg2)+1),tregister(longint(reg1)+1)), PF_F32));
  4310. //list.Concat(setoppostfix(taicpu.op_reg_reg(A_VMOV,reg2,reg1), PF_F32));
  4311. end
  4312. else if (fromsize=OS_F32) and
  4313. (tosize=OS_F64) then
  4314. //list.Concat(setoppostfix(taicpu.op_reg_reg(A_VCVT,reg2,reg1), PF_F32))
  4315. begin
  4316. //list.concat(nil);
  4317. end;
  4318. end;
  4319. procedure tthumb2cgarm.a_loadmm_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister; shuffle: pmmshuffle);
  4320. var
  4321. href: treference;
  4322. tmpreg: TRegister;
  4323. so: tshifterop;
  4324. begin
  4325. href:=ref;
  4326. if (href.base<>NR_NO) and
  4327. (href.index<>NR_NO) then
  4328. begin
  4329. tmpreg:=getintregister(list,OS_INT);
  4330. if href.shiftmode<>SM_None then
  4331. begin
  4332. so.rs:=href.index;
  4333. so.shiftimm:=href.shiftimm;
  4334. so.shiftmode:=href.shiftmode;
  4335. list.concat(taicpu.op_reg_reg_shifterop(A_ADD,tmpreg,href.base,so));
  4336. end
  4337. else
  4338. a_op_reg_reg_reg(list,OP_ADD,OS_INT,href.index,href.base,tmpreg);
  4339. reference_reset_base(href,tmpreg,href.offset,0);
  4340. end;
  4341. if assigned(href.symbol) then
  4342. begin
  4343. tmpreg:=getintregister(list,OS_INT);
  4344. a_loadaddr_ref_reg(list,href,tmpreg);
  4345. reference_reset_base(href,tmpreg,0,0);
  4346. end;
  4347. if fromsize=OS_F32 then
  4348. list.Concat(setoppostfix(taicpu.op_reg_ref(A_VLDR,reg,href), PF_F32))
  4349. else
  4350. list.Concat(setoppostfix(taicpu.op_reg_ref(A_VLDR,reg,href), PF_F64));
  4351. end;
  4352. procedure tthumb2cgarm.a_loadmm_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference; shuffle: pmmshuffle);
  4353. var
  4354. href: treference;
  4355. so: tshifterop;
  4356. tmpreg: TRegister;
  4357. begin
  4358. href:=ref;
  4359. if (href.base<>NR_NO) and
  4360. (href.index<>NR_NO) then
  4361. begin
  4362. tmpreg:=getintregister(list,OS_INT);
  4363. if href.shiftmode<>SM_None then
  4364. begin
  4365. so.rs:=href.index;
  4366. so.shiftimm:=href.shiftimm;
  4367. so.shiftmode:=href.shiftmode;
  4368. list.concat(taicpu.op_reg_reg_shifterop(A_ADD,tmpreg,href.base,so));
  4369. end
  4370. else
  4371. a_op_reg_reg_reg(list,OP_ADD,OS_INT,href.index,href.base,tmpreg);
  4372. reference_reset_base(href,tmpreg,href.offset,0);
  4373. end;
  4374. if assigned(href.symbol) then
  4375. begin
  4376. tmpreg:=getintregister(list,OS_INT);
  4377. a_loadaddr_ref_reg(list,href,tmpreg);
  4378. reference_reset_base(href,tmpreg,0,0);
  4379. end;
  4380. if fromsize=OS_F32 then
  4381. list.Concat(setoppostfix(taicpu.op_reg_ref(A_VSTR,reg,href), PF_32))
  4382. else
  4383. list.Concat(setoppostfix(taicpu.op_reg_ref(A_VSTR,reg,href), PF_64));
  4384. end;
  4385. procedure tthumb2cgarm.a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize: tcgsize; intreg, mmreg: tregister; shuffle: pmmshuffle);
  4386. begin
  4387. if //(shuffle=nil) and
  4388. (tosize=OS_F32) then
  4389. list.Concat(taicpu.op_reg_reg(A_VMOV,mmreg,intreg))
  4390. else
  4391. internalerror(2012100813);
  4392. end;
  4393. procedure tthumb2cgarm.a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize: tcgsize; mmreg, intreg: tregister; shuffle: pmmshuffle);
  4394. begin
  4395. if //(shuffle=nil) and
  4396. (fromsize=OS_F32) then
  4397. list.Concat(taicpu.op_reg_reg(A_VMOV,intreg,mmreg))
  4398. else
  4399. internalerror(2012100814);
  4400. end;
  4401. procedure tthumb2cg64farm.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  4402. var tmpreg: tregister;
  4403. begin
  4404. case op of
  4405. OP_NEG:
  4406. begin
  4407. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4408. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  4409. tmpreg:=cg.getintregister(list,OS_32);
  4410. list.concat(taicpu.op_reg_const(A_MOV,tmpreg,0));
  4411. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,tmpreg,regsrc.reghi));
  4412. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  4413. end;
  4414. else
  4415. inherited a_op64_reg_reg(list, op, size, regsrc, regdst);
  4416. end;
  4417. end;
  4418. procedure tthumbcg64farm.a_op64_reg_reg(list: TAsmList; op: TOpCG; size: tcgsize; regsrc, regdst: tregister64);
  4419. begin
  4420. case op of
  4421. OP_NEG:
  4422. begin
  4423. list.concat(taicpu.op_reg_const(A_MOV,regdst.reglo,0));
  4424. list.concat(taicpu.op_reg_const(A_MOV,regdst.reghi,0));
  4425. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4426. list.concat(taicpu.op_reg_reg(A_SUB,regdst.reglo,regsrc.reglo));
  4427. list.concat(taicpu.op_reg_reg(A_SBC,regdst.reghi,regsrc.reghi));
  4428. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  4429. end;
  4430. OP_NOT:
  4431. begin
  4432. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  4433. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  4434. end;
  4435. OP_AND,OP_OR,OP_XOR:
  4436. begin
  4437. cg.a_op_reg_reg(list,op,OS_32,regsrc.reglo,regdst.reglo);
  4438. cg.a_op_reg_reg(list,op,OS_32,regsrc.reghi,regdst.reghi);
  4439. end;
  4440. OP_ADD:
  4441. begin
  4442. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4443. list.concat(taicpu.op_reg_reg(A_ADD,regdst.reglo,regsrc.reglo));
  4444. list.concat(taicpu.op_reg_reg(A_ADC,regdst.reghi,regsrc.reghi));
  4445. end;
  4446. OP_SUB:
  4447. begin
  4448. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4449. list.concat(taicpu.op_reg_reg(A_SUB,regdst.reglo,regsrc.reglo));
  4450. list.concat(taicpu.op_reg_reg(A_SBC,regdst.reghi,regsrc.reghi));
  4451. end;
  4452. else
  4453. internalerror(2003083101);
  4454. end;
  4455. end;
  4456. procedure tthumbcg64farm.a_op64_const_reg(list: TAsmList; op: TOpCG; size: tcgsize; value: int64; reg: tregister64);
  4457. var
  4458. tmpreg : tregister;
  4459. b : byte;
  4460. begin
  4461. case op of
  4462. OP_AND,OP_OR,OP_XOR:
  4463. begin
  4464. cg.a_op_const_reg(list,op,OS_32,aint(lo(value)),reg.reglo);
  4465. cg.a_op_const_reg(list,op,OS_32,aint(hi(value)),reg.reghi);
  4466. end;
  4467. OP_ADD:
  4468. begin
  4469. if (aint(lo(value))>=0) and (aint(lo(value))<=255) then
  4470. begin
  4471. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4472. list.concat(taicpu.op_reg_const(A_ADD,reg.reglo,aint(lo(value))));
  4473. end
  4474. else
  4475. begin
  4476. tmpreg:=cg.getintregister(list,OS_32);
  4477. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  4478. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4479. list.concat(taicpu.op_reg_reg(A_ADD,reg.reglo,tmpreg));
  4480. end;
  4481. tmpreg:=cg.getintregister(list,OS_32);
  4482. cg.a_load_const_reg(list,OS_32,aint(hi(value)),tmpreg);
  4483. list.concat(taicpu.op_reg_reg(A_ADC,reg.reghi,tmpreg));
  4484. end;
  4485. OP_SUB:
  4486. begin
  4487. if (aint(lo(value))>=0) and (aint(lo(value))<=255) then
  4488. begin
  4489. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4490. list.concat(taicpu.op_reg_const(A_SUB,reg.reglo,aint(lo(value))))
  4491. end
  4492. else
  4493. begin
  4494. tmpreg:=cg.getintregister(list,OS_32);
  4495. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  4496. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  4497. list.concat(taicpu.op_reg_reg(A_SUB,reg.reglo,tmpreg));
  4498. end;
  4499. tmpreg:=cg.getintregister(list,OS_32);
  4500. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  4501. list.concat(taicpu.op_reg_reg(A_SBC,reg.reghi,tmpreg));
  4502. end;
  4503. else
  4504. internalerror(2003083101);
  4505. end;
  4506. end;
  4507. procedure create_codegen;
  4508. begin
  4509. if current_settings.cputype in cpu_thumb2 then
  4510. begin
  4511. cg:=tthumb2cgarm.create;
  4512. cg64:=tthumb2cg64farm.create;
  4513. casmoptimizer:=TCpuThumb2AsmOptimizer;
  4514. end
  4515. else if current_settings.cputype in cpu_thumb then
  4516. begin
  4517. cg:=tthumbcgarm.create;
  4518. cg64:=tthumbcg64farm.create;
  4519. // casmoptimizer:=TCpuThumbAsmOptimizer;
  4520. end
  4521. else
  4522. begin
  4523. cg:=tarmcgarm.create;
  4524. cg64:=tarmcg64farm.create;
  4525. casmoptimizer:=TCpuAsmOptimizer;
  4526. end;
  4527. end;
  4528. end.