cgcpu.pas 150 KB

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