cgcpu.pas 149 KB

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