cgcpu.pas 143 KB

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