cgcpu.pas 149 KB

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