cgcpu.pas 150 KB

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