cgcpu.pas 150 KB

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