cgcpu.pas 144 KB

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