cgcpu.pas 149 KB

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