cgcpu.pas 153 KB

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