cgcpu.pas 213 KB

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