cgcpu.pas 151 KB

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