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