2
0

cgcpu.pas 150 KB

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