cgcpu.pas 149 KB

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