cgcpu.pas 164 KB

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