cgcpu.pas 157 KB

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