cgcpu.pas 212 KB

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