cgcpu.pas 212 KB

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