2
0

cgcpu.pas 127 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278
  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_param_const(list : TAsmList;size : tcgsize;a : aint;const paraloc : TCGPara);override;
  32. procedure a_param_ref(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);override;
  33. procedure a_paramaddr_ref(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: aint; 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: aint; 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: aint; 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_paramfpu_ref(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 : aint;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 : aint);override;
  67. procedure g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : aint);override;
  68. procedure g_concatcopy_move(list : TAsmList;const source,dest : treference;len : aint);
  69. procedure g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : aint;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: aint); override;
  79. procedure g_stackpointer_alloc(list : TAsmList;size : longint);override;
  80. private
  81. { clear out potential overflow bits from 8 or 16 bit operations }
  82. { the upper 24/16 bits of a register after an operation }
  83. procedure maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  84. function get_darwin_call_stub(const s: string; weak: boolean): tasmsymbol;
  85. end;
  86. tarmcgarm = class(tcgarm)
  87. procedure init_register_allocators;override;
  88. procedure done_register_allocators;override;
  89. procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);override;
  90. procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  91. end;
  92. tcg64farm = class(tcg64f32)
  93. procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  94. procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
  95. procedure a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);override;
  96. procedure a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);override;
  97. procedure a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
  98. procedure a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
  99. end;
  100. Tthumb2cgarm = class(tcgarm)
  101. procedure init_register_allocators;override;
  102. procedure done_register_allocators;override;
  103. procedure a_call_reg(list : TAsmList;reg: tregister);override;
  104. procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);override;
  105. procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  106. procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  107. procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  108. procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  109. procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
  110. procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
  111. function handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference; override;
  112. end;
  113. tthumb2cg64farm = class(tcg64farm)
  114. procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  115. end;
  116. const
  117. OpCmp2AsmCond : Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_GT,
  118. C_LT,C_GE,C_LE,C_NE,C_LS,C_CC,C_CS,C_HI);
  119. winstackpagesize = 4096;
  120. function get_fpu_postfix(def : tdef) : toppostfix;
  121. procedure create_codegen;
  122. implementation
  123. uses
  124. globals,verbose,systems,cutils,
  125. aopt,aoptcpu,
  126. fmodule,
  127. symconst,symsym,
  128. tgobj,
  129. procinfo,cpupi,
  130. paramgr;
  131. function get_fpu_postfix(def : tdef) : toppostfix;
  132. begin
  133. if def.typ=floatdef then
  134. begin
  135. case tfloatdef(def).floattype of
  136. s32real:
  137. result:=PF_S;
  138. s64real:
  139. result:=PF_D;
  140. s80real:
  141. result:=PF_E;
  142. else
  143. internalerror(200401272);
  144. end;
  145. end
  146. else
  147. internalerror(200401271);
  148. end;
  149. procedure tarmcgarm.init_register_allocators;
  150. begin
  151. inherited init_register_allocators;
  152. { currently, we save R14 always, so we can use it }
  153. if (target_info.system<>system_arm_darwin) then
  154. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
  155. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  156. RS_R9,RS_R10,RS_R12,RS_R14],first_int_imreg,[])
  157. else
  158. { r9 is not available on Darwin according to the llvm code generator }
  159. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
  160. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  161. RS_R10,RS_R12,RS_R14],first_int_imreg,[]);
  162. rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
  163. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7],first_fpu_imreg,[]);
  164. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
  165. [RS_S0,RS_S1,RS_R2,RS_R3,RS_R4,RS_S31],first_mm_imreg,[]);
  166. end;
  167. procedure tarmcgarm.done_register_allocators;
  168. begin
  169. rg[R_INTREGISTER].free;
  170. rg[R_FPUREGISTER].free;
  171. rg[R_MMREGISTER].free;
  172. inherited done_register_allocators;
  173. end;
  174. procedure tarmcgarm.a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);
  175. var
  176. imm_shift : byte;
  177. l : tasmlabel;
  178. hr : treference;
  179. begin
  180. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  181. internalerror(2002090902);
  182. if is_shifter_const(a,imm_shift) then
  183. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  184. else if is_shifter_const(not(a),imm_shift) then
  185. list.concat(taicpu.op_reg_const(A_MVN,reg,not(a)))
  186. { loading of constants with mov and orr }
  187. else if (is_shifter_const(a-byte(a),imm_shift)) then
  188. begin
  189. list.concat(taicpu.op_reg_const(A_MOV,reg,a-byte(a)));
  190. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,byte(a)));
  191. end
  192. else if (is_shifter_const(a-word(a),imm_shift)) and (is_shifter_const(word(a),imm_shift)) then
  193. begin
  194. list.concat(taicpu.op_reg_const(A_MOV,reg,a-word(a)));
  195. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,word(a)));
  196. end
  197. else if (is_shifter_const(a-(dword(a) shl 8) shr 8,imm_shift)) and (is_shifter_const((dword(a) shl 8) shr 8,imm_shift)) then
  198. begin
  199. list.concat(taicpu.op_reg_const(A_MOV,reg,a-(dword(a) shl 8) shr 8));
  200. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,(dword(a) shl 8) shr 8));
  201. end
  202. else
  203. begin
  204. reference_reset(hr,4);
  205. current_asmdata.getjumplabel(l);
  206. cg.a_label(current_procinfo.aktlocaldata,l);
  207. hr.symboldata:=current_procinfo.aktlocaldata.last;
  208. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
  209. hr.symbol:=l;
  210. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  211. end;
  212. end;
  213. procedure tarmcgarm.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  214. var
  215. oppostfix:toppostfix;
  216. usedtmpref: treference;
  217. tmpreg,tmpreg2 : tregister;
  218. so : tshifterop;
  219. dir : integer;
  220. begin
  221. if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then
  222. FromSize := ToSize;
  223. case FromSize of
  224. { signed integer registers }
  225. OS_8:
  226. oppostfix:=PF_B;
  227. OS_S8:
  228. oppostfix:=PF_SB;
  229. OS_16:
  230. oppostfix:=PF_H;
  231. OS_S16:
  232. oppostfix:=PF_SH;
  233. OS_32,
  234. OS_S32:
  235. oppostfix:=PF_None;
  236. else
  237. InternalError(200308297);
  238. end;
  239. if (ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[fromsize]) then
  240. begin
  241. if target_info.endian=endian_big then
  242. dir:=-1
  243. else
  244. dir:=1;
  245. case FromSize of
  246. OS_16,OS_S16:
  247. begin
  248. { only complicated references need an extra loadaddr }
  249. if assigned(ref.symbol) or
  250. (ref.index<>NR_NO) or
  251. (ref.offset<-4095) or
  252. (ref.offset>4094) or
  253. { sometimes the compiler reused registers }
  254. (reg=ref.index) or
  255. (reg=ref.base) then
  256. begin
  257. tmpreg2:=getintregister(list,OS_INT);
  258. a_loadaddr_ref_reg(list,ref,tmpreg2);
  259. reference_reset_base(usedtmpref,tmpreg2,0,ref.alignment);
  260. end
  261. else
  262. usedtmpref:=ref;
  263. if target_info.endian=endian_big then
  264. inc(usedtmpref.offset,1);
  265. shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8;
  266. tmpreg:=getintregister(list,OS_INT);
  267. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  268. inc(usedtmpref.offset,dir);
  269. if FromSize=OS_16 then
  270. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg)
  271. else
  272. a_internal_load_ref_reg(list,OS_S8,OS_S8,usedtmpref,tmpreg);
  273. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  274. end;
  275. OS_32,OS_S32:
  276. begin
  277. tmpreg:=getintregister(list,OS_INT);
  278. { only complicated references need an extra loadaddr }
  279. if assigned(ref.symbol) or
  280. (ref.index<>NR_NO) or
  281. (ref.offset<-4095) or
  282. (ref.offset>4092) or
  283. { sometimes the compiler reused registers }
  284. (reg=ref.index) or
  285. (reg=ref.base) then
  286. begin
  287. tmpreg2:=getintregister(list,OS_INT);
  288. a_loadaddr_ref_reg(list,ref,tmpreg2);
  289. reference_reset_base(usedtmpref,tmpreg2,0,ref.alignment);
  290. end
  291. else
  292. usedtmpref:=ref;
  293. shifterop_reset(so);so.shiftmode:=SM_LSL;
  294. if ref.alignment=2 then
  295. begin
  296. if target_info.endian=endian_big then
  297. inc(usedtmpref.offset,2);
  298. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,reg);
  299. inc(usedtmpref.offset,dir*2);
  300. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,tmpreg);
  301. so.shiftimm:=16;
  302. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  303. end
  304. else
  305. begin
  306. if target_info.endian=endian_big then
  307. inc(usedtmpref.offset,3);
  308. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  309. inc(usedtmpref.offset,dir);
  310. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  311. so.shiftimm:=8;
  312. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  313. inc(usedtmpref.offset,dir);
  314. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  315. so.shiftimm:=16;
  316. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  317. inc(usedtmpref.offset,dir);
  318. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  319. so.shiftimm:=24;
  320. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  321. end;
  322. end
  323. else
  324. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  325. end;
  326. end
  327. else
  328. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  329. if (fromsize=OS_S8) and (tosize = OS_16) then
  330. a_load_reg_reg(list,OS_16,OS_32,reg,reg);
  331. end;
  332. procedure tcgarm.a_param_const(list : TAsmList;size : tcgsize;a : aint;const paraloc : TCGPara);
  333. var
  334. ref: treference;
  335. begin
  336. paraloc.check_simple_location;
  337. case paraloc.location^.loc of
  338. LOC_REGISTER,LOC_CREGISTER:
  339. a_load_const_reg(list,size,a,paraloc.location^.register);
  340. LOC_REFERENCE:
  341. begin
  342. reference_reset(ref,paraloc.alignment);
  343. ref.base:=paraloc.location^.reference.index;
  344. ref.offset:=paraloc.location^.reference.offset;
  345. a_load_const_ref(list,size,a,ref);
  346. end;
  347. else
  348. internalerror(2002081101);
  349. end;
  350. end;
  351. procedure tcgarm.a_param_ref(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);
  352. var
  353. tmpref, ref: treference;
  354. location: pcgparalocation;
  355. sizeleft: aint;
  356. begin
  357. location := paraloc.location;
  358. tmpref := r;
  359. sizeleft := paraloc.intsize;
  360. while assigned(location) do
  361. begin
  362. case location^.loc of
  363. LOC_REGISTER,LOC_CREGISTER:
  364. a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
  365. LOC_REFERENCE:
  366. begin
  367. reference_reset_base(ref,location^.reference.index,location^.reference.offset,paraloc.alignment);
  368. { doubles in softemu mode have a strange order of registers and references }
  369. if location^.size=OS_32 then
  370. g_concatcopy(list,tmpref,ref,4)
  371. else
  372. begin
  373. g_concatcopy(list,tmpref,ref,sizeleft);
  374. if assigned(location^.next) then
  375. internalerror(2005010710);
  376. end;
  377. end;
  378. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  379. case location^.size of
  380. OS_F32, OS_F64:
  381. a_loadfpu_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
  382. else
  383. internalerror(2002072801);
  384. end;
  385. LOC_VOID:
  386. begin
  387. // nothing to do
  388. end;
  389. else
  390. internalerror(2002081103);
  391. end;
  392. inc(tmpref.offset,tcgsize2size[location^.size]);
  393. dec(sizeleft,tcgsize2size[location^.size]);
  394. location := location^.next;
  395. end;
  396. end;
  397. procedure tcgarm.a_paramaddr_ref(list : TAsmList;const r : treference;const paraloc : TCGPara);
  398. var
  399. ref: treference;
  400. tmpreg: tregister;
  401. begin
  402. paraloc.check_simple_location;
  403. case paraloc.location^.loc of
  404. LOC_REGISTER,LOC_CREGISTER:
  405. a_loadaddr_ref_reg(list,r,paraloc.location^.register);
  406. LOC_REFERENCE:
  407. begin
  408. reference_reset(ref,paraloc.alignment);
  409. ref.base := paraloc.location^.reference.index;
  410. ref.offset := paraloc.location^.reference.offset;
  411. tmpreg := getintregister(list,OS_ADDR);
  412. a_loadaddr_ref_reg(list,r,tmpreg);
  413. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  414. end;
  415. else
  416. internalerror(2002080701);
  417. end;
  418. end;
  419. procedure tcgarm.a_call_name(list : TAsmList;const s : string; weak: boolean);
  420. begin
  421. if target_info.system<>system_arm_darwin then
  422. if not weak then
  423. list.concat(taicpu.op_sym(A_BL,current_asmdata.RefAsmSymbol(s)))
  424. else
  425. list.concat(taicpu.op_sym(A_BL,current_asmdata.WeakRefAsmSymbol(s)))
  426. else
  427. list.concat(taicpu.op_sym(A_BL,get_darwin_call_stub(s,weak)));
  428. {
  429. the compiler does not properly set this flag anymore in pass 1, and
  430. for now we only need it after pass 2 (I hope) (JM)
  431. if not(pi_do_call in current_procinfo.flags) then
  432. internalerror(2003060703);
  433. }
  434. include(current_procinfo.flags,pi_do_call);
  435. end;
  436. procedure tcgarm.a_call_reg(list : TAsmList;reg: tregister);
  437. begin
  438. list.concat(taicpu.op_reg_reg(A_MOV,NR_R14,NR_PC));
  439. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,reg));
  440. {
  441. the compiler does not properly set this flag anymore in pass 1, and
  442. for now we only need it after pass 2 (I hope) (JM)
  443. if not(pi_do_call in current_procinfo.flags) then
  444. internalerror(2003060703);
  445. }
  446. include(current_procinfo.flags,pi_do_call);
  447. end;
  448. procedure tcgarm.a_call_ref(list : TAsmList;ref: treference);
  449. begin
  450. a_reg_alloc(list,NR_R12);
  451. a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,NR_R12);
  452. list.concat(taicpu.op_reg_reg(A_MOV,NR_R14,NR_PC));
  453. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
  454. a_reg_dealloc(list,NR_R12);
  455. include(current_procinfo.flags,pi_do_call);
  456. end;
  457. procedure tcgarm.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister);
  458. begin
  459. a_op_const_reg_reg(list,op,size,a,reg,reg);
  460. end;
  461. procedure tcgarm.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  462. begin
  463. case op of
  464. OP_NEG:
  465. list.concat(taicpu.op_reg_reg_const(A_RSB,dst,src,0));
  466. OP_NOT:
  467. begin
  468. list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
  469. case size of
  470. OS_8 :
  471. a_op_const_reg_reg(list,OP_AND,OS_INT,$ff,dst,dst);
  472. OS_16 :
  473. a_op_const_reg_reg(list,OP_AND,OS_INT,$ffff,dst,dst);
  474. end;
  475. end
  476. else
  477. a_op_reg_reg_reg(list,op,OS_32,src,dst,dst);
  478. end;
  479. end;
  480. const
  481. op_reg_reg_opcg2asmop: array[TOpCG] of tasmop =
  482. (A_NONE,A_MOV,A_ADD,A_AND,A_NONE,A_NONE,A_MUL,A_MUL,A_NONE,A_NONE,A_ORR,
  483. A_NONE,A_NONE,A_NONE,A_SUB,A_EOR,A_NONE,A_NONE);
  484. procedure tcgarm.a_op_const_reg_reg(list: TAsmList; op: TOpCg;
  485. size: tcgsize; a: aint; src, dst: tregister);
  486. var
  487. ovloc : tlocation;
  488. begin
  489. a_op_const_reg_reg_checkoverflow(list,op,size,a,src,dst,false,ovloc);
  490. end;
  491. procedure tcgarm.a_op_reg_reg_reg(list: TAsmList; op: TOpCg;
  492. size: tcgsize; src1, src2, dst: tregister);
  493. var
  494. ovloc : tlocation;
  495. begin
  496. a_op_reg_reg_reg_checkoverflow(list,op,size,src1,src2,dst,false,ovloc);
  497. end;
  498. procedure tcgarm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);
  499. var
  500. shift : byte;
  501. tmpreg : tregister;
  502. so : tshifterop;
  503. l1 : longint;
  504. begin
  505. ovloc.loc:=LOC_VOID;
  506. if {$ifopt R+}(a<>-2147483648) and{$endif} is_shifter_const(-a,shift) then
  507. case op of
  508. OP_ADD:
  509. begin
  510. op:=OP_SUB;
  511. a:=aint(dword(-a));
  512. end;
  513. OP_SUB:
  514. begin
  515. op:=OP_ADD;
  516. a:=aint(dword(-a));
  517. end
  518. end;
  519. if is_shifter_const(a,shift) and not(op in [OP_IMUL,OP_MUL]) then
  520. case op of
  521. OP_NEG,OP_NOT,
  522. OP_DIV,OP_IDIV:
  523. internalerror(200308281);
  524. OP_SHL:
  525. begin
  526. if a>32 then
  527. internalerror(200308294);
  528. if a<>0 then
  529. begin
  530. shifterop_reset(so);
  531. so.shiftmode:=SM_LSL;
  532. so.shiftimm:=a;
  533. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  534. end
  535. else
  536. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  537. end;
  538. OP_ROL:
  539. begin
  540. if a>32 then
  541. internalerror(200308294);
  542. if a<>0 then
  543. begin
  544. shifterop_reset(so);
  545. so.shiftmode:=SM_ROR;
  546. so.shiftimm:=32-a;
  547. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  548. end
  549. else
  550. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  551. end;
  552. OP_ROR:
  553. begin
  554. if a>32 then
  555. internalerror(200308294);
  556. if a<>0 then
  557. begin
  558. shifterop_reset(so);
  559. so.shiftmode:=SM_ROR;
  560. so.shiftimm:=a;
  561. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  562. end
  563. else
  564. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  565. end;
  566. OP_SHR:
  567. begin
  568. if a>32 then
  569. internalerror(200308292);
  570. shifterop_reset(so);
  571. if a<>0 then
  572. begin
  573. so.shiftmode:=SM_LSR;
  574. so.shiftimm:=a;
  575. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  576. end
  577. else
  578. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  579. end;
  580. OP_SAR:
  581. begin
  582. if a>32 then
  583. internalerror(200308295);
  584. if a<>0 then
  585. begin
  586. shifterop_reset(so);
  587. so.shiftmode:=SM_ASR;
  588. so.shiftimm:=a;
  589. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  590. end
  591. else
  592. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  593. end;
  594. else
  595. {if (op in [OP_SUB, OP_ADD]) and
  596. ((a < 0) or
  597. (a > 4095)) then
  598. begin
  599. tmpreg:=getintregister(list,size);
  600. list.concat(taicpu.op_reg_const(A_MOVT, tmpreg, (a shr 16) and $FFFF));
  601. list.concat(taicpu.op_reg_const(A_MOV, tmpreg, a and $FFFF));
  602. list.concat(setoppostfix(taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src,tmpreg),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  603. ));
  604. end
  605. else}
  606. list.concat(setoppostfix(
  607. taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  608. ));
  609. if (cgsetflags or setflags) and (size in [OS_8,OS_16,OS_32]) then
  610. begin
  611. ovloc.loc:=LOC_FLAGS;
  612. case op of
  613. OP_ADD:
  614. ovloc.resflags:=F_CS;
  615. OP_SUB:
  616. ovloc.resflags:=F_CC;
  617. end;
  618. end;
  619. end
  620. else
  621. begin
  622. { there could be added some more sophisticated optimizations }
  623. if (op in [OP_MUL,OP_IMUL]) and (a=1) then
  624. a_load_reg_reg(list,size,size,src,dst)
  625. else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
  626. a_load_const_reg(list,size,0,dst)
  627. else if (op in [OP_IMUL]) and (a=-1) then
  628. a_op_reg_reg(list,OP_NEG,size,src,dst)
  629. { we do this here instead in the peephole optimizer because
  630. it saves us a register }
  631. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) and not(cgsetflags or setflags) then
  632. a_op_const_reg_reg(list,OP_SHL,size,l1,src,dst)
  633. { for example : b=a*5 -> b=a*4+a with add instruction and shl }
  634. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a-1,l1) and not(cgsetflags or setflags) then
  635. begin
  636. if l1>32 then{roozbeh does this ever happen?}
  637. internalerror(200308296);
  638. shifterop_reset(so);
  639. so.shiftmode:=SM_LSL;
  640. so.shiftimm:=l1;
  641. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,dst,src,src,so));
  642. end
  643. else
  644. begin
  645. tmpreg:=getintregister(list,size);
  646. a_load_const_reg(list,size,a,tmpreg);
  647. a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,setflags,ovloc);
  648. end;
  649. end;
  650. maybeadjustresult(list,op,size,dst);
  651. end;
  652. procedure tcgarm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);
  653. var
  654. so : tshifterop;
  655. tmpreg,overflowreg : tregister;
  656. asmop : tasmop;
  657. begin
  658. ovloc.loc:=LOC_VOID;
  659. case op of
  660. OP_NEG,OP_NOT,
  661. OP_DIV,OP_IDIV:
  662. internalerror(200308281);
  663. OP_SHL:
  664. begin
  665. shifterop_reset(so);
  666. so.rs:=src1;
  667. so.shiftmode:=SM_LSL;
  668. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  669. end;
  670. OP_SHR:
  671. begin
  672. shifterop_reset(so);
  673. so.rs:=src1;
  674. so.shiftmode:=SM_LSR;
  675. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  676. end;
  677. OP_SAR:
  678. begin
  679. shifterop_reset(so);
  680. so.rs:=src1;
  681. so.shiftmode:=SM_ASR;
  682. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  683. end;
  684. OP_ROL:
  685. begin
  686. if not(size in [OS_32,OS_S32]) then
  687. internalerror(2008072801);
  688. { simulate ROL by ror'ing 32-value }
  689. tmpreg:=getintregister(list,OS_32);
  690. list.concat(taicpu.op_reg_const(A_MOV,tmpreg,32));
  691. list.concat(taicpu.op_reg_reg_reg(A_SUB,src1,tmpreg,src1));
  692. shifterop_reset(so);
  693. so.rs:=src1;
  694. so.shiftmode:=SM_ROR;
  695. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  696. end;
  697. OP_ROR:
  698. begin
  699. if not(size in [OS_32,OS_S32]) then
  700. internalerror(2008072802);
  701. shifterop_reset(so);
  702. so.rs:=src1;
  703. so.shiftmode:=SM_ROR;
  704. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  705. end;
  706. OP_IMUL,
  707. OP_MUL:
  708. begin
  709. if cgsetflags or setflags then
  710. begin
  711. overflowreg:=getintregister(list,size);
  712. if op=OP_IMUL then
  713. asmop:=A_SMULL
  714. else
  715. asmop:=A_UMULL;
  716. { the arm doesn't allow that rd and rm are the same }
  717. if dst=src2 then
  718. begin
  719. if dst<>src1 then
  720. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src1,src2))
  721. else
  722. begin
  723. tmpreg:=getintregister(list,size);
  724. a_load_reg_reg(list,size,size,src2,dst);
  725. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,tmpreg,src1));
  726. end;
  727. end
  728. else
  729. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src2,src1));
  730. if op=OP_IMUL then
  731. begin
  732. shifterop_reset(so);
  733. so.shiftmode:=SM_ASR;
  734. so.shiftimm:=31;
  735. list.concat(taicpu.op_reg_reg_shifterop(A_CMP,overflowreg,dst,so));
  736. end
  737. else
  738. list.concat(taicpu.op_reg_const(A_CMP,overflowreg,0));
  739. ovloc.loc:=LOC_FLAGS;
  740. ovloc.resflags:=F_NE;
  741. end
  742. else
  743. begin
  744. { the arm doesn't allow that rd and rm are the same }
  745. if dst=src2 then
  746. begin
  747. if dst<>src1 then
  748. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
  749. else
  750. begin
  751. tmpreg:=getintregister(list,size);
  752. a_load_reg_reg(list,size,size,src2,dst);
  753. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,tmpreg,src1));
  754. end;
  755. end
  756. else
  757. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
  758. end;
  759. end;
  760. else
  761. list.concat(setoppostfix(
  762. taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  763. ));
  764. end;
  765. maybeadjustresult(list,op,size,dst);
  766. end;
  767. function tcgarm.handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference;
  768. var
  769. tmpreg : tregister;
  770. tmpref : treference;
  771. l : tasmlabel;
  772. begin
  773. tmpreg:=NR_NO;
  774. { Be sure to have a base register }
  775. if (ref.base=NR_NO) then
  776. begin
  777. if ref.shiftmode<>SM_None then
  778. internalerror(200308294);
  779. ref.base:=ref.index;
  780. ref.index:=NR_NO;
  781. end;
  782. { absolute symbols can't be handled directly, we've to store the symbol reference
  783. in the text segment and access it pc relative
  784. For now, we assume that references where base or index equals to PC are already
  785. relative, all other references are assumed to be absolute and thus they need
  786. to be handled extra.
  787. A proper solution would be to change refoptions to a set and store the information
  788. if the symbol is absolute or relative there.
  789. }
  790. if (assigned(ref.symbol) and
  791. not(is_pc(ref.base)) and
  792. not(is_pc(ref.index))
  793. ) or
  794. { [#xxx] isn't a valid address operand }
  795. ((ref.base=NR_NO) and (ref.index=NR_NO)) or
  796. (ref.offset<-4095) or
  797. (ref.offset>4095) or
  798. ((oppostfix in [PF_SB,PF_H,PF_SH]) and
  799. ((ref.offset<-255) or
  800. (ref.offset>255)
  801. )
  802. ) or
  803. ((op in [A_LDF,A_STF]) and
  804. ((ref.offset<-1020) or
  805. (ref.offset>1020) or
  806. { the usual pc relative symbol handling assumes possible offsets of +/- 4095 }
  807. assigned(ref.symbol)
  808. )
  809. ) then
  810. begin
  811. reference_reset(tmpref,4);
  812. { load symbol }
  813. tmpreg:=getintregister(list,OS_INT);
  814. if assigned(ref.symbol) then
  815. begin
  816. current_asmdata.getjumplabel(l);
  817. cg.a_label(current_procinfo.aktlocaldata,l);
  818. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  819. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset));
  820. { load consts entry }
  821. tmpref.symbol:=l;
  822. tmpref.base:=NR_R15;
  823. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  824. { in case of LDF/STF, we got rid of the NR_R15 }
  825. if is_pc(ref.base) then
  826. ref.base:=NR_NO;
  827. if is_pc(ref.index) then
  828. ref.index:=NR_NO;
  829. end
  830. else
  831. a_load_const_reg(list,OS_ADDR,ref.offset,tmpreg);
  832. if (ref.base<>NR_NO) then
  833. begin
  834. if ref.index<>NR_NO then
  835. begin
  836. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  837. ref.base:=tmpreg;
  838. end
  839. else
  840. begin
  841. ref.index:=tmpreg;
  842. ref.shiftimm:=0;
  843. ref.signindex:=1;
  844. ref.shiftmode:=SM_None;
  845. end;
  846. end
  847. else
  848. ref.base:=tmpreg;
  849. ref.offset:=0;
  850. ref.symbol:=nil;
  851. end;
  852. if (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then
  853. begin
  854. if tmpreg<>NR_NO then
  855. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg,tmpreg)
  856. else
  857. begin
  858. tmpreg:=getintregister(list,OS_ADDR);
  859. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg);
  860. ref.base:=tmpreg;
  861. end;
  862. ref.offset:=0;
  863. end;
  864. { floating point operations have only limited references
  865. we expect here, that a base is already set }
  866. if (op in [A_LDF,A_STF]) and (ref.index<>NR_NO) then
  867. begin
  868. if ref.shiftmode<>SM_none then
  869. internalerror(200309121);
  870. if tmpreg<>NR_NO then
  871. begin
  872. if ref.base=tmpreg then
  873. begin
  874. if ref.signindex<0 then
  875. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,tmpreg,ref.index))
  876. else
  877. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg,ref.index));
  878. ref.index:=NR_NO;
  879. end
  880. else
  881. begin
  882. if ref.index<>tmpreg then
  883. internalerror(200403161);
  884. if ref.signindex<0 then
  885. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,ref.base,tmpreg))
  886. else
  887. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  888. ref.base:=tmpreg;
  889. ref.index:=NR_NO;
  890. end;
  891. end
  892. else
  893. begin
  894. tmpreg:=getintregister(list,OS_ADDR);
  895. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
  896. ref.base:=tmpreg;
  897. ref.index:=NR_NO;
  898. end;
  899. end;
  900. list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
  901. Result := ref;
  902. end;
  903. procedure tcgarm.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  904. var
  905. oppostfix:toppostfix;
  906. usedtmpref: treference;
  907. tmpreg : tregister;
  908. so : tshifterop;
  909. dir : integer;
  910. begin
  911. if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then
  912. FromSize := ToSize;
  913. case ToSize of
  914. { signed integer registers }
  915. OS_8,
  916. OS_S8:
  917. oppostfix:=PF_B;
  918. OS_16,
  919. OS_S16:
  920. oppostfix:=PF_H;
  921. OS_32,
  922. OS_S32:
  923. oppostfix:=PF_None;
  924. else
  925. InternalError(200308295);
  926. end;
  927. if (ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[tosize]) then
  928. begin
  929. if target_info.endian=endian_big then
  930. dir:=-1
  931. else
  932. dir:=1;
  933. case FromSize of
  934. OS_16,OS_S16:
  935. begin
  936. shifterop_reset(so);so.shiftmode:=SM_LSR;so.shiftimm:=8;
  937. tmpreg:=getintregister(list,OS_INT);
  938. usedtmpref:=ref;
  939. if target_info.endian=endian_big then
  940. inc(usedtmpref.offset,1);
  941. usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,usedtmpref);
  942. inc(usedtmpref.offset,dir);
  943. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
  944. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  945. end;
  946. OS_32,OS_S32:
  947. begin
  948. tmpreg:=getintregister(list,OS_INT);
  949. usedtmpref:=ref;
  950. shifterop_reset(so);so.shiftmode:=SM_LSR;
  951. if ref.alignment=2 then
  952. begin
  953. so.shiftimm:=16;
  954. if target_info.endian=endian_big then
  955. inc(usedtmpref.offset,2);
  956. usedtmpref:=a_internal_load_reg_ref(list,OS_16,OS_16,reg,usedtmpref);
  957. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
  958. inc(usedtmpref.offset,dir*2);
  959. a_internal_load_reg_ref(list,OS_16,OS_16,tmpreg,usedtmpref);
  960. end
  961. else
  962. begin
  963. so.shiftimm:=8;
  964. if target_info.endian=endian_big then
  965. inc(usedtmpref.offset,3);
  966. usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,usedtmpref);
  967. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
  968. inc(usedtmpref.offset,dir);
  969. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  970. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
  971. inc(usedtmpref.offset,dir);
  972. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  973. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
  974. inc(usedtmpref.offset,dir);
  975. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  976. end;
  977. end
  978. else
  979. handle_load_store(list,A_STR,oppostfix,reg,ref);
  980. end;
  981. end
  982. else
  983. handle_load_store(list,A_STR,oppostfix,reg,ref);
  984. end;
  985. function tcgarm.a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference;
  986. var
  987. oppostfix:toppostfix;
  988. begin
  989. case ToSize of
  990. { signed integer registers }
  991. OS_8,
  992. OS_S8:
  993. oppostfix:=PF_B;
  994. OS_16,
  995. OS_S16:
  996. oppostfix:=PF_H;
  997. OS_32,
  998. OS_S32:
  999. oppostfix:=PF_None;
  1000. else
  1001. InternalError(2003082910);
  1002. end;
  1003. result:=handle_load_store(list,A_STR,oppostfix,reg,ref);
  1004. end;
  1005. function tcgarm.a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference;
  1006. var
  1007. oppostfix:toppostfix;
  1008. begin
  1009. case FromSize of
  1010. { signed integer registers }
  1011. OS_8:
  1012. oppostfix:=PF_B;
  1013. OS_S8:
  1014. oppostfix:=PF_SB;
  1015. OS_16:
  1016. oppostfix:=PF_H;
  1017. OS_S16:
  1018. oppostfix:=PF_SH;
  1019. OS_32,
  1020. OS_S32:
  1021. oppostfix:=PF_None;
  1022. else
  1023. InternalError(200308291);
  1024. end;
  1025. result:=handle_load_store(list,A_LDR,oppostfix,reg,ref);
  1026. end;
  1027. procedure tcgarm.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  1028. var
  1029. so : tshifterop;
  1030. procedure do_shift(shiftmode : tshiftmode; shiftimm : byte; reg : tregister);
  1031. begin
  1032. so.shiftmode:=shiftmode;
  1033. so.shiftimm:=shiftimm;
  1034. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg,so));
  1035. end;
  1036. var
  1037. instr: taicpu;
  1038. conv_done: boolean;
  1039. begin
  1040. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1041. internalerror(2002090901);
  1042. conv_done:=false;
  1043. if tosize<>fromsize then
  1044. begin
  1045. shifterop_reset(so);
  1046. conv_done:=true;
  1047. if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  1048. fromsize:=tosize;
  1049. case fromsize of
  1050. OS_8:
  1051. list.concat(taicpu.op_reg_reg_const(A_AND,reg2,reg1,$ff));
  1052. OS_S8:
  1053. begin
  1054. do_shift(SM_LSL,24,reg1);
  1055. if tosize=OS_16 then
  1056. begin
  1057. do_shift(SM_ASR,8,reg2);
  1058. do_shift(SM_LSR,16,reg2);
  1059. end
  1060. else
  1061. do_shift(SM_ASR,24,reg2);
  1062. end;
  1063. OS_16:
  1064. begin
  1065. do_shift(SM_LSL,16,reg1);
  1066. do_shift(SM_LSR,16,reg2);
  1067. end;
  1068. OS_S16:
  1069. begin
  1070. do_shift(SM_LSL,16,reg1);
  1071. do_shift(SM_ASR,16,reg2)
  1072. end;
  1073. else
  1074. conv_done:=false;
  1075. end;
  1076. end;
  1077. if not conv_done and (reg1<>reg2) then
  1078. begin
  1079. { same size, only a register mov required }
  1080. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  1081. list.Concat(instr);
  1082. { Notify the register allocator that we have written a move instruction so
  1083. it can try to eliminate it. }
  1084. add_move_instruction(instr);
  1085. end;
  1086. end;
  1087. procedure tcgarm.a_paramfpu_ref(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);
  1088. var
  1089. href,href2 : treference;
  1090. hloc : pcgparalocation;
  1091. begin
  1092. href:=ref;
  1093. hloc:=paraloc.location;
  1094. while assigned(hloc) do
  1095. begin
  1096. case hloc^.loc of
  1097. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  1098. a_loadfpu_ref_reg(list,size,size,ref,hloc^.register);
  1099. LOC_REGISTER :
  1100. case hloc^.size of
  1101. OS_F32:
  1102. a_load_ref_reg(list,OS_32,OS_32,href,hloc^.register);
  1103. OS_64,
  1104. OS_F64:
  1105. cg64.a_param64_ref(list,href,paraloc);
  1106. else
  1107. a_load_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
  1108. end;
  1109. LOC_REFERENCE :
  1110. begin
  1111. reference_reset_base(href2,hloc^.reference.index,hloc^.reference.offset,paraloc.alignment);
  1112. { concatcopy should choose the best way to copy the data }
  1113. g_concatcopy(list,href,href2,tcgsize2size[size]);
  1114. end;
  1115. else
  1116. internalerror(200408241);
  1117. end;
  1118. inc(href.offset,tcgsize2size[hloc^.size]);
  1119. hloc:=hloc^.next;
  1120. end;
  1121. end;
  1122. procedure tcgarm.a_loadfpu_reg_reg(list: TAsmList; fromsize,tosize: tcgsize; reg1, reg2: tregister);
  1123. begin
  1124. list.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,reg2,reg1),cgsize2fpuoppostfix[tosize]));
  1125. end;
  1126. procedure tcgarm.a_loadfpu_ref_reg(list: TAsmList; fromsize,tosize: tcgsize; const ref: treference; reg: tregister);
  1127. var
  1128. oppostfix:toppostfix;
  1129. begin
  1130. case fromsize of
  1131. OS_32,
  1132. OS_F32:
  1133. oppostfix:=PF_S;
  1134. OS_64,
  1135. OS_F64:
  1136. oppostfix:=PF_D;
  1137. OS_F80:
  1138. oppostfix:=PF_E;
  1139. else
  1140. InternalError(200309021);
  1141. end;
  1142. handle_load_store(list,A_LDF,oppostfix,reg,ref);
  1143. if fromsize<>tosize then
  1144. a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
  1145. end;
  1146. procedure tcgarm.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  1147. var
  1148. oppostfix:toppostfix;
  1149. begin
  1150. case tosize of
  1151. OS_F32:
  1152. oppostfix:=PF_S;
  1153. OS_F64:
  1154. oppostfix:=PF_D;
  1155. OS_F80:
  1156. oppostfix:=PF_E;
  1157. else
  1158. InternalError(200309022);
  1159. end;
  1160. handle_load_store(list,A_STF,oppostfix,reg,ref);
  1161. end;
  1162. { comparison operations }
  1163. procedure tcgarm.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
  1164. l : tasmlabel);
  1165. var
  1166. tmpreg : tregister;
  1167. b : byte;
  1168. begin
  1169. if is_shifter_const(a,b) then
  1170. list.concat(taicpu.op_reg_const(A_CMP,reg,a))
  1171. { CMN reg,0 and CMN reg,$80000000 are different from CMP reg,$ffffffff
  1172. and CMP reg,$7fffffff regarding the flags according to the ARM manual }
  1173. else if (a<>$7fffffff) and (a<>-1) and is_shifter_const(-a,b) then
  1174. list.concat(taicpu.op_reg_const(A_CMN,reg,-a))
  1175. else
  1176. begin
  1177. tmpreg:=getintregister(list,size);
  1178. a_load_const_reg(list,size,a,tmpreg);
  1179. list.concat(taicpu.op_reg_reg(A_CMP,reg,tmpreg));
  1180. end;
  1181. a_jmp_cond(list,cmp_op,l);
  1182. end;
  1183. procedure tcgarm.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  1184. begin
  1185. list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1));
  1186. a_jmp_cond(list,cmp_op,l);
  1187. end;
  1188. procedure tcgarm.a_jmp_name(list : TAsmList;const s : string);
  1189. var
  1190. ai : taicpu;
  1191. begin
  1192. ai:=taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(s));
  1193. ai.is_jmp:=true;
  1194. list.concat(ai);
  1195. end;
  1196. procedure tcgarm.a_jmp_always(list : TAsmList;l: tasmlabel);
  1197. var
  1198. ai : taicpu;
  1199. begin
  1200. ai:=taicpu.op_sym(A_B,l);
  1201. ai.is_jmp:=true;
  1202. list.concat(ai);
  1203. end;
  1204. procedure tcgarm.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
  1205. var
  1206. ai : taicpu;
  1207. begin
  1208. ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
  1209. ai.is_jmp:=true;
  1210. list.concat(ai);
  1211. end;
  1212. procedure tcgarm.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  1213. begin
  1214. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
  1215. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond(flags_to_cond(f))));
  1216. end;
  1217. procedure tcgarm.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  1218. var
  1219. ref : treference;
  1220. shift : byte;
  1221. firstfloatreg,lastfloatreg,
  1222. r : byte;
  1223. regs : tcpuregisterset;
  1224. stackmisalignment: pint;
  1225. begin
  1226. LocalSize:=align(LocalSize,4);
  1227. { call instruction does not put anything on the stack }
  1228. stackmisalignment:=0;
  1229. if not(nostackframe) then
  1230. begin
  1231. firstfloatreg:=RS_NO;
  1232. { save floating point registers? }
  1233. for r:=RS_F0 to RS_F7 do
  1234. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  1235. begin
  1236. if firstfloatreg=RS_NO then
  1237. firstfloatreg:=r;
  1238. lastfloatreg:=r;
  1239. inc(stackmisalignment,12);
  1240. end;
  1241. a_reg_alloc(list,NR_STACK_POINTER_REG);
  1242. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1243. begin
  1244. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  1245. a_reg_alloc(list,NR_R12);
  1246. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  1247. end;
  1248. { save int registers }
  1249. reference_reset(ref,4);
  1250. ref.index:=NR_STACK_POINTER_REG;
  1251. ref.addressmode:=AM_PREINDEXED;
  1252. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1253. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1254. regs:=regs+[RS_R11,RS_R12,RS_R14,RS_R15]
  1255. else
  1256. if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
  1257. include(regs,RS_R14);
  1258. if regs<>[] then
  1259. begin
  1260. for r:=RS_R0 to RS_R15 do
  1261. if (r in regs) then
  1262. inc(stackmisalignment,4);
  1263. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,regs),PF_FD));
  1264. end;
  1265. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1266. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  1267. stackmisalignment:=stackmisalignment mod current_settings.alignment.localalignmax;
  1268. if (LocalSize<>0) or
  1269. ((stackmisalignment<>0) and
  1270. ((pi_do_call in current_procinfo.flags) or
  1271. (po_assembler in current_procinfo.procdef.procoptions))) then
  1272. begin
  1273. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  1274. if not(is_shifter_const(localsize,shift)) then
  1275. begin
  1276. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  1277. a_reg_alloc(list,NR_R12);
  1278. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  1279. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1280. a_reg_dealloc(list,NR_R12);
  1281. end
  1282. else
  1283. begin
  1284. a_reg_dealloc(list,NR_R12);
  1285. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  1286. end;
  1287. end;
  1288. if firstfloatreg<>RS_NO then
  1289. begin
  1290. reference_reset(ref,4);
  1291. if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
  1292. begin
  1293. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  1294. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  1295. ref.base:=NR_R12;
  1296. end
  1297. else
  1298. begin
  1299. ref.base:=current_procinfo.framepointer;
  1300. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  1301. end;
  1302. list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  1303. lastfloatreg-firstfloatreg+1,ref));
  1304. end;
  1305. end;
  1306. end;
  1307. procedure tcgarm.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  1308. var
  1309. ref : treference;
  1310. firstfloatreg,lastfloatreg,
  1311. r : byte;
  1312. shift : byte;
  1313. regs : tcpuregisterset;
  1314. LocalSize : longint;
  1315. stackmisalignment: pint;
  1316. begin
  1317. if not(nostackframe) then
  1318. begin
  1319. stackmisalignment:=0;
  1320. { restore floating point register }
  1321. firstfloatreg:=RS_NO;
  1322. { save floating point registers? }
  1323. for r:=RS_F0 to RS_F7 do
  1324. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  1325. begin
  1326. if firstfloatreg=RS_NO then
  1327. firstfloatreg:=r;
  1328. lastfloatreg:=r;
  1329. { floating point register space is already included in
  1330. localsize below by calc_stackframe_size
  1331. inc(stackmisalignment,12);
  1332. }
  1333. end;
  1334. if firstfloatreg<>RS_NO then
  1335. begin
  1336. reference_reset(ref,4);
  1337. if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
  1338. begin
  1339. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  1340. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  1341. ref.base:=NR_R12;
  1342. end
  1343. else
  1344. begin
  1345. ref.base:=current_procinfo.framepointer;
  1346. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  1347. end;
  1348. list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  1349. lastfloatreg-firstfloatreg+1,ref));
  1350. end;
  1351. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1352. if (pi_do_call in current_procinfo.flags) or (regs<>[]) then
  1353. begin
  1354. exclude(regs,RS_R14);
  1355. include(regs,RS_R15);
  1356. end;
  1357. if (current_procinfo.framepointer<>NR_STACK_POINTER_REG) then
  1358. regs:=regs+[RS_R11,RS_R13,RS_R15];
  1359. for r:=RS_R0 to RS_R15 do
  1360. if (r in regs) then
  1361. inc(stackmisalignment,4);
  1362. stackmisalignment:=stackmisalignment mod current_settings.alignment.localalignmax;
  1363. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  1364. begin
  1365. LocalSize:=current_procinfo.calc_stackframe_size;
  1366. if (LocalSize<>0) or
  1367. ((stackmisalignment<>0) and
  1368. ((pi_do_call in current_procinfo.flags) or
  1369. (po_assembler in current_procinfo.procdef.procoptions))) then
  1370. begin
  1371. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  1372. if not(is_shifter_const(LocalSize,shift)) then
  1373. begin
  1374. a_reg_alloc(list,NR_R12);
  1375. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  1376. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1377. a_reg_dealloc(list,NR_R12);
  1378. end
  1379. else
  1380. begin
  1381. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  1382. end;
  1383. end;
  1384. if regs=[] then
  1385. list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
  1386. else
  1387. begin
  1388. reference_reset(ref,4);
  1389. ref.index:=NR_STACK_POINTER_REG;
  1390. ref.addressmode:=AM_PREINDEXED;
  1391. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,regs),PF_FD));
  1392. end;
  1393. end
  1394. else
  1395. begin
  1396. { restore int registers and return }
  1397. reference_reset(ref,4);
  1398. ref.index:=NR_FRAME_POINTER_REG;
  1399. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,regs),PF_EA));
  1400. end;
  1401. end
  1402. else
  1403. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14));
  1404. end;
  1405. procedure tcgarm.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  1406. var
  1407. b : byte;
  1408. tmpref : treference;
  1409. instr : taicpu;
  1410. begin
  1411. if ref.addressmode<>AM_OFFSET then
  1412. internalerror(200309071);
  1413. tmpref:=ref;
  1414. { Be sure to have a base register }
  1415. if (tmpref.base=NR_NO) then
  1416. begin
  1417. if tmpref.shiftmode<>SM_None then
  1418. internalerror(200308294);
  1419. if tmpref.signindex<0 then
  1420. internalerror(200312023);
  1421. tmpref.base:=tmpref.index;
  1422. tmpref.index:=NR_NO;
  1423. end;
  1424. if assigned(tmpref.symbol) or
  1425. not((is_shifter_const(tmpref.offset,b)) or
  1426. (is_shifter_const(-tmpref.offset,b))
  1427. ) then
  1428. fixref(list,tmpref);
  1429. { expect a base here if there is an index }
  1430. if (tmpref.base=NR_NO) and (tmpref.index<>NR_NO) then
  1431. internalerror(200312022);
  1432. if tmpref.index<>NR_NO then
  1433. begin
  1434. if tmpref.shiftmode<>SM_None then
  1435. internalerror(200312021);
  1436. if tmpref.signindex<0 then
  1437. a_op_reg_reg_reg(list,OP_SUB,OS_ADDR,tmpref.base,tmpref.index,r)
  1438. else
  1439. a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,tmpref.base,tmpref.index,r);
  1440. if tmpref.offset<>0 then
  1441. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,r,r);
  1442. end
  1443. else
  1444. begin
  1445. if tmpref.base=NR_NO then
  1446. a_load_const_reg(list,OS_ADDR,tmpref.offset,r)
  1447. else
  1448. if tmpref.offset<>0 then
  1449. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,tmpref.base,r)
  1450. else
  1451. begin
  1452. instr:=taicpu.op_reg_reg(A_MOV,r,tmpref.base);
  1453. list.concat(instr);
  1454. add_move_instruction(instr);
  1455. end;
  1456. end;
  1457. end;
  1458. procedure tcgarm.fixref(list : TAsmList;var ref : treference);
  1459. var
  1460. tmpreg : tregister;
  1461. tmpref : treference;
  1462. l : tasmlabel;
  1463. begin
  1464. { absolute symbols can't be handled directly, we've to store the symbol reference
  1465. in the text segment and access it pc relative
  1466. For now, we assume that references where base or index equals to PC are already
  1467. relative, all other references are assumed to be absolute and thus they need
  1468. to be handled extra.
  1469. A proper solution would be to change refoptions to a set and store the information
  1470. if the symbol is absolute or relative there.
  1471. }
  1472. { create consts entry }
  1473. reference_reset(tmpref,4);
  1474. current_asmdata.getjumplabel(l);
  1475. cg.a_label(current_procinfo.aktlocaldata,l);
  1476. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  1477. if assigned(ref.symbol) then
  1478. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset))
  1479. else
  1480. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  1481. { load consts entry }
  1482. tmpreg:=getintregister(list,OS_INT);
  1483. tmpref.symbol:=l;
  1484. tmpref.base:=NR_PC;
  1485. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  1486. if (ref.base<>NR_NO) then
  1487. begin
  1488. if ref.index<>NR_NO then
  1489. begin
  1490. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  1491. ref.base:=tmpreg;
  1492. end
  1493. else
  1494. if ref.base<>NR_PC then
  1495. begin
  1496. ref.index:=tmpreg;
  1497. ref.shiftimm:=0;
  1498. ref.signindex:=1;
  1499. ref.shiftmode:=SM_None;
  1500. end
  1501. else
  1502. ref.base:=tmpreg;
  1503. end
  1504. else
  1505. ref.base:=tmpreg;
  1506. ref.offset:=0;
  1507. ref.symbol:=nil;
  1508. end;
  1509. procedure tcgarm.g_concatcopy_move(list : TAsmList;const source,dest : treference;len : aint);
  1510. var
  1511. paraloc1,paraloc2,paraloc3 : TCGPara;
  1512. begin
  1513. paraloc1.init;
  1514. paraloc2.init;
  1515. paraloc3.init;
  1516. paramanager.getintparaloc(pocall_default,1,paraloc1);
  1517. paramanager.getintparaloc(pocall_default,2,paraloc2);
  1518. paramanager.getintparaloc(pocall_default,3,paraloc3);
  1519. paramanager.allocparaloc(list,paraloc3);
  1520. a_param_const(list,OS_INT,len,paraloc3);
  1521. paramanager.allocparaloc(list,paraloc2);
  1522. a_paramaddr_ref(list,dest,paraloc2);
  1523. paramanager.allocparaloc(list,paraloc2);
  1524. a_paramaddr_ref(list,source,paraloc1);
  1525. paramanager.freeparaloc(list,paraloc3);
  1526. paramanager.freeparaloc(list,paraloc2);
  1527. paramanager.freeparaloc(list,paraloc1);
  1528. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1529. alloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1530. a_call_name(list,'FPC_MOVE',false);
  1531. dealloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1532. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1533. paraloc3.done;
  1534. paraloc2.done;
  1535. paraloc1.done;
  1536. end;
  1537. procedure tcgarm.g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : aint;aligned : boolean);
  1538. const
  1539. 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}
  1540. var
  1541. srcref,dstref,usedtmpref,usedtmpref2:treference;
  1542. srcreg,destreg,countreg,r,tmpreg:tregister;
  1543. helpsize:aint;
  1544. copysize:byte;
  1545. cgsize:Tcgsize;
  1546. tmpregisters:array[1..maxtmpreg] of tregister;
  1547. tmpregi,tmpregi2:byte;
  1548. { will never be called with count<=4 }
  1549. procedure genloop(count : aword;size : byte);
  1550. const
  1551. size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
  1552. var
  1553. l : tasmlabel;
  1554. begin
  1555. current_asmdata.getjumplabel(l);
  1556. if count<size then size:=1;
  1557. a_load_const_reg(list,OS_INT,count div size,countreg);
  1558. cg.a_label(list,l);
  1559. srcref.addressmode:=AM_POSTINDEXED;
  1560. dstref.addressmode:=AM_POSTINDEXED;
  1561. srcref.offset:=size;
  1562. dstref.offset:=size;
  1563. r:=getintregister(list,size2opsize[size]);
  1564. a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
  1565. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
  1566. a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
  1567. a_jmp_flags(list,F_NE,l);
  1568. srcref.offset:=1;
  1569. dstref.offset:=1;
  1570. case count mod size of
  1571. 1:
  1572. begin
  1573. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1574. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1575. end;
  1576. 2:
  1577. if aligned then
  1578. begin
  1579. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  1580. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  1581. end
  1582. else
  1583. begin
  1584. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1585. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1586. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1587. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1588. end;
  1589. 3:
  1590. if aligned then
  1591. begin
  1592. srcref.offset:=2;
  1593. dstref.offset:=2;
  1594. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  1595. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  1596. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1597. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1598. end
  1599. else
  1600. begin
  1601. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1602. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1603. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1604. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1605. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1606. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1607. end;
  1608. end;
  1609. { keep the registers alive }
  1610. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  1611. list.concat(taicpu.op_reg_reg(A_MOV,srcreg,srcreg));
  1612. list.concat(taicpu.op_reg_reg(A_MOV,destreg,destreg));
  1613. end;
  1614. begin
  1615. if len=0 then
  1616. exit;
  1617. helpsize:=12+maxtmpreg*4;//52 with maxtmpreg=10
  1618. dstref:=dest;
  1619. srcref:=source;
  1620. if cs_opt_size in current_settings.optimizerswitches then
  1621. helpsize:=8;
  1622. if (len<=helpsize) and aligned then
  1623. begin
  1624. tmpregi:=0;
  1625. srcreg:=getintregister(list,OS_ADDR);
  1626. { explicit pc relative addressing, could be
  1627. e.g. a floating point constant }
  1628. if source.base=NR_PC then
  1629. begin
  1630. { ... then we don't need a loadaddr }
  1631. srcref:=source;
  1632. end
  1633. else
  1634. begin
  1635. a_loadaddr_ref_reg(list,source,srcreg);
  1636. reference_reset_base(srcref,srcreg,0,source.alignment);
  1637. end;
  1638. while (len div 4 <> 0) and (tmpregi<maxtmpreg) do
  1639. begin
  1640. inc(tmpregi);
  1641. tmpregisters[tmpregi]:=getintregister(list,OS_32);
  1642. a_load_ref_reg(list,OS_32,OS_32,srcref,tmpregisters[tmpregi]);
  1643. inc(srcref.offset,4);
  1644. dec(len,4);
  1645. end;
  1646. destreg:=getintregister(list,OS_ADDR);
  1647. a_loadaddr_ref_reg(list,dest,destreg);
  1648. reference_reset_base(dstref,destreg,0,dest.alignment);
  1649. tmpregi2:=1;
  1650. while (tmpregi2<=tmpregi) do
  1651. begin
  1652. a_load_reg_ref(list,OS_32,OS_32,tmpregisters[tmpregi2],dstref);
  1653. inc(dstref.offset,4);
  1654. inc(tmpregi2);
  1655. end;
  1656. copysize:=4;
  1657. cgsize:=OS_32;
  1658. while len<>0 do
  1659. begin
  1660. if len<2 then
  1661. begin
  1662. copysize:=1;
  1663. cgsize:=OS_8;
  1664. end
  1665. else if len<4 then
  1666. begin
  1667. copysize:=2;
  1668. cgsize:=OS_16;
  1669. end;
  1670. dec(len,copysize);
  1671. r:=getintregister(list,cgsize);
  1672. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  1673. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  1674. inc(srcref.offset,copysize);
  1675. inc(dstref.offset,copysize);
  1676. end;{end of while}
  1677. end
  1678. else
  1679. begin
  1680. cgsize:=OS_32;
  1681. if (len<=4) then{len<=4 and not aligned}
  1682. begin
  1683. r:=getintregister(list,cgsize);
  1684. usedtmpref:=a_internal_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1685. if Len=1 then
  1686. a_load_reg_ref(list,OS_8,OS_8,r,dstref)
  1687. else
  1688. begin
  1689. tmpreg:=getintregister(list,cgsize);
  1690. usedtmpref2:=a_internal_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1691. inc(usedtmpref.offset,1);
  1692. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1693. inc(usedtmpref2.offset,1);
  1694. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1695. if len>2 then
  1696. begin
  1697. inc(usedtmpref.offset,1);
  1698. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1699. inc(usedtmpref2.offset,1);
  1700. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1701. if len>3 then
  1702. begin
  1703. inc(usedtmpref.offset,1);
  1704. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1705. inc(usedtmpref2.offset,1);
  1706. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1707. end;
  1708. end;
  1709. end;
  1710. end{end of if len<=4}
  1711. else
  1712. begin{unaligned & 4<len<helpsize **or** aligned/unaligned & len>helpsize}
  1713. destreg:=getintregister(list,OS_ADDR);
  1714. a_loadaddr_ref_reg(list,dest,destreg);
  1715. reference_reset_base(dstref,destreg,0,dest.alignment);
  1716. srcreg:=getintregister(list,OS_ADDR);
  1717. a_loadaddr_ref_reg(list,source,srcreg);
  1718. reference_reset_base(srcref,srcreg,0,source.alignment);
  1719. countreg:=getintregister(list,OS_32);
  1720. // if cs_opt_size in current_settings.optimizerswitches then
  1721. { roozbeh : it seems loading 1 byte is faster becouse of caching/fetching(?) }
  1722. {if aligned then
  1723. genloop(len,4)
  1724. else}
  1725. genloop(len,1);
  1726. end;
  1727. end;
  1728. end;
  1729. procedure tcgarm.g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : aint);
  1730. begin
  1731. g_concatcopy_internal(list,source,dest,len,false);
  1732. end;
  1733. procedure tcgarm.g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);
  1734. begin
  1735. if (source.alignment in [1..3]) or
  1736. (dest.alignment in [1..3]) then
  1737. g_concatcopy_internal(list,source,dest,len,false)
  1738. else
  1739. g_concatcopy_internal(list,source,dest,len,true);
  1740. end;
  1741. procedure tcgarm.g_overflowCheck(list : TAsmList;const l : tlocation;def : tdef);
  1742. var
  1743. ovloc : tlocation;
  1744. begin
  1745. ovloc.loc:=LOC_VOID;
  1746. g_overflowCheck_loc(list,l,def,ovloc);
  1747. end;
  1748. procedure tcgarm.g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);
  1749. var
  1750. hl : tasmlabel;
  1751. ai:TAiCpu;
  1752. hflags : tresflags;
  1753. begin
  1754. if not(cs_check_overflow in current_settings.localswitches) then
  1755. exit;
  1756. current_asmdata.getjumplabel(hl);
  1757. case ovloc.loc of
  1758. LOC_VOID:
  1759. begin
  1760. ai:=taicpu.op_sym(A_B,hl);
  1761. ai.is_jmp:=true;
  1762. if not((def.typ=pointerdef) or
  1763. ((def.typ=orddef) and
  1764. (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,pasbool]))) then
  1765. ai.SetCondition(C_VC)
  1766. else
  1767. if TAiCpu(List.Last).opcode in [A_RSB,A_RSC,A_SBC,A_SUB] then
  1768. ai.SetCondition(C_CS)
  1769. else
  1770. ai.SetCondition(C_CC);
  1771. list.concat(ai);
  1772. end;
  1773. LOC_FLAGS:
  1774. begin
  1775. hflags:=ovloc.resflags;
  1776. inverse_flags(hflags);
  1777. cg.a_jmp_flags(list,hflags,hl);
  1778. end;
  1779. else
  1780. internalerror(200409281);
  1781. end;
  1782. a_call_name(list,'FPC_OVERFLOW',false);
  1783. a_label(list,hl);
  1784. end;
  1785. procedure tcgarm.g_save_registers(list : TAsmList);
  1786. begin
  1787. { this work is done in g_proc_entry }
  1788. end;
  1789. procedure tcgarm.g_restore_registers(list : TAsmList);
  1790. begin
  1791. { this work is done in g_proc_exit }
  1792. end;
  1793. procedure tcgarm.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  1794. var
  1795. ai : taicpu;
  1796. begin
  1797. ai:=Taicpu.Op_sym(A_B,l);
  1798. ai.SetCondition(OpCmp2AsmCond[cond]);
  1799. ai.is_jmp:=true;
  1800. list.concat(ai);
  1801. end;
  1802. procedure tcgarm.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: aint);
  1803. var
  1804. hsym : tsym;
  1805. href : treference;
  1806. paraloc : Pcgparalocation;
  1807. shift : byte;
  1808. begin
  1809. { calculate the parameter info for the procdef }
  1810. if not procdef.has_paraloc_info then
  1811. begin
  1812. procdef.requiredargarea:=paramanager.create_paraloc_info(procdef,callerside);
  1813. procdef.has_paraloc_info:=true;
  1814. end;
  1815. hsym:=tsym(procdef.parast.Find('self'));
  1816. if not(assigned(hsym) and
  1817. (hsym.typ=paravarsym)) then
  1818. internalerror(200305251);
  1819. paraloc:=tparavarsym(hsym).paraloc[callerside].location;
  1820. while paraloc<>nil do
  1821. with paraloc^ do
  1822. begin
  1823. case loc of
  1824. LOC_REGISTER:
  1825. begin
  1826. if is_shifter_const(ioffset,shift) then
  1827. a_op_const_reg(list,OP_SUB,size,ioffset,register)
  1828. else
  1829. begin
  1830. a_load_const_reg(list,OS_ADDR,ioffset,NR_R12);
  1831. a_op_reg_reg(list,OP_SUB,size,NR_R12,register);
  1832. end;
  1833. end;
  1834. LOC_REFERENCE:
  1835. begin
  1836. { offset in the wrapper needs to be adjusted for the stored
  1837. return address }
  1838. reference_reset_base(href,reference.index,reference.offset+sizeof(aint),sizeof(pint));
  1839. if is_shifter_const(ioffset,shift) then
  1840. a_op_const_ref(list,OP_SUB,size,ioffset,href)
  1841. else
  1842. begin
  1843. a_load_const_reg(list,OS_ADDR,ioffset,NR_R12);
  1844. a_op_reg_ref(list,OP_SUB,size,NR_R12,href);
  1845. end;
  1846. end
  1847. else
  1848. internalerror(200309189);
  1849. end;
  1850. paraloc:=next;
  1851. end;
  1852. end;
  1853. procedure tcgarm.g_stackpointer_alloc(list: TAsmList; size: longint);
  1854. begin
  1855. internalerror(200807237);
  1856. end;
  1857. procedure tcgarm.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  1858. procedure loadvmttor12;
  1859. var
  1860. href : treference;
  1861. begin
  1862. reference_reset_base(href,NR_R0,0,sizeof(pint));
  1863. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1864. end;
  1865. procedure op_onr12methodaddr;
  1866. var
  1867. href : treference;
  1868. begin
  1869. if (procdef.extnumber=$ffff) then
  1870. Internalerror(200006139);
  1871. { call/jmp vmtoffs(%eax) ; method offs }
  1872. reference_reset_base(href,NR_R12,procdef._class.vmtmethodoffset(procdef.extnumber),sizeof(pint));
  1873. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1874. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
  1875. end;
  1876. var
  1877. make_global : boolean;
  1878. begin
  1879. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  1880. Internalerror(200006137);
  1881. if not assigned(procdef._class) or
  1882. (procdef.procoptions*[po_classmethod, po_staticmethod,
  1883. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  1884. Internalerror(200006138);
  1885. if procdef.owner.symtabletype<>ObjectSymtable then
  1886. Internalerror(200109191);
  1887. make_global:=false;
  1888. if (not current_module.is_unit) or
  1889. create_smartlink or
  1890. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  1891. make_global:=true;
  1892. if make_global then
  1893. list.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  1894. else
  1895. list.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  1896. { the wrapper might need aktlocaldata for the additional data to
  1897. load the constant }
  1898. current_procinfo:=cprocinfo.create(nil);
  1899. { set param1 interface to self }
  1900. g_adjust_self_value(list,procdef,ioffset);
  1901. { case 4 }
  1902. if po_virtualmethod in procdef.procoptions then
  1903. begin
  1904. loadvmttor12;
  1905. op_onr12methodaddr;
  1906. end
  1907. { case 0 }
  1908. else
  1909. list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname)));
  1910. list.concatlist(current_procinfo.aktlocaldata);
  1911. current_procinfo.Free;
  1912. current_procinfo:=nil;
  1913. list.concat(Tai_symbol_end.Createname(labelname));
  1914. end;
  1915. procedure tcgarm.maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  1916. const
  1917. overflowops = [OP_MUL,OP_SHL,OP_ADD,OP_SUB,OP_NOT,OP_NEG];
  1918. begin
  1919. if (op in overflowops) and
  1920. (size in [OS_8,OS_S8,OS_16,OS_S16]) then
  1921. a_load_reg_reg(list,OS_32,size,dst,dst);
  1922. end;
  1923. function tcgarm.get_darwin_call_stub(const s: string; weak: boolean): tasmsymbol;
  1924. var
  1925. stubname: string;
  1926. l1: tasmsymbol;
  1927. href: treference;
  1928. begin
  1929. stubname := 'L'+s+'$stub';
  1930. result := current_asmdata.getasmsymbol(stubname);
  1931. if assigned(result) then
  1932. exit;
  1933. if current_asmdata.asmlists[al_imports]=nil then
  1934. current_asmdata.asmlists[al_imports]:=TAsmList.create;
  1935. current_asmdata.asmlists[al_imports].concat(Tai_section.create(sec_stub,'',0));
  1936. current_asmdata.asmlists[al_imports].concat(Tai_align.Create(4));
  1937. result := current_asmdata.RefAsmSymbol(stubname);
  1938. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(result,0));
  1939. { register as a weak symbol if necessary }
  1940. if weak then
  1941. current_asmdata.weakrefasmsymbol(s);
  1942. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_indirect_symbol,s));
  1943. if not(cs_create_pic in current_settings.moduleswitches) then
  1944. begin
  1945. l1 := current_asmdata.RefAsmSymbol('L'+s+'$slp');
  1946. reference_reset_symbol(href,l1,0,sizeof(pint));
  1947. href.refaddr:=addr_full;
  1948. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_ref(A_LDR,NR_R12,href));
  1949. reference_reset_base(href,NR_R12,0,sizeof(pint));
  1950. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_ref(A_LDR,NR_R15,href));
  1951. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(l1,0));
  1952. l1 := current_asmdata.RefAsmSymbol('L'+s+'$lazy_ptr');
  1953. current_asmdata.asmlists[al_imports].concat(tai_const.create_sym(l1));
  1954. end
  1955. else
  1956. internalerror(2008100401);
  1957. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_lazy_symbol_pointer,''));
  1958. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(l1,0));
  1959. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_indirect_symbol,s));
  1960. current_asmdata.asmlists[al_imports].concat(tai_const.createname('dyld_stub_binding_helper',0));
  1961. end;
  1962. procedure tcg64farm.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  1963. begin
  1964. case op of
  1965. OP_NEG:
  1966. begin
  1967. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  1968. list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
  1969. end;
  1970. OP_NOT:
  1971. begin
  1972. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  1973. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  1974. end;
  1975. else
  1976. a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
  1977. end;
  1978. end;
  1979. procedure tcg64farm.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  1980. begin
  1981. a_op64_const_reg_reg(list,op,size,value,reg,reg);
  1982. end;
  1983. procedure tcg64farm.a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);
  1984. var
  1985. ovloc : tlocation;
  1986. begin
  1987. a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,ovloc);
  1988. end;
  1989. procedure tcg64farm.a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
  1990. var
  1991. ovloc : tlocation;
  1992. begin
  1993. a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,ovloc);
  1994. end;
  1995. procedure tcg64farm.a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  1996. var
  1997. tmpreg : tregister;
  1998. b : byte;
  1999. begin
  2000. ovloc.loc:=LOC_VOID;
  2001. case op of
  2002. OP_NEG,
  2003. OP_NOT :
  2004. internalerror(200306017);
  2005. end;
  2006. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  2007. begin
  2008. case op of
  2009. OP_ADD:
  2010. begin
  2011. if is_shifter_const(lo(value),b) then
  2012. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  2013. else
  2014. begin
  2015. tmpreg:=cg.getintregister(list,OS_32);
  2016. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  2017. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  2018. end;
  2019. if is_shifter_const(hi(value),b) then
  2020. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  2021. else
  2022. begin
  2023. tmpreg:=cg.getintregister(list,OS_32);
  2024. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  2025. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  2026. end;
  2027. end;
  2028. OP_SUB:
  2029. begin
  2030. if is_shifter_const(lo(value),b) then
  2031. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  2032. else
  2033. begin
  2034. tmpreg:=cg.getintregister(list,OS_32);
  2035. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  2036. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  2037. end;
  2038. if is_shifter_const(hi(value),b) then
  2039. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))),PF_S))
  2040. else
  2041. begin
  2042. tmpreg:=cg.getintregister(list,OS_32);
  2043. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  2044. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  2045. end;
  2046. end;
  2047. else
  2048. internalerror(200502131);
  2049. end;
  2050. if size=OS_64 then
  2051. begin
  2052. { the arm has an weired opinion how flags for SUB/ADD are handled }
  2053. ovloc.loc:=LOC_FLAGS;
  2054. case op of
  2055. OP_ADD:
  2056. ovloc.resflags:=F_CS;
  2057. OP_SUB:
  2058. ovloc.resflags:=F_CC;
  2059. end;
  2060. end;
  2061. end
  2062. else
  2063. begin
  2064. case op of
  2065. OP_AND,OP_OR,OP_XOR:
  2066. begin
  2067. cg.a_op_const_reg_reg(list,op,OS_32,aint(lo(value)),regsrc.reglo,regdst.reglo);
  2068. cg.a_op_const_reg_reg(list,op,OS_32,aint(hi(value)),regsrc.reghi,regdst.reghi);
  2069. end;
  2070. OP_ADD:
  2071. begin
  2072. if is_shifter_const(aint(lo(value)),b) then
  2073. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
  2074. else
  2075. begin
  2076. tmpreg:=cg.getintregister(list,OS_32);
  2077. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  2078. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  2079. end;
  2080. if is_shifter_const(aint(hi(value)),b) then
  2081. list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,aint(hi(value))))
  2082. else
  2083. begin
  2084. tmpreg:=cg.getintregister(list,OS_32);
  2085. cg.a_load_const_reg(list,OS_32,aint(hi(value)),tmpreg);
  2086. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
  2087. end;
  2088. end;
  2089. OP_SUB:
  2090. begin
  2091. if is_shifter_const(aint(lo(value)),b) then
  2092. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
  2093. else
  2094. begin
  2095. tmpreg:=cg.getintregister(list,OS_32);
  2096. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  2097. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  2098. end;
  2099. if is_shifter_const(aint(hi(value)),b) then
  2100. list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))))
  2101. else
  2102. begin
  2103. tmpreg:=cg.getintregister(list,OS_32);
  2104. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  2105. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
  2106. end;
  2107. end;
  2108. else
  2109. internalerror(2003083101);
  2110. end;
  2111. end;
  2112. end;
  2113. procedure tcg64farm.a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  2114. begin
  2115. ovloc.loc:=LOC_VOID;
  2116. case op of
  2117. OP_NEG,
  2118. OP_NOT :
  2119. internalerror(200306017);
  2120. end;
  2121. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  2122. begin
  2123. case op of
  2124. OP_ADD:
  2125. begin
  2126. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  2127. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi),PF_S));
  2128. end;
  2129. OP_SUB:
  2130. begin
  2131. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  2132. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi),PF_S));
  2133. end;
  2134. else
  2135. internalerror(2003083101);
  2136. end;
  2137. if size=OS_64 then
  2138. begin
  2139. { the arm has an weired opinion how flags for SUB/ADD are handled }
  2140. ovloc.loc:=LOC_FLAGS;
  2141. case op of
  2142. OP_ADD:
  2143. ovloc.resflags:=F_CS;
  2144. OP_SUB:
  2145. ovloc.resflags:=F_CC;
  2146. end;
  2147. end;
  2148. end
  2149. else
  2150. begin
  2151. case op of
  2152. OP_AND,OP_OR,OP_XOR:
  2153. begin
  2154. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  2155. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  2156. end;
  2157. OP_ADD:
  2158. begin
  2159. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  2160. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  2161. end;
  2162. OP_SUB:
  2163. begin
  2164. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  2165. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
  2166. end;
  2167. else
  2168. internalerror(2003083101);
  2169. end;
  2170. end;
  2171. end;
  2172. procedure Tthumb2cgarm.init_register_allocators;
  2173. begin
  2174. inherited init_register_allocators;
  2175. { currently, we save R14 always, so we can use it }
  2176. if (target_info.system<>system_arm_darwin) then
  2177. rg[R_INTREGISTER]:=trgcputhumb2.create(R_INTREGISTER,R_SUBWHOLE,
  2178. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  2179. RS_R9,RS_R10,RS_R12,RS_R14],first_int_imreg,[])
  2180. else
  2181. { r9 is not available on Darwin according to the llvm code generator }
  2182. rg[R_INTREGISTER]:=trgcputhumb2.create(R_INTREGISTER,R_SUBWHOLE,
  2183. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  2184. RS_R10,RS_R12,RS_R14],first_int_imreg,[]);
  2185. rg[R_FPUREGISTER]:=trgcputhumb2.create(R_FPUREGISTER,R_SUBNONE,
  2186. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7],first_fpu_imreg,[]);
  2187. rg[R_MMREGISTER]:=trgcputhumb2.create(R_MMREGISTER,R_SUBNONE,
  2188. [RS_S0,RS_S1,RS_R2,RS_R3,RS_R4,RS_S31],first_mm_imreg,[]);
  2189. end;
  2190. procedure Tthumb2cgarm.done_register_allocators;
  2191. begin
  2192. rg[R_INTREGISTER].free;
  2193. rg[R_FPUREGISTER].free;
  2194. rg[R_MMREGISTER].free;
  2195. inherited done_register_allocators;
  2196. end;
  2197. procedure Tthumb2cgarm.a_call_reg(list : TAsmList;reg: tregister);
  2198. begin
  2199. list.concat(taicpu.op_reg(A_BLX, reg));
  2200. {
  2201. the compiler does not properly set this flag anymore in pass 1, and
  2202. for now we only need it after pass 2 (I hope) (JM)
  2203. if not(pi_do_call in current_procinfo.flags) then
  2204. internalerror(2003060703);
  2205. }
  2206. include(current_procinfo.flags,pi_do_call);
  2207. end;
  2208. procedure Tthumb2cgarm.a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);
  2209. var
  2210. imm_shift : byte;
  2211. l : tasmlabel;
  2212. hr : treference;
  2213. begin
  2214. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  2215. internalerror(2002090902);
  2216. if is_shifter_const(a,imm_shift) then
  2217. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  2218. { loading of constants with mov and orr }
  2219. else if (is_shifter_const(a-byte(a),imm_shift)) then
  2220. begin
  2221. list.concat(taicpu.op_reg_const(A_MOV,reg,a-byte(a)));
  2222. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,byte(a)));
  2223. end
  2224. else if (is_shifter_const(a-word(a),imm_shift)) and (is_shifter_const(word(a),imm_shift)) then
  2225. begin
  2226. list.concat(taicpu.op_reg_const(A_MOV,reg,a-word(a)));
  2227. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,word(a)));
  2228. end
  2229. else if (is_shifter_const(a-(dword(a) shl 8) shr 8,imm_shift)) and (is_shifter_const((dword(a) shl 8) shr 8,imm_shift)) then
  2230. begin
  2231. list.concat(taicpu.op_reg_const(A_MOV,reg,a-(dword(a) shl 8) shr 8));
  2232. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,(dword(a) shl 8) shr 8));
  2233. end
  2234. else
  2235. begin
  2236. reference_reset(hr,4);
  2237. current_asmdata.getjumplabel(l);
  2238. cg.a_label(current_procinfo.aktlocaldata,l);
  2239. hr.symboldata:=current_procinfo.aktlocaldata.last;
  2240. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
  2241. hr.symbol:=l;
  2242. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  2243. end;
  2244. end;
  2245. procedure Tthumb2cgarm.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  2246. var
  2247. oppostfix:toppostfix;
  2248. usedtmpref: treference;
  2249. tmpreg,tmpreg2 : tregister;
  2250. so : tshifterop;
  2251. dir : integer;
  2252. begin
  2253. if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then
  2254. FromSize := ToSize;
  2255. case FromSize of
  2256. { signed integer registers }
  2257. OS_8:
  2258. oppostfix:=PF_B;
  2259. OS_S8:
  2260. oppostfix:=PF_SB;
  2261. OS_16:
  2262. oppostfix:=PF_H;
  2263. OS_S16:
  2264. oppostfix:=PF_SH;
  2265. OS_32,
  2266. OS_S32:
  2267. oppostfix:=PF_None;
  2268. else
  2269. InternalError(200308297);
  2270. end;
  2271. if (ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[fromsize]) then
  2272. begin
  2273. if target_info.endian=endian_big then
  2274. dir:=-1
  2275. else
  2276. dir:=1;
  2277. case FromSize of
  2278. OS_16,OS_S16:
  2279. begin
  2280. { only complicated references need an extra loadaddr }
  2281. if assigned(ref.symbol) or
  2282. (ref.index<>NR_NO) or
  2283. (ref.offset<-255) or
  2284. (ref.offset>4094) or
  2285. { sometimes the compiler reused registers }
  2286. (reg=ref.index) or
  2287. (reg=ref.base) then
  2288. begin
  2289. tmpreg2:=getintregister(list,OS_INT);
  2290. a_loadaddr_ref_reg(list,ref,tmpreg2);
  2291. reference_reset_base(usedtmpref,tmpreg2,0,ref.alignment);
  2292. end
  2293. else
  2294. usedtmpref:=ref;
  2295. if target_info.endian=endian_big then
  2296. inc(usedtmpref.offset,1);
  2297. shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8;
  2298. tmpreg:=getintregister(list,OS_INT);
  2299. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  2300. inc(usedtmpref.offset,dir);
  2301. if FromSize=OS_16 then
  2302. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg)
  2303. else
  2304. a_internal_load_ref_reg(list,OS_S8,OS_S8,usedtmpref,tmpreg);
  2305. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  2306. end;
  2307. OS_32,OS_S32:
  2308. begin
  2309. tmpreg:=getintregister(list,OS_INT);
  2310. { only complicated references need an extra loadaddr }
  2311. if assigned(ref.symbol) or
  2312. (ref.index<>NR_NO) or
  2313. (ref.offset<-255) or
  2314. (ref.offset>4092) or
  2315. { sometimes the compiler reused registers }
  2316. (reg=ref.index) or
  2317. (reg=ref.base) then
  2318. begin
  2319. tmpreg2:=getintregister(list,OS_INT);
  2320. a_loadaddr_ref_reg(list,ref,tmpreg2);
  2321. reference_reset_base(usedtmpref,tmpreg2,0,ref.alignment);
  2322. end
  2323. else
  2324. usedtmpref:=ref;
  2325. shifterop_reset(so);so.shiftmode:=SM_LSL;
  2326. if ref.alignment=2 then
  2327. begin
  2328. if target_info.endian=endian_big then
  2329. inc(usedtmpref.offset,2);
  2330. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,reg);
  2331. inc(usedtmpref.offset,dir*2);
  2332. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,tmpreg);
  2333. so.shiftimm:=16;
  2334. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  2335. end
  2336. else
  2337. begin
  2338. if target_info.endian=endian_big then
  2339. inc(usedtmpref.offset,3);
  2340. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  2341. inc(usedtmpref.offset,dir);
  2342. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  2343. so.shiftimm:=8;
  2344. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  2345. inc(usedtmpref.offset,dir);
  2346. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  2347. so.shiftimm:=16;
  2348. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  2349. inc(usedtmpref.offset,dir);
  2350. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  2351. so.shiftimm:=24;
  2352. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  2353. end;
  2354. end
  2355. else
  2356. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  2357. end;
  2358. end
  2359. else
  2360. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  2361. if (fromsize=OS_S8) and (tosize = OS_16) then
  2362. a_load_reg_reg(list,OS_16,OS_32,reg,reg);
  2363. end;
  2364. procedure Tthumb2cgarm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);
  2365. var
  2366. shift : byte;
  2367. tmpreg : tregister;
  2368. so : tshifterop;
  2369. l1 : longint;
  2370. begin
  2371. ovloc.loc:=LOC_VOID;
  2372. if {$ifopt R+}(a<>-2147483648) and{$endif} is_shifter_const(-a,shift) then
  2373. case op of
  2374. OP_ADD:
  2375. begin
  2376. op:=OP_SUB;
  2377. a:=aint(dword(-a));
  2378. end;
  2379. OP_SUB:
  2380. begin
  2381. op:=OP_ADD;
  2382. a:=aint(dword(-a));
  2383. end
  2384. end;
  2385. if is_shifter_const(a,shift) and not(op in [OP_IMUL,OP_MUL]) then
  2386. case op of
  2387. OP_NEG,OP_NOT,
  2388. OP_DIV,OP_IDIV:
  2389. internalerror(200308281);
  2390. OP_SHL:
  2391. begin
  2392. if a>32 then
  2393. internalerror(200308294);
  2394. if a<>0 then
  2395. begin
  2396. shifterop_reset(so);
  2397. so.shiftmode:=SM_LSL;
  2398. so.shiftimm:=a;
  2399. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  2400. end
  2401. else
  2402. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  2403. end;
  2404. OP_ROL:
  2405. begin
  2406. if a>32 then
  2407. internalerror(200308294);
  2408. if a<>0 then
  2409. begin
  2410. shifterop_reset(so);
  2411. so.shiftmode:=SM_ROR;
  2412. so.shiftimm:=32-a;
  2413. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  2414. end
  2415. else
  2416. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  2417. end;
  2418. OP_ROR:
  2419. begin
  2420. if a>32 then
  2421. internalerror(200308294);
  2422. if a<>0 then
  2423. begin
  2424. shifterop_reset(so);
  2425. so.shiftmode:=SM_ROR;
  2426. so.shiftimm:=a;
  2427. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  2428. end
  2429. else
  2430. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  2431. end;
  2432. OP_SHR:
  2433. begin
  2434. if a>32 then
  2435. internalerror(200308292);
  2436. shifterop_reset(so);
  2437. if a<>0 then
  2438. begin
  2439. so.shiftmode:=SM_LSR;
  2440. so.shiftimm:=a;
  2441. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  2442. end
  2443. else
  2444. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  2445. end;
  2446. OP_SAR:
  2447. begin
  2448. if a>32 then
  2449. internalerror(200308295);
  2450. if a<>0 then
  2451. begin
  2452. shifterop_reset(so);
  2453. so.shiftmode:=SM_ASR;
  2454. so.shiftimm:=a;
  2455. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  2456. end
  2457. else
  2458. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  2459. end;
  2460. else
  2461. if (op in [OP_SUB, OP_ADD]) and
  2462. ((a < 0) or
  2463. (a > 4095)) then
  2464. begin
  2465. tmpreg:=getintregister(list,size);
  2466. a_load_const_reg(list, size, a, tmpreg);
  2467. list.concat(setoppostfix(taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src,tmpreg),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  2468. ));
  2469. end
  2470. else
  2471. list.concat(setoppostfix(
  2472. taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  2473. ));
  2474. if (cgsetflags or setflags) and (size in [OS_8,OS_16,OS_32]) then
  2475. begin
  2476. ovloc.loc:=LOC_FLAGS;
  2477. case op of
  2478. OP_ADD:
  2479. ovloc.resflags:=F_CS;
  2480. OP_SUB:
  2481. ovloc.resflags:=F_CC;
  2482. end;
  2483. end;
  2484. end
  2485. else
  2486. begin
  2487. { there could be added some more sophisticated optimizations }
  2488. if (op in [OP_MUL,OP_IMUL]) and (a=1) then
  2489. a_load_reg_reg(list,size,size,src,dst)
  2490. else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
  2491. a_load_const_reg(list,size,0,dst)
  2492. else if (op in [OP_IMUL]) and (a=-1) then
  2493. a_op_reg_reg(list,OP_NEG,size,src,dst)
  2494. { we do this here instead in the peephole optimizer because
  2495. it saves us a register }
  2496. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) and not(cgsetflags or setflags) then
  2497. a_op_const_reg_reg(list,OP_SHL,size,l1,src,dst)
  2498. { for example : b=a*5 -> b=a*4+a with add instruction and shl }
  2499. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a-1,l1) and not(cgsetflags or setflags) then
  2500. begin
  2501. if l1>32 then{roozbeh does this ever happen?}
  2502. internalerror(200308296);
  2503. shifterop_reset(so);
  2504. so.shiftmode:=SM_LSL;
  2505. so.shiftimm:=l1;
  2506. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,dst,src,src,so));
  2507. end
  2508. else
  2509. begin
  2510. tmpreg:=getintregister(list,size);
  2511. a_load_const_reg(list,size,a,tmpreg);
  2512. a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,setflags,ovloc);
  2513. end;
  2514. end;
  2515. maybeadjustresult(list,op,size,dst);
  2516. end;
  2517. const
  2518. op_reg_reg_opcg2asmopThumb2: array[TOpCG] of tasmop =
  2519. (A_NONE,A_MOV,A_ADD,A_AND,A_UDIV,A_SDIV,A_MUL,A_MUL,A_NONE,A_MVN,A_ORR,
  2520. A_ASR,A_LSL,A_LSR,A_SUB,A_EOR,A_NONE,A_ROR);
  2521. procedure Tthumb2cgarm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);
  2522. var
  2523. so : tshifterop;
  2524. tmpreg,overflowreg : tregister;
  2525. asmop : tasmop;
  2526. begin
  2527. ovloc.loc:=LOC_VOID;
  2528. case op of
  2529. OP_NEG,OP_NOT,
  2530. OP_DIV,OP_IDIV:
  2531. internalerror(200308281);
  2532. OP_ROL:
  2533. begin
  2534. if not(size in [OS_32,OS_S32]) then
  2535. internalerror(2008072801);
  2536. { simulate ROL by ror'ing 32-value }
  2537. tmpreg:=getintregister(list,OS_32);
  2538. list.concat(taicpu.op_reg_const(A_MOV,tmpreg,32));
  2539. list.concat(taicpu.op_reg_reg_reg(A_SUB,src1,tmpreg,src1));
  2540. list.concat(taicpu.op_reg_reg_reg(A_ROR, dst, src2, src1));
  2541. end;
  2542. OP_ROR:
  2543. begin
  2544. if not(size in [OS_32,OS_S32]) then
  2545. internalerror(2008072802);
  2546. list.concat(taicpu.op_reg_reg_reg(A_ROR, dst, src2, src1));
  2547. end;
  2548. OP_IMUL,
  2549. OP_MUL:
  2550. begin
  2551. if cgsetflags or setflags then
  2552. begin
  2553. overflowreg:=getintregister(list,size);
  2554. if op=OP_IMUL then
  2555. asmop:=A_SMULL
  2556. else
  2557. asmop:=A_UMULL;
  2558. { the arm doesn't allow that rd and rm are the same }
  2559. if dst=src2 then
  2560. begin
  2561. if dst<>src1 then
  2562. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src1,src2))
  2563. else
  2564. begin
  2565. tmpreg:=getintregister(list,size);
  2566. a_load_reg_reg(list,size,size,src2,dst);
  2567. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,tmpreg,src1));
  2568. end;
  2569. end
  2570. else
  2571. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src2,src1));
  2572. if op=OP_IMUL then
  2573. begin
  2574. shifterop_reset(so);
  2575. so.shiftmode:=SM_ASR;
  2576. so.shiftimm:=31;
  2577. list.concat(taicpu.op_reg_reg_shifterop(A_CMP,overflowreg,dst,so));
  2578. end
  2579. else
  2580. list.concat(taicpu.op_reg_const(A_CMP,overflowreg,0));
  2581. ovloc.loc:=LOC_FLAGS;
  2582. ovloc.resflags:=F_NE;
  2583. end
  2584. else
  2585. begin
  2586. { the arm doesn't allow that rd and rm are the same }
  2587. if dst=src2 then
  2588. begin
  2589. if dst<>src1 then
  2590. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
  2591. else
  2592. begin
  2593. tmpreg:=getintregister(list,size);
  2594. a_load_reg_reg(list,size,size,src2,dst);
  2595. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,tmpreg,src1));
  2596. end;
  2597. end
  2598. else
  2599. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
  2600. end;
  2601. end;
  2602. else
  2603. list.concat(setoppostfix(
  2604. taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmopThumb2[op],dst,src2,src1),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  2605. ));
  2606. end;
  2607. maybeadjustresult(list,op,size,dst);
  2608. end;
  2609. procedure Tthumb2cgarm.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  2610. var item: taicpu;
  2611. begin
  2612. item := setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f));
  2613. list.concat(item);
  2614. list.insertbefore(taicpu.op_cond(A_IT, flags_to_cond(f)), item);
  2615. item := setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond(flags_to_cond(f)));
  2616. list.concat(item);
  2617. list.insertbefore(taicpu.op_cond(A_IT, inverse_cond(flags_to_cond(f))), item);
  2618. end;
  2619. procedure Tthumb2cgarm.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  2620. var
  2621. ref : treference;
  2622. shift : byte;
  2623. firstfloatreg,lastfloatreg,
  2624. r : byte;
  2625. regs : tcpuregisterset;
  2626. stackmisalignment: pint;
  2627. begin
  2628. LocalSize:=align(LocalSize,4);
  2629. { call instruction does not put anything on the stack }
  2630. stackmisalignment:=0;
  2631. if not(nostackframe) then
  2632. begin
  2633. firstfloatreg:=RS_NO;
  2634. { save floating point registers? }
  2635. for r:=RS_F0 to RS_F7 do
  2636. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  2637. begin
  2638. if firstfloatreg=RS_NO then
  2639. firstfloatreg:=r;
  2640. lastfloatreg:=r;
  2641. inc(stackmisalignment,12);
  2642. end;
  2643. a_reg_alloc(list,NR_STACK_POINTER_REG);
  2644. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  2645. begin
  2646. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  2647. a_reg_alloc(list,NR_R12);
  2648. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  2649. end;
  2650. { save int registers }
  2651. reference_reset(ref,4);
  2652. ref.index:=NR_STACK_POINTER_REG;
  2653. ref.addressmode:=AM_PREINDEXED;
  2654. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  2655. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  2656. regs:=regs+[RS_R11,RS_R14]
  2657. else if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
  2658. include(regs,RS_R14);
  2659. if regs<>[] then
  2660. begin
  2661. for r:=RS_R0 to RS_R15 do
  2662. if (r in regs) then
  2663. inc(stackmisalignment,4);
  2664. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,regs),PF_FD));
  2665. end;
  2666. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  2667. list.concat(taicpu.op_reg_reg(A_MOV,NR_FRAME_POINTER_REG,NR_R12));
  2668. stackmisalignment:=stackmisalignment mod current_settings.alignment.localalignmax;
  2669. if (LocalSize<>0) or
  2670. ((stackmisalignment<>0) and
  2671. ((pi_do_call in current_procinfo.flags) or
  2672. (po_assembler in current_procinfo.procdef.procoptions))) then
  2673. begin
  2674. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  2675. if not(is_shifter_const(localsize,shift)) then
  2676. begin
  2677. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  2678. a_reg_alloc(list,NR_R12);
  2679. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  2680. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  2681. a_reg_dealloc(list,NR_R12);
  2682. end
  2683. else
  2684. begin
  2685. a_reg_dealloc(list,NR_R12);
  2686. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  2687. end;
  2688. end;
  2689. if firstfloatreg<>RS_NO then
  2690. begin
  2691. reference_reset(ref,4);
  2692. if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
  2693. begin
  2694. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  2695. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  2696. ref.base:=NR_R12;
  2697. end
  2698. else
  2699. begin
  2700. ref.base:=current_procinfo.framepointer;
  2701. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  2702. end;
  2703. list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  2704. lastfloatreg-firstfloatreg+1,ref));
  2705. end;
  2706. end;
  2707. end;
  2708. procedure Tthumb2cgarm.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  2709. var
  2710. ref : treference;
  2711. firstfloatreg,lastfloatreg,
  2712. r : byte;
  2713. shift : byte;
  2714. regs : tcpuregisterset;
  2715. LocalSize : longint;
  2716. stackmisalignment: pint;
  2717. begin
  2718. if not(nostackframe) then
  2719. begin
  2720. stackmisalignment:=0;
  2721. { restore floating point register }
  2722. firstfloatreg:=RS_NO;
  2723. { save floating point registers? }
  2724. for r:=RS_F0 to RS_F7 do
  2725. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  2726. begin
  2727. if firstfloatreg=RS_NO then
  2728. firstfloatreg:=r;
  2729. lastfloatreg:=r;
  2730. { floating point register space is already included in
  2731. localsize below by calc_stackframe_size
  2732. inc(stackmisalignment,12);
  2733. }
  2734. end;
  2735. if firstfloatreg<>RS_NO then
  2736. begin
  2737. reference_reset(ref,4);
  2738. if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
  2739. begin
  2740. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  2741. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  2742. ref.base:=NR_R12;
  2743. end
  2744. else
  2745. begin
  2746. ref.base:=current_procinfo.framepointer;
  2747. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  2748. end;
  2749. list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  2750. lastfloatreg-firstfloatreg+1,ref));
  2751. end;
  2752. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  2753. if (pi_do_call in current_procinfo.flags) or (regs<>[]) then
  2754. begin
  2755. exclude(regs,RS_R14);
  2756. include(regs,RS_R15);
  2757. end;
  2758. if (current_procinfo.framepointer<>NR_STACK_POINTER_REG) then
  2759. regs:=regs+[RS_R11,RS_R15];
  2760. for r:=RS_R0 to RS_R15 do
  2761. if (r in regs) then
  2762. inc(stackmisalignment,4);
  2763. stackmisalignment:=stackmisalignment mod current_settings.alignment.localalignmax;
  2764. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  2765. begin
  2766. LocalSize:=current_procinfo.calc_stackframe_size;
  2767. if (LocalSize<>0) or
  2768. ((stackmisalignment<>0) and
  2769. ((pi_do_call in current_procinfo.flags) or
  2770. (po_assembler in current_procinfo.procdef.procoptions))) then
  2771. begin
  2772. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  2773. if not(is_shifter_const(LocalSize,shift)) then
  2774. begin
  2775. a_reg_alloc(list,NR_R12);
  2776. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  2777. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  2778. a_reg_dealloc(list,NR_R12);
  2779. end
  2780. else
  2781. begin
  2782. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  2783. end;
  2784. end;
  2785. if regs=[] then
  2786. list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
  2787. else
  2788. begin
  2789. reference_reset(ref,4);
  2790. ref.index:=NR_STACK_POINTER_REG;
  2791. ref.addressmode:=AM_PREINDEXED;
  2792. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,regs),PF_FD));
  2793. end;
  2794. end
  2795. else
  2796. begin
  2797. { restore int registers and return }
  2798. list.concat(taicpu.op_reg_reg(A_MOV, NR_STACK_POINTER_REG, NR_R11));
  2799. reference_reset(ref,4);
  2800. ref.index:=NR_STACK_POINTER_REG;
  2801. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,regs),PF_DB));
  2802. end;
  2803. end
  2804. else
  2805. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14));
  2806. end;
  2807. function Tthumb2cgarm.handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference;
  2808. var
  2809. tmpreg : tregister;
  2810. tmpref : treference;
  2811. l : tasmlabel;
  2812. so: tshifterop;
  2813. begin
  2814. tmpreg:=NR_NO;
  2815. { Be sure to have a base register }
  2816. if (ref.base=NR_NO) then
  2817. begin
  2818. if ref.shiftmode<>SM_None then
  2819. internalerror(200308294);
  2820. ref.base:=ref.index;
  2821. ref.index:=NR_NO;
  2822. end;
  2823. { absolute symbols can't be handled directly, we've to store the symbol reference
  2824. in the text segment and access it pc relative
  2825. For now, we assume that references where base or index equals to PC are already
  2826. relative, all other references are assumed to be absolute and thus they need
  2827. to be handled extra.
  2828. A proper solution would be to change refoptions to a set and store the information
  2829. if the symbol is absolute or relative there.
  2830. }
  2831. if (assigned(ref.symbol) and
  2832. not(is_pc(ref.base)) and
  2833. not(is_pc(ref.index))
  2834. ) or
  2835. { [#xxx] isn't a valid address operand }
  2836. ((ref.base=NR_NO) and (ref.index=NR_NO)) or
  2837. //(ref.offset<-4095) or
  2838. (ref.offset<-255) or
  2839. (ref.offset>4095) or
  2840. ((oppostfix in [PF_SB,PF_H,PF_SH]) and
  2841. ((ref.offset<-255) or
  2842. (ref.offset>255)
  2843. )
  2844. ) or
  2845. ((op in [A_LDF,A_STF]) and
  2846. ((ref.offset<-1020) or
  2847. (ref.offset>1020) or
  2848. { the usual pc relative symbol handling assumes possible offsets of +/- 4095 }
  2849. assigned(ref.symbol)
  2850. )
  2851. ) then
  2852. begin
  2853. reference_reset(tmpref,4);
  2854. { load symbol }
  2855. tmpreg:=getintregister(list,OS_INT);
  2856. if assigned(ref.symbol) then
  2857. begin
  2858. current_asmdata.getjumplabel(l);
  2859. cg.a_label(current_procinfo.aktlocaldata,l);
  2860. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  2861. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset));
  2862. { load consts entry }
  2863. tmpref.symbol:=l;
  2864. tmpref.base:=NR_R15;
  2865. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  2866. { in case of LDF/STF, we got rid of the NR_R15 }
  2867. if is_pc(ref.base) then
  2868. ref.base:=NR_NO;
  2869. if is_pc(ref.index) then
  2870. ref.index:=NR_NO;
  2871. end
  2872. else
  2873. a_load_const_reg(list,OS_ADDR,ref.offset,tmpreg);
  2874. if (ref.base<>NR_NO) then
  2875. begin
  2876. if ref.index<>NR_NO then
  2877. begin
  2878. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  2879. ref.base:=tmpreg;
  2880. end
  2881. else
  2882. begin
  2883. ref.index:=tmpreg;
  2884. ref.shiftimm:=0;
  2885. ref.signindex:=1;
  2886. ref.shiftmode:=SM_None;
  2887. end;
  2888. end
  2889. else
  2890. ref.base:=tmpreg;
  2891. ref.offset:=0;
  2892. ref.symbol:=nil;
  2893. end;
  2894. if (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then
  2895. begin
  2896. if tmpreg<>NR_NO then
  2897. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg,tmpreg)
  2898. else
  2899. begin
  2900. tmpreg:=getintregister(list,OS_ADDR);
  2901. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg);
  2902. ref.base:=tmpreg;
  2903. end;
  2904. ref.offset:=0;
  2905. end;
  2906. { Hack? Thumb2 doesn't allow PC indexed addressing modes(although it does in the specification) }
  2907. if (ref.base=NR_R15) and (ref.index<>NR_NO) and (ref.shiftmode <> sm_none) then
  2908. begin
  2909. tmpreg:=getintregister(list,OS_ADDR);
  2910. list.concat(taicpu.op_reg_reg(A_MOV, tmpreg, NR_R15));
  2911. ref.base := tmpreg;
  2912. end;
  2913. { floating point operations have only limited references
  2914. we expect here, that a base is already set }
  2915. if (op in [A_LDF,A_STF]) and (ref.index<>NR_NO) then
  2916. begin
  2917. if ref.shiftmode<>SM_none then
  2918. internalerror(200309121);
  2919. if tmpreg<>NR_NO then
  2920. begin
  2921. if ref.base=tmpreg then
  2922. begin
  2923. if ref.signindex<0 then
  2924. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,tmpreg,ref.index))
  2925. else
  2926. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg,ref.index));
  2927. ref.index:=NR_NO;
  2928. end
  2929. else
  2930. begin
  2931. if ref.index<>tmpreg then
  2932. internalerror(200403161);
  2933. if ref.signindex<0 then
  2934. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,ref.base,tmpreg))
  2935. else
  2936. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  2937. ref.base:=tmpreg;
  2938. ref.index:=NR_NO;
  2939. end;
  2940. end
  2941. else
  2942. begin
  2943. tmpreg:=getintregister(list,OS_ADDR);
  2944. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
  2945. ref.base:=tmpreg;
  2946. ref.index:=NR_NO;
  2947. end;
  2948. end;
  2949. list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
  2950. Result := ref;
  2951. end;
  2952. procedure tthumb2cg64farm.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  2953. var tmpreg: tregister;
  2954. begin
  2955. case op of
  2956. OP_NEG:
  2957. begin
  2958. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  2959. tmpreg:=cg.getintregister(list,OS_32);
  2960. list.concat(taicpu.op_reg_const(A_MOV,tmpreg,0));
  2961. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,tmpreg,regsrc.reghi));
  2962. end;
  2963. else
  2964. inherited a_op64_reg_reg(list, op, size, regsrc, regdst);
  2965. end;
  2966. end;
  2967. procedure create_codegen;
  2968. begin
  2969. if current_settings.cputype in cpu_thumb2 then
  2970. begin
  2971. cg:=tthumb2cgarm.create;
  2972. cg64:=tthumb2cg64farm.create;
  2973. casmoptimizer:=TCpuThumb2AsmOptimizer;
  2974. end
  2975. else
  2976. begin
  2977. cg:=tarmcgarm.create;
  2978. cg64:=tcg64farm.create;
  2979. casmoptimizer:=TCpuAsmOptimizer;
  2980. end;
  2981. end;
  2982. end.