cgcpu.pas 158 KB

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