cgcpu.pas 151 KB

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