cgcpu.pas 144 KB

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