cgobj.pas 135 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312
  1. {
  2. Copyright (c) 1998-2005 by Florian Klaempfl
  3. Member of the Free Pascal development team
  4. This unit implements the basic code generator object
  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. {# @abstract(Abstract code generator unit)
  19. Abstreact code generator unit. This contains the base class
  20. to implement for all new supported processors.
  21. WARNING: None of the routines implemented in these modules,
  22. or their descendants, should use the temp. allocator, as
  23. these routines may be called inside genentrycode, and the
  24. stack frame is already setup!
  25. }
  26. unit cgobj;
  27. {$i fpcdefs.inc}
  28. interface
  29. uses
  30. globtype,constexp,
  31. cpubase,cgbase,cgutils,parabase,
  32. aasmbase,aasmtai,aasmdata,aasmcpu,
  33. symconst,symtype,symdef,rgobj
  34. ;
  35. type
  36. talignment = (AM_NATURAL,AM_NONE,AM_2BYTE,AM_4BYTE,AM_8BYTE);
  37. {# @abstract(Abstract code generator)
  38. This class implements an abstract instruction generator. Some of
  39. the methods of this class are generic, while others must
  40. be overridden for all new processors which will be supported
  41. by Free Pascal. For 32-bit processors, the base class
  42. should be @link(tcg64f32) and not @var(tcg).
  43. }
  44. { tcg }
  45. tcg = class
  46. { how many times is this current code executed }
  47. executionweight : longint;
  48. alignment : talignment;
  49. rg : array[tregistertype] of trgobj;
  50. {$if defined(cpu8bitalu) or defined(cpu16bitalu)}
  51. has_next_reg: bitpacked array[TSuperRegister] of boolean;
  52. {$endif cpu8bitalu or cpu16bitalu}
  53. {$ifdef flowgraph}
  54. aktflownode:word;
  55. {$endif}
  56. {************************************************}
  57. { basic routines }
  58. constructor create;
  59. {# Initialize the register allocators needed for the codegenerator.}
  60. procedure init_register_allocators;virtual;
  61. {# Clean up the register allocators needed for the codegenerator.}
  62. procedure done_register_allocators;virtual;
  63. {# Set whether live_start or live_end should be updated when allocating registers, needed when e.g. generating initcode after the rest of the code. }
  64. procedure set_regalloc_live_range_direction(dir: TRADirection);
  65. {$ifdef flowgraph}
  66. procedure init_flowgraph;
  67. procedure done_flowgraph;
  68. {$endif}
  69. {# Gets a register suitable to do integer operations on.}
  70. function getintregister(list:TAsmList;size:Tcgsize):Tregister;virtual;
  71. {# Gets a register suitable to do integer operations on.}
  72. function getaddressregister(list:TAsmList):Tregister;virtual;
  73. function getfpuregister(list:TAsmList;size:Tcgsize):Tregister;virtual;
  74. function getmmregister(list:TAsmList;size:Tcgsize):Tregister;virtual;
  75. function getflagregister(list:TAsmList;size:Tcgsize):Tregister;virtual;
  76. function gettempregister(list:TAsmList):Tregister;virtual;
  77. {Does the generic cg need SIMD registers, like getmmxregister? Or should
  78. the cpu specific child cg object have such a method?}
  79. {$if defined(cpu8bitalu) or defined(cpu16bitalu)}
  80. {# returns the next virtual register }
  81. function GetNextReg(const r: TRegister): TRegister;virtual;
  82. {$endif cpu8bitalu or cpu16bitalu}
  83. {$ifdef cpu8bitalu}
  84. {# returns the register with the offset of ofs of a continuous set of register starting with r }
  85. function GetOffsetReg(const r : TRegister;ofs : shortint) : TRegister;virtual;abstract;
  86. {# returns the register with the offset of ofs of a continuous set of register starting with r and being continued with rhi }
  87. function GetOffsetReg64(const r,rhi: TRegister;ofs : shortint): TRegister;virtual;abstract;
  88. {$endif cpu8bitalu}
  89. procedure add_reg_instruction(instr:Tai;r:tregister);virtual;
  90. procedure add_move_instruction(instr:Taicpu);virtual;
  91. function uses_registers(rt:Tregistertype):boolean;virtual;
  92. {# Get a specific register.}
  93. procedure getcpuregister(list:TAsmList;r:Tregister);virtual;
  94. procedure ungetcpuregister(list:TAsmList;r:Tregister);virtual;
  95. {# Get multiple registers specified.}
  96. procedure alloccpuregisters(list:TAsmList;rt:Tregistertype;const r:Tcpuregisterset);virtual;
  97. {# Free multiple registers specified.}
  98. procedure dealloccpuregisters(list:TAsmList;rt:Tregistertype;const r:Tcpuregisterset);virtual;
  99. procedure allocallcpuregisters(list:TAsmList);virtual;
  100. procedure deallocallcpuregisters(list:TAsmList);virtual;
  101. procedure do_register_allocation(list:TAsmList;headertai:tai);virtual;
  102. procedure translate_register(var reg : tregister);
  103. function makeregsize(list:TAsmList;reg:Tregister;size:Tcgsize):Tregister; virtual;
  104. {# Emit a label to the instruction stream. }
  105. procedure a_label(list : TAsmList;l : tasmlabel);virtual;
  106. {# Allocates register r by inserting a pai_realloc record }
  107. procedure a_reg_alloc(list : TAsmList;r : tregister);
  108. {# Deallocates register r by inserting a pa_regdealloc record}
  109. procedure a_reg_dealloc(list : TAsmList;r : tregister);
  110. { Synchronize register, make sure it is still valid }
  111. procedure a_reg_sync(list : TAsmList;r : tregister);
  112. {# Pass a parameter, which is located in a register, to a routine.
  113. This routine should push/send the parameter to the routine, as
  114. required by the specific processor ABI and routine modifiers.
  115. It must generate register allocation information for the cgpara in
  116. case it consists of cpuregisters.
  117. @param(size size of the operand in the register)
  118. @param(r register source of the operand)
  119. @param(cgpara where the parameter will be stored)
  120. }
  121. procedure a_load_reg_cgpara(list : TAsmList;size : tcgsize;r : tregister;const cgpara : TCGPara);virtual;
  122. {# Pass a parameter, which is a constant, to a routine.
  123. A generic version is provided. This routine should
  124. be overridden for optimization purposes if the cpu
  125. permits directly sending this type of parameter.
  126. It must generate register allocation information for the cgpara in
  127. case it consists of cpuregisters.
  128. @param(size size of the operand in constant)
  129. @param(a value of constant to send)
  130. @param(cgpara where the parameter will be stored)
  131. }
  132. procedure a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const cgpara : TCGPara);virtual;
  133. {# Pass the value of a parameter, which is located in memory, to a routine.
  134. A generic version is provided. This routine should
  135. be overridden for optimization purposes if the cpu
  136. permits directly sending this type of parameter.
  137. It must generate register allocation information for the cgpara in
  138. case it consists of cpuregisters.
  139. @param(size size of the operand in constant)
  140. @param(r Memory reference of value to send)
  141. @param(cgpara where the parameter will be stored)
  142. }
  143. procedure a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : TCGPara);virtual;
  144. {# Pass the value of a parameter, which can be located either in a register or memory location,
  145. to a routine.
  146. A generic version is provided.
  147. @param(l location of the operand to send)
  148. @param(nr parameter number (starting from one) of routine (from left to right))
  149. @param(cgpara where the parameter will be stored)
  150. }
  151. procedure a_load_loc_cgpara(list : TAsmList;const l : tlocation;const cgpara : TCGPara);
  152. {# Pass the address of a reference to a routine. This routine
  153. will calculate the address of the reference, and pass this
  154. calculated address as a parameter.
  155. It must generate register allocation information for the cgpara in
  156. case it consists of cpuregisters.
  157. A generic version is provided. This routine should
  158. be overridden for optimization purposes if the cpu
  159. permits directly sending this type of parameter.
  160. @param(r reference to get address from)
  161. @param(nr parameter number (starting from one) of routine (from left to right))
  162. }
  163. procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const cgpara : TCGPara);virtual;
  164. {# Load a cgparaloc into a memory reference.
  165. It must generate register allocation information for the cgpara in
  166. case it consists of cpuregisters.
  167. @param(paraloc the source parameter sublocation)
  168. @param(ref the destination reference)
  169. @param(sizeleft indicates the total number of bytes left in all of
  170. the remaining sublocations of this parameter (the current
  171. sublocation and all of the sublocations coming after it).
  172. In case this location is also a reference, it is assumed
  173. to be the final part sublocation of the parameter and that it
  174. contains all of the "sizeleft" bytes).)
  175. @param(align the alignment of the paraloc in case it's a reference)
  176. }
  177. procedure a_load_cgparaloc_ref(list : TAsmList;const paraloc : TCGParaLocation;const ref : treference;sizeleft : tcgint;align : longint);
  178. {# Load a cgparaloc into any kind of register (int, fp, mm).
  179. @param(regsize the size of the destination register)
  180. @param(paraloc the source parameter sublocation)
  181. @param(reg the destination register)
  182. @param(align the alignment of the paraloc in case it's a reference)
  183. }
  184. procedure a_load_cgparaloc_anyreg(list : TAsmList;regsize : tcgsize;const paraloc : TCGParaLocation;reg : tregister;align : longint);
  185. { Remarks:
  186. * If a method specifies a size you have only to take care
  187. of that number of bits, i.e. load_const_reg with OP_8 must
  188. only load the lower 8 bit of the specified register
  189. the rest of the register can be undefined
  190. if necessary the compiler will call a method
  191. to zero or sign extend the register
  192. * The a_load_XX_XX with OP_64 needn't to be
  193. implemented for 32 bit
  194. processors, the code generator takes care of that
  195. * the addr size is for work with the natural pointer
  196. size
  197. * the procedures without fpu/mm are only for integer usage
  198. * normally the first location is the source and the
  199. second the destination
  200. }
  201. {# Emits instruction to call the method specified by symbol name.
  202. This routine must be overridden for each new target cpu.
  203. }
  204. procedure a_call_name(list : TAsmList;const s : string; weak: boolean);virtual; abstract;
  205. procedure a_call_reg(list : TAsmList;reg : tregister);virtual; abstract;
  206. { same as a_call_name, might be overridden on certain architectures to emit
  207. static calls without usage of a got trampoline }
  208. procedure a_call_name_static(list : TAsmList;const s : string);virtual;
  209. { move instructions }
  210. procedure a_load_const_reg(list : TAsmList;size : tcgsize;a : tcgint;register : tregister);virtual; abstract;
  211. procedure a_load_const_ref(list : TAsmList;size : tcgsize;a : tcgint;const ref : treference);virtual;
  212. procedure a_load_const_loc(list : TAsmList;a : tcgint;const loc : tlocation);
  213. procedure a_load_reg_ref(list : TAsmList;fromsize,tosize : tcgsize;register : tregister;const ref : treference);virtual; abstract;
  214. procedure a_load_reg_ref_unaligned(list : TAsmList;fromsize,tosize : tcgsize;register : tregister;const ref : treference);virtual;
  215. procedure a_load_reg_reg(list : TAsmList;fromsize,tosize : tcgsize;reg1,reg2 : tregister);virtual; abstract;
  216. procedure a_load_reg_loc(list : TAsmList;fromsize : tcgsize;reg : tregister;const loc: tlocation);
  217. procedure a_load_ref_reg(list : TAsmList;fromsize,tosize : tcgsize;const ref : treference;register : tregister);virtual; abstract;
  218. procedure a_load_ref_reg_unaligned(list : TAsmList;fromsize,tosize : tcgsize;const ref : treference;register : tregister);virtual;
  219. procedure a_load_ref_ref(list : TAsmList;fromsize,tosize : tcgsize;const sref : treference;const dref : treference);virtual;
  220. procedure a_load_loc_reg(list : TAsmList;tosize: tcgsize; const loc: tlocation; reg : tregister);
  221. procedure a_load_loc_ref(list : TAsmList;tosize: tcgsize; const loc: tlocation; const ref : treference);
  222. procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);virtual; abstract;
  223. { bit scan instructions }
  224. procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister); virtual;
  225. { Multiplication with doubling result size.
  226. dstlo or dsthi may be NR_NO, in which case corresponding half of result is discarded. }
  227. procedure a_mul_reg_reg_pair(list: TAsmList; size: tcgsize; src1,src2,dstlo,dsthi: TRegister);virtual;
  228. { fpu move instructions }
  229. procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize:tcgsize; reg1, reg2: tregister); virtual; abstract;
  230. procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); virtual; abstract;
  231. procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); virtual; abstract;
  232. procedure a_loadfpu_ref_ref(list: TAsmList; fromsize, tosize: tcgsize; const ref1,ref2: treference);
  233. procedure a_loadfpu_loc_reg(list: TAsmList; tosize: tcgsize; const loc: tlocation; const reg: tregister);
  234. procedure a_loadfpu_reg_loc(list: TAsmList; fromsize: tcgsize; const reg: tregister; const loc: tlocation);
  235. procedure a_loadfpu_reg_cgpara(list : TAsmList;size : tcgsize;const r : tregister;const cgpara : TCGPara);virtual;
  236. procedure a_loadfpu_ref_cgpara(list : TAsmList;size : tcgsize;const ref : treference;const cgpara : TCGPara);virtual;
  237. procedure a_loadfpu_intreg_reg(list: TAsmList; fromsize, tosize : tcgsize; intreg, fpureg: tregister); virtual;
  238. { vector register move instructions }
  239. procedure a_loadmm_reg_reg(list: TAsmList; fromsize, tosize : tcgsize;reg1, reg2: tregister;shuffle : pmmshuffle); virtual;
  240. procedure a_loadmm_ref_reg(list: TAsmList; fromsize, tosize : tcgsize;const ref: treference; reg: tregister;shuffle : pmmshuffle); virtual;
  241. procedure a_loadmm_reg_ref(list: TAsmList; fromsize, tosize : tcgsize;reg: tregister; const ref: treference;shuffle : pmmshuffle); virtual;
  242. procedure a_loadmm_loc_reg(list: TAsmList; size: tcgsize; const loc: tlocation; const reg: tregister;shuffle : pmmshuffle);
  243. procedure a_loadmm_reg_loc(list: TAsmList; size: tcgsize; const reg: tregister; const loc: tlocation;shuffle : pmmshuffle);
  244. procedure a_loadmm_reg_cgpara(list: TAsmList; size: tcgsize; reg: tregister;const cgpara : TCGPara;shuffle : pmmshuffle); virtual;
  245. procedure a_loadmm_ref_cgpara(list: TAsmList; size: tcgsize; const ref: treference;const cgpara : TCGPara;shuffle : pmmshuffle); virtual;
  246. procedure a_loadmm_loc_cgpara(list: TAsmList; const loc: tlocation; const cgpara : TCGPara;shuffle : pmmshuffle); virtual;
  247. procedure a_opmm_reg_reg(list: TAsmList; Op: TOpCG; size : tcgsize;src,dst: tregister;shuffle : pmmshuffle); virtual;
  248. procedure a_opmm_ref_reg(list: TAsmList; Op: TOpCG; size : tcgsize;const ref: treference; reg: tregister;shuffle : pmmshuffle); virtual;
  249. procedure a_opmm_loc_reg(list: TAsmList; Op: TOpCG; size : tcgsize;const loc: tlocation; reg: tregister;shuffle : pmmshuffle); virtual;
  250. procedure a_opmm_reg_ref(list: TAsmList; Op: TOpCG; size : tcgsize;reg: tregister;const ref: treference; shuffle : pmmshuffle); virtual;
  251. procedure a_opmm_loc_reg_reg(list: TAsmList;Op : TOpCG;size : tcgsize;const loc : tlocation;src,dst : tregister;shuffle : pmmshuffle); virtual;
  252. procedure a_opmm_reg_reg_reg(list: TAsmList; Op: TOpCG; size : tcgsize;src1,src2,dst: tregister;shuffle : pmmshuffle); virtual;
  253. procedure a_opmm_ref_reg_reg(list: TAsmList; Op: TOpCG; size : tcgsize;const ref: treference; src,dst: tregister;shuffle : pmmshuffle); virtual;
  254. procedure a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize : tcgsize; intreg, mmreg: tregister; shuffle: pmmshuffle); virtual;
  255. procedure a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize : tcgsize; mmreg, intreg: tregister; shuffle : pmmshuffle); virtual;
  256. { basic arithmetic operations }
  257. { note: for operators which require only one argument (not, neg), use }
  258. { the op_reg_reg, op_reg_ref or op_reg_loc methods and keep in mind }
  259. { that in this case the *second* operand is used as both source and }
  260. { destination (JM) }
  261. procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); virtual; abstract;
  262. procedure a_op_const_ref(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; const ref: TReference); virtual;
  263. procedure a_op_const_loc(list : TAsmList; Op: TOpCG; a: tcgint; const loc: tlocation);
  264. procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; reg1, reg2: TRegister); virtual; abstract;
  265. procedure a_op_reg_ref(list : TAsmList; Op: TOpCG; size: TCGSize; reg: TRegister; const ref: TReference); virtual;
  266. procedure a_op_ref_reg(list : TAsmList; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister); virtual;
  267. procedure a_op_reg_loc(list : TAsmList; Op: TOpCG; reg: tregister; const loc: tlocation);
  268. procedure a_op_loc_reg(list : TAsmList; Op: TOpCG; size: TCGSize; const loc: tlocation; reg: tregister);
  269. procedure a_op_ref_loc(list : TAsmList; Op: TOpCG; const ref: TReference; const loc: tlocation);
  270. { trinary operations for processors that support them, 'emulated' }
  271. { on others. None with "ref" arguments since I don't think there }
  272. { are any processors that support it (JM) }
  273. procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister); virtual;
  274. procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister); virtual;
  275. procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister;setflags : boolean;var ovloc : tlocation); virtual;
  276. procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation); virtual;
  277. { comparison operations }
  278. procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister;
  279. l : tasmlabel); virtual;
  280. procedure a_cmp_const_ref_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;const ref : treference;
  281. l : tasmlabel); virtual;
  282. procedure a_cmp_const_loc_label(list: TAsmList; size: tcgsize;cmp_op: topcmp; a: tcgint; const loc: tlocation;
  283. l : tasmlabel);
  284. procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); virtual; abstract;
  285. procedure a_cmp_ref_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp; const ref: treference; reg : tregister; l : tasmlabel); virtual;
  286. procedure a_cmp_reg_ref_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg : tregister; const ref: treference; l : tasmlabel); virtual;
  287. procedure a_cmp_loc_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp; const loc: tlocation; reg : tregister; l : tasmlabel);
  288. procedure a_cmp_reg_loc_label(list : TAsmList;size : tcgsize;cmp_op : topcmp; reg: tregister; const loc: tlocation; l : tasmlabel);
  289. procedure a_cmp_ref_loc_label(list: TAsmList; size: tcgsize;cmp_op: topcmp; const ref: treference; const loc: tlocation;
  290. l : tasmlabel);
  291. procedure a_jmp_name(list : TAsmList;const s : string); virtual; abstract;
  292. procedure a_jmp_always(list : TAsmList;l: tasmlabel); virtual; abstract;
  293. {$ifdef cpuflags}
  294. procedure a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); virtual; abstract;
  295. {# Depending on the value to check in the flags, either sets the register reg to one (if the flag is set)
  296. or zero (if the flag is cleared). The size parameter indicates the destination size register.
  297. }
  298. procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: tresflags; reg: TRegister); virtual; abstract;
  299. procedure g_flags2ref(list: TAsmList; size: TCgSize; const f: tresflags; const ref:TReference); virtual;
  300. {$endif cpuflags}
  301. {
  302. This routine tries to optimize the op_const_reg/ref opcode, and should be
  303. called at the start of a_op_const_reg/ref. It returns the actual opcode
  304. to emit, and the constant value to emit. This function can opcode OP_NONE to
  305. remove the opcode and OP_MOVE to replace it with a simple load
  306. @param(size Size of the operand in constant)
  307. @param(op The opcode to emit, returns the opcode which must be emitted)
  308. @param(a The constant which should be emitted, returns the constant which must
  309. be emitted)
  310. }
  311. procedure optimize_op_const(size: TCGSize; var op: topcg; var a : tcgint);virtual;
  312. {# This should emit the opcode to copy len bytes from the source
  313. to destination.
  314. It must be overridden for each new target processor.
  315. @param(source Source reference of copy)
  316. @param(dest Destination reference of copy)
  317. }
  318. procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);virtual; abstract;
  319. {# This should emit the opcode to copy len bytes from the an unaligned source
  320. to destination.
  321. It must be overridden for each new target processor.
  322. @param(source Source reference of copy)
  323. @param(dest Destination reference of copy)
  324. }
  325. procedure g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : tcgint);virtual;
  326. {# Generates overflow checking code for a node }
  327. procedure g_overflowcheck(list: TAsmList; const Loc:tlocation; def:tdef); virtual;abstract;
  328. procedure g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);virtual;
  329. {# Emits instructions when compilation is done in profile
  330. mode (this is set as a command line option). The default
  331. behavior does nothing, should be overridden as required.
  332. }
  333. procedure g_profilecode(list : TAsmList);virtual;
  334. {# Emits instruction for allocating @var(size) bytes at the stackpointer
  335. @param(size Number of bytes to allocate)
  336. }
  337. procedure g_stackpointer_alloc(list : TAsmList;size : longint);virtual;
  338. {# Emits instruction for allocating the locals in entry
  339. code of a routine. This is one of the first
  340. routine called in @var(genentrycode).
  341. @param(localsize Number of bytes to allocate as locals)
  342. }
  343. procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);virtual; abstract;
  344. {# Emits instructions for returning from a subroutine.
  345. Should also restore the framepointer and stack.
  346. @param(parasize Number of bytes of parameters to deallocate from stack)
  347. }
  348. procedure g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);virtual;abstract;
  349. {# This routine is called when generating the code for the entry point
  350. of a routine. It should save all registers which are not used in this
  351. routine, and which should be declared as saved in the std_saved_registers
  352. set.
  353. This routine is mainly used when linking to code which is generated
  354. by ABI-compliant compilers (like GCC), to make sure that the reserved
  355. registers of that ABI are not clobbered.
  356. @param(usedinproc Registers which are used in the code of this routine)
  357. }
  358. procedure g_save_registers(list:TAsmList);virtual;
  359. {# This routine is called when generating the code for the exit point
  360. of a routine. It should restore all registers which were previously
  361. saved in @var(g_save_standard_registers).
  362. @param(usedinproc Registers which are used in the code of this routine)
  363. }
  364. procedure g_restore_registers(list:TAsmList);virtual;
  365. procedure g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);virtual;
  366. { initialize the pic/got register }
  367. procedure g_maybe_got_init(list: TAsmList); virtual;
  368. { initialize the tls register if needed }
  369. procedure g_maybe_tls_init(list : TAsmList); virtual;
  370. { allocallcpuregisters, a_call_name, deallocallcpuregisters sequence }
  371. procedure g_call(list: TAsmList; const s: string);
  372. { Generate code to exit an unwind-protected region. The default implementation
  373. produces a simple jump to destination label. }
  374. procedure g_local_unwind(list: TAsmList; l: TAsmLabel);virtual;
  375. { Generate code for integer division by constant,
  376. generic version is suitable for 3-address CPUs }
  377. procedure g_div_const_reg_reg(list:tasmlist; size: TCgSize; a: tcgint; src,dst: tregister); virtual;
  378. { some CPUs do not support hardware fpu exceptions, this procedure is called after instructions which
  379. might set FPU exception related flags, so it has to check these flags if needed and throw an exeception }
  380. procedure g_check_for_fpu_exception(list: TAsmList); virtual;
  381. protected
  382. function g_indirect_sym_load(list:TAsmList;const symname: string; const flags: tindsymflags): tregister;virtual;
  383. end;
  384. {$ifdef cpu64bitalu}
  385. { This class implements an abstract code generator class
  386. for 128 Bit operations, it applies currently only to 64 Bit CPUs and supports only simple operations
  387. }
  388. tcg128 = class
  389. procedure a_load128_reg_reg(list : TAsmList;regsrc,regdst : tregister128);virtual;
  390. procedure a_load128_reg_ref(list : TAsmList;reg : tregister128;const ref : treference);virtual;
  391. procedure a_load128_ref_reg(list : TAsmList;const ref : treference;reg : tregister128);virtual;
  392. procedure a_load128_loc_ref(list : TAsmList;const l : tlocation;const ref : treference);virtual;
  393. procedure a_load128_reg_loc(list : TAsmList;reg : tregister128;const l : tlocation);virtual;
  394. procedure a_load128_const_reg(list : TAsmList;valuelo,valuehi : int64;reg : tregister128);virtual;
  395. procedure a_load128_loc_cgpara(list : TAsmList;const l : tlocation;const paraloc : TCGPara);virtual;
  396. procedure a_load128_ref_cgpara(list: TAsmList; const r: treference;const paraloc: tcgpara);
  397. procedure a_load128_reg_cgpara(list: TAsmList; reg: tregister128;const paraloc: tcgpara);
  398. end;
  399. { Creates a tregister128 record from 2 64 Bit registers. }
  400. function joinreg128(reglo,reghi : tregister) : tregister128;
  401. {$else cpu64bitalu}
  402. {# @abstract(Abstract code generator for 64 Bit operations)
  403. This class implements an abstract code generator class
  404. for 64 Bit operations.
  405. }
  406. tcg64 = class
  407. procedure a_load64_const_ref(list : TAsmList;value : int64;const ref : treference);virtual;abstract;
  408. procedure a_load64_reg_ref(list : TAsmList;reg : tregister64;const ref : treference);virtual;abstract;
  409. procedure a_load64_ref_reg(list : TAsmList;const ref : treference;reg : tregister64);virtual;abstract;
  410. procedure a_load64_reg_reg(list : TAsmList;regsrc,regdst : tregister64);virtual;abstract;
  411. procedure a_load64_const_reg(list : TAsmList;value : int64;reg : tregister64);virtual;abstract;
  412. procedure a_load64_loc_reg(list : TAsmList;const l : tlocation;reg : tregister64);virtual;abstract;
  413. procedure a_load64_loc_ref(list : TAsmList;const l : tlocation;const ref : treference);virtual;abstract;
  414. procedure a_load64_const_loc(list : TAsmList;value : int64;const l : tlocation);virtual;abstract;
  415. procedure a_load64_reg_loc(list : TAsmList;reg : tregister64;const l : tlocation);virtual;abstract;
  416. procedure a_load64_subsetref_reg(list : TAsmList; const sref: tsubsetreference; destreg: tregister64);virtual;abstract;
  417. procedure a_load64_reg_subsetref(list : TAsmList; fromreg: tregister64; const sref: tsubsetreference);virtual;abstract;
  418. procedure a_load64_const_subsetref(list: TAsmlist; a: int64; const sref: tsubsetreference);virtual;abstract;
  419. procedure a_load64_ref_subsetref(list : TAsmList; const fromref: treference; const sref: tsubsetreference);virtual;abstract;
  420. procedure a_load64_subsetref_subsetref(list: TAsmlist; const fromsref, tosref: tsubsetreference); virtual;abstract;
  421. procedure a_load64_subsetref_ref(list : TAsmList; const sref: tsubsetreference; const destref: treference); virtual;abstract;
  422. procedure a_load64_loc_subsetref(list : TAsmList; const l: tlocation; const sref : tsubsetreference);
  423. procedure a_load64_subsetref_loc(list: TAsmlist; const sref: tsubsetreference; const l: tlocation);
  424. procedure a_load64high_reg_ref(list : TAsmList;reg : tregister;const ref : treference);virtual;abstract;
  425. procedure a_load64low_reg_ref(list : TAsmList;reg : tregister;const ref : treference);virtual;abstract;
  426. procedure a_load64high_ref_reg(list : TAsmList;const ref : treference;reg : tregister);virtual;abstract;
  427. procedure a_load64low_ref_reg(list : TAsmList;const ref : treference;reg : tregister);virtual;abstract;
  428. procedure a_load64high_loc_reg(list : TAsmList;const l : tlocation;reg : tregister);virtual;abstract;
  429. procedure a_load64low_loc_reg(list : TAsmList;const l : tlocation;reg : tregister);virtual;abstract;
  430. procedure a_op64_ref_reg(list : TAsmList;op:TOpCG;size : tcgsize;const ref : treference;reg : tregister64);virtual;abstract;
  431. procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);virtual;abstract;
  432. procedure a_op64_reg_ref(list : TAsmList;op:TOpCG;size : tcgsize;regsrc : tregister64;const ref : treference);virtual;abstract;
  433. procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;regdst : tregister64);virtual;abstract;
  434. procedure a_op64_const_ref(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;const ref : treference);virtual;abstract;
  435. procedure a_op64_const_loc(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;const l: tlocation);virtual;abstract;
  436. procedure a_op64_reg_loc(list : TAsmList;op:TOpCG;size : tcgsize;reg : tregister64;const l : tlocation);virtual;abstract;
  437. procedure a_op64_loc_reg(list : TAsmList;op:TOpCG;size : tcgsize;const l : tlocation;reg64 : tregister64);virtual;abstract;
  438. procedure a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);virtual;
  439. procedure a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);virtual;
  440. procedure a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);virtual;
  441. procedure a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);virtual;
  442. procedure a_op64_const_subsetref(list : TAsmList; Op : TOpCG; size : TCGSize; a : int64; const sref: tsubsetreference);
  443. procedure a_op64_reg_subsetref(list : TAsmList; Op : TOpCG; size : TCGSize; reg: tregister64; const sref: tsubsetreference);
  444. procedure a_op64_ref_subsetref(list : TAsmList; Op : TOpCG; size : TCGSize; const ref: treference; const sref: tsubsetreference);
  445. procedure a_op64_subsetref_subsetref(list : TAsmList; Op : TOpCG; size : TCGSize; const ssref,dsref: tsubsetreference);
  446. procedure a_load64_reg_cgpara(list : TAsmList;reg64 : tregister64;const loc : TCGPara);virtual;abstract;
  447. procedure a_load64_const_cgpara(list : TAsmList;value : int64;const loc : TCGPara);virtual;abstract;
  448. procedure a_load64_ref_cgpara(list : TAsmList;const r : treference;const loc : TCGPara);virtual;abstract;
  449. procedure a_load64_loc_cgpara(list : TAsmList;const l : tlocation;const loc : TCGPara);virtual;abstract;
  450. procedure a_loadmm_intreg64_reg(list: TAsmList; mmsize: tcgsize; intreg: tregister64; mmreg: tregister); virtual;abstract;
  451. procedure a_loadmm_reg_intreg64(list: TAsmList; mmsize: tcgsize; mmreg: tregister; intreg: tregister64); virtual;abstract;
  452. {
  453. This routine tries to optimize the const_reg opcode, and should be
  454. called at the start of a_op64_const_reg. It returns the actual opcode
  455. to emit, and the constant value to emit. If this routine returns
  456. TRUE, @var(no) instruction should be emitted (.eg : imul reg by 1 )
  457. @param(op The opcode to emit, returns the opcode which must be emitted)
  458. @param(a The constant which should be emitted, returns the constant which must
  459. be emitted)
  460. @param(reg The register to emit the opcode with, returns the register with
  461. which the opcode will be emitted)
  462. }
  463. function optimize64_op_const_reg(list: TAsmList; var op: topcg; var a : int64; var reg: tregister64): boolean;virtual;abstract;
  464. { override to catch 64bit rangechecks }
  465. procedure g_rangecheck64(list: TAsmList; const l:tlocation; fromdef,todef: tdef);virtual;abstract;
  466. end;
  467. { Creates a tregister64 record from 2 32 Bit registers. }
  468. function joinreg64(reglo,reghi : tregister) : tregister64;
  469. {$endif cpu64bitalu}
  470. var
  471. { Main code generator class }
  472. cg : tcg;
  473. {$ifdef cpu64bitalu}
  474. { Code generator class for all operations working with 128-Bit operands }
  475. cg128 : tcg128;
  476. {$else cpu64bitalu}
  477. { Code generator class for all operations working with 64-Bit operands }
  478. cg64 : tcg64;
  479. {$endif cpu64bitalu}
  480. function asmsym2indsymflags(sym: TAsmSymbol): tindsymflags;
  481. procedure destroy_codegen;
  482. implementation
  483. uses
  484. globals,systems,
  485. verbose,paramgr,symsym,
  486. tgobj,cutils,procinfo;
  487. {*****************************************************************************
  488. basic functionallity
  489. ******************************************************************************}
  490. constructor tcg.create;
  491. begin
  492. end;
  493. {*****************************************************************************
  494. register allocation
  495. ******************************************************************************}
  496. procedure tcg.init_register_allocators;
  497. begin
  498. {$if defined(cpu8bitalu) or defined(cpu16bitalu)}
  499. fillchar(has_next_reg,sizeof(has_next_reg),0);
  500. {$endif cpu8bitalu or cpu16bitalu}
  501. fillchar(rg,sizeof(rg),0);
  502. add_reg_instruction_hook:=@add_reg_instruction;
  503. executionweight:=100;
  504. end;
  505. procedure tcg.done_register_allocators;
  506. begin
  507. { Safety }
  508. fillchar(rg,sizeof(rg),0);
  509. add_reg_instruction_hook:=nil;
  510. {$if defined(cpu8bitalu) or defined(cpu16bitalu)}
  511. fillchar(has_next_reg,sizeof(has_next_reg),0);
  512. {$endif cpu8bitalu or cpu16bitalu}
  513. end;
  514. {$ifdef flowgraph}
  515. procedure Tcg.init_flowgraph;
  516. begin
  517. aktflownode:=0;
  518. end;
  519. procedure Tcg.done_flowgraph;
  520. begin
  521. end;
  522. {$endif}
  523. function tcg.getintregister(list:TAsmList;size:Tcgsize):Tregister;
  524. {$ifdef cpu8bitalu}
  525. var
  526. tmp1,tmp2,tmp3 : TRegister;
  527. {$endif cpu8bitalu}
  528. begin
  529. if not assigned(rg[R_INTREGISTER]) then
  530. internalerror(200312122);
  531. {$if defined(cpu8bitalu)}
  532. case size of
  533. OS_8,OS_S8:
  534. Result:=rg[R_INTREGISTER].getregister(list,cgsize2subreg(R_INTREGISTER,size));
  535. OS_16,OS_S16:
  536. begin
  537. Result:=getintregister(list, OS_8);
  538. has_next_reg[getsupreg(Result)]:=true;
  539. { ensure that the high register can be retrieved by
  540. GetNextReg
  541. }
  542. if getintregister(list, OS_8)<>GetNextReg(Result) then
  543. internalerror(2011021331);
  544. end;
  545. OS_32,OS_S32:
  546. begin
  547. Result:=getintregister(list, OS_8);
  548. has_next_reg[getsupreg(Result)]:=true;
  549. tmp1:=getintregister(list, OS_8);
  550. has_next_reg[getsupreg(tmp1)]:=true;
  551. { ensure that the high register can be retrieved by
  552. GetNextReg
  553. }
  554. if tmp1<>GetNextReg(Result) then
  555. internalerror(2011021332);
  556. tmp2:=getintregister(list, OS_8);
  557. has_next_reg[getsupreg(tmp2)]:=true;
  558. { ensure that the upper register can be retrieved by
  559. GetNextReg
  560. }
  561. if tmp2<>GetNextReg(tmp1) then
  562. internalerror(2011021333);
  563. tmp3:=getintregister(list, OS_8);
  564. { ensure that the upper register can be retrieved by
  565. GetNextReg
  566. }
  567. if tmp3<>GetNextReg(tmp2) then
  568. internalerror(2011021334);
  569. end;
  570. else
  571. internalerror(2011021330);
  572. end;
  573. {$elseif defined(cpu16bitalu)}
  574. case size of
  575. OS_8, OS_S8,
  576. OS_16, OS_S16:
  577. Result:=rg[R_INTREGISTER].getregister(list,cgsize2subreg(R_INTREGISTER,size));
  578. OS_32, OS_S32:
  579. begin
  580. Result:=getintregister(list, OS_16);
  581. has_next_reg[getsupreg(Result)]:=true;
  582. { ensure that the high register can be retrieved by
  583. GetNextReg
  584. }
  585. if getintregister(list, OS_16)<>GetNextReg(Result) then
  586. internalerror(2013030202);
  587. end;
  588. else
  589. internalerror(2013030201);
  590. end;
  591. {$elseif defined(cpu32bitalu) or defined(cpu64bitalu)}
  592. result:=rg[R_INTREGISTER].getregister(list,cgsize2subreg(R_INTREGISTER,size));
  593. {$endif}
  594. end;
  595. function tcg.getfpuregister(list:TAsmList;size:Tcgsize):Tregister;
  596. begin
  597. if not assigned(rg[R_FPUREGISTER]) then
  598. internalerror(200312123);
  599. result:=rg[R_FPUREGISTER].getregister(list,cgsize2subreg(R_FPUREGISTER,size));
  600. end;
  601. function tcg.getmmregister(list:TAsmList;size:Tcgsize):Tregister;
  602. begin
  603. if not assigned(rg[R_MMREGISTER]) then
  604. internalerror(2003121214);
  605. result:=rg[R_MMREGISTER].getregister(list,cgsize2subreg(R_MMREGISTER,size));
  606. end;
  607. function tcg.getaddressregister(list:TAsmList):Tregister;
  608. begin
  609. if assigned(rg[R_ADDRESSREGISTER]) then
  610. result:=rg[R_ADDRESSREGISTER].getregister(list,R_SUBWHOLE)
  611. else
  612. begin
  613. if not assigned(rg[R_INTREGISTER]) then
  614. internalerror(200312121);
  615. result:=rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
  616. end;
  617. end;
  618. function tcg.gettempregister(list: TAsmList): Tregister;
  619. begin
  620. result:=rg[R_TEMPREGISTER].getregister(list,R_SUBWHOLE);
  621. end;
  622. {$if defined(cpu8bitalu) or defined(cpu16bitalu)}
  623. function tcg.GetNextReg(const r: TRegister): TRegister;
  624. begin
  625. {$ifndef AVR}
  626. { the AVR code generator depends on the fact that it can do GetNextReg also on physical registers }
  627. if getsupreg(r)<first_int_imreg then
  628. internalerror(2013051401);
  629. if not has_next_reg[getsupreg(r)] then
  630. internalerror(2017091103);
  631. {$else AVR}
  632. if (getsupreg(r)>=first_int_imreg) and not(has_next_reg[getsupreg(r)]) then
  633. internalerror(2017091103);
  634. {$endif AVR}
  635. if getregtype(r)<>R_INTREGISTER then
  636. internalerror(2017091101);
  637. if getsubreg(r)<>R_SUBWHOLE then
  638. internalerror(2017091102);
  639. result:=TRegister(longint(r)+1);
  640. end;
  641. {$endif cpu8bitalu or cpu16bitalu}
  642. function Tcg.makeregsize(list:TAsmList;reg:Tregister;size:Tcgsize):Tregister;
  643. var
  644. subreg:Tsubregister;
  645. begin
  646. subreg:=cgsize2subreg(getregtype(reg),size);
  647. result:=reg;
  648. setsubreg(result,subreg);
  649. { notify RA }
  650. if result<>reg then
  651. list.concat(tai_regalloc.resize(result));
  652. end;
  653. procedure tcg.getcpuregister(list:TAsmList;r:Tregister);
  654. begin
  655. if not assigned(rg[getregtype(r)]) then
  656. internalerror(200312125);
  657. rg[getregtype(r)].getcpuregister(list,r);
  658. end;
  659. procedure tcg.ungetcpuregister(list:TAsmList;r:Tregister);
  660. begin
  661. if not assigned(rg[getregtype(r)]) then
  662. internalerror(200312126);
  663. rg[getregtype(r)].ungetcpuregister(list,r);
  664. end;
  665. procedure tcg.alloccpuregisters(list:TAsmList;rt:Tregistertype;const r:Tcpuregisterset);
  666. begin
  667. if assigned(rg[rt]) then
  668. rg[rt].alloccpuregisters(list,r)
  669. else
  670. internalerror(200310092);
  671. end;
  672. procedure tcg.allocallcpuregisters(list:TAsmList);
  673. begin
  674. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  675. if uses_registers(R_ADDRESSREGISTER) then
  676. alloccpuregisters(list,R_ADDRESSREGISTER,paramanager.get_volatile_registers_address(pocall_default));
  677. {$if not(defined(i386)) and not(defined(i8086)) and not(defined(avr))}
  678. if uses_registers(R_FPUREGISTER) then
  679. alloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  680. {$ifdef cpumm}
  681. if uses_registers(R_MMREGISTER) then
  682. alloccpuregisters(list,R_MMREGISTER,paramanager.get_volatile_registers_mm(pocall_default));
  683. {$endif cpumm}
  684. {$endif not(defined(i386)) and not(defined(i8086)) and not(defined(avr))}
  685. end;
  686. procedure tcg.dealloccpuregisters(list:TAsmList;rt:Tregistertype;const r:Tcpuregisterset);
  687. begin
  688. if assigned(rg[rt]) then
  689. rg[rt].dealloccpuregisters(list,r)
  690. else
  691. internalerror(200310093);
  692. end;
  693. procedure tcg.deallocallcpuregisters(list:TAsmList);
  694. begin
  695. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  696. if uses_registers(R_ADDRESSREGISTER) then
  697. dealloccpuregisters(list,R_ADDRESSREGISTER,paramanager.get_volatile_registers_address(pocall_default));
  698. {$if not(defined(i386)) and not(defined(i8086)) and not(defined(avr))}
  699. if uses_registers(R_FPUREGISTER) then
  700. dealloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  701. {$ifdef cpumm}
  702. if uses_registers(R_MMREGISTER) then
  703. dealloccpuregisters(list,R_MMREGISTER,paramanager.get_volatile_registers_mm(pocall_default));
  704. {$endif cpumm}
  705. {$endif not(defined(i386)) and not(defined(i8086)) and not(defined(avr))}
  706. end;
  707. function tcg.uses_registers(rt:Tregistertype):boolean;
  708. begin
  709. if assigned(rg[rt]) then
  710. result:=rg[rt].uses_registers
  711. else
  712. result:=false;
  713. end;
  714. procedure tcg.add_reg_instruction(instr:Tai;r:tregister);
  715. var
  716. rt : tregistertype;
  717. begin
  718. rt:=getregtype(r);
  719. { Only add it when a register allocator is configured.
  720. No IE can be generated, because the VMT is written
  721. without a valid rg[] }
  722. if assigned(rg[rt]) then
  723. rg[rt].add_reg_instruction(instr,r,executionweight);
  724. end;
  725. procedure tcg.add_move_instruction(instr:Taicpu);
  726. var
  727. rt : tregistertype;
  728. begin
  729. rt:=getregtype(instr.oper[O_MOV_SOURCE]^.reg);
  730. if assigned(rg[rt]) then
  731. rg[rt].add_move_instruction(instr)
  732. else
  733. internalerror(200310095);
  734. end;
  735. procedure tcg.set_regalloc_live_range_direction(dir: TRADirection);
  736. var
  737. rt : tregistertype;
  738. begin
  739. for rt:=low(rg) to high(rg) do
  740. begin
  741. if assigned(rg[rt]) then
  742. rg[rt].live_range_direction:=dir;
  743. end;
  744. end;
  745. procedure tcg.do_register_allocation(list:TAsmList;headertai:tai);
  746. var
  747. rt : tregistertype;
  748. begin
  749. for rt:=R_FPUREGISTER to R_SPECIALREGISTER do
  750. begin
  751. if assigned(rg[rt]) then
  752. rg[rt].do_register_allocation(list,headertai);
  753. end;
  754. { running the other register allocator passes could require addition int/addr. registers
  755. when spilling so run int/addr register allocation at the end }
  756. if assigned(rg[R_INTREGISTER]) then
  757. rg[R_INTREGISTER].do_register_allocation(list,headertai);
  758. if assigned(rg[R_ADDRESSREGISTER]) then
  759. rg[R_ADDRESSREGISTER].do_register_allocation(list,headertai);
  760. end;
  761. procedure tcg.translate_register(var reg : tregister);
  762. var
  763. rt: tregistertype;
  764. begin
  765. { Getting here without assigned rg is possible for an "assembler nostackframe"
  766. function returning x87 float, compiler tries to translate NR_ST which is used for
  767. result. }
  768. rt:=getregtype(reg);
  769. if assigned(rg[rt]) then
  770. rg[rt].translate_register(reg);
  771. end;
  772. procedure tcg.a_reg_alloc(list : TAsmList;r : tregister);
  773. begin
  774. list.concat(tai_regalloc.alloc(r,nil));
  775. end;
  776. procedure tcg.a_reg_dealloc(list : TAsmList;r : tregister);
  777. begin
  778. if (r<>NR_NO) then
  779. list.concat(tai_regalloc.dealloc(r,nil));
  780. end;
  781. procedure tcg.a_reg_sync(list : TAsmList;r : tregister);
  782. var
  783. instr : tai;
  784. begin
  785. instr:=tai_regalloc.sync(r);
  786. list.concat(instr);
  787. add_reg_instruction(instr,r);
  788. end;
  789. procedure tcg.a_label(list : TAsmList;l : tasmlabel);
  790. begin
  791. list.concat(tai_label.create(l));
  792. end;
  793. {*****************************************************************************
  794. for better code generation these methods should be overridden
  795. ******************************************************************************}
  796. procedure tcg.a_load_reg_cgpara(list : TAsmList;size : tcgsize;r : tregister;const cgpara : TCGPara);
  797. var
  798. ref : treference;
  799. tmpreg : tregister;
  800. begin
  801. if assigned(cgpara.location^.next) then
  802. begin
  803. tg.gethltemp(list,cgpara.def,cgpara.def.size,tt_persistent,ref);
  804. a_load_reg_ref(list,size,size,r,ref);
  805. a_load_ref_cgpara(list,size,ref,cgpara);
  806. tg.ungettemp(list,ref);
  807. exit;
  808. end;
  809. paramanager.alloccgpara(list,cgpara);
  810. if cgpara.location^.shiftval<0 then
  811. begin
  812. tmpreg:=getintregister(list,cgpara.location^.size);
  813. a_op_const_reg_reg(list,OP_SHL,cgpara.location^.size,-cgpara.location^.shiftval,r,tmpreg);
  814. r:=tmpreg;
  815. end;
  816. case cgpara.location^.loc of
  817. LOC_REGISTER,LOC_CREGISTER:
  818. a_load_reg_reg(list,size,cgpara.location^.size,r,cgpara.location^.register);
  819. LOC_REFERENCE,LOC_CREFERENCE:
  820. begin
  821. reference_reset_base(ref,cgpara.location^.reference.index,cgpara.location^.reference.offset,ctempposinvalid,cgpara.alignment,[]);
  822. a_load_reg_ref(list,size,cgpara.location^.size,r,ref);
  823. end;
  824. LOC_MMREGISTER,LOC_CMMREGISTER:
  825. a_loadmm_intreg_reg(list,size,cgpara.location^.size,r,cgpara.location^.register,mms_movescalar);
  826. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  827. begin
  828. tg.GetTemp(list,TCGSize2Size[size],TCGSize2Size[size],tt_normal,ref);
  829. a_load_reg_ref(list,size,size,r,ref);
  830. a_loadfpu_ref_cgpara(list,cgpara.location^.size,ref,cgpara);
  831. tg.Ungettemp(list,ref);
  832. end
  833. else
  834. internalerror(2002071004);
  835. end;
  836. end;
  837. procedure tcg.a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const cgpara : TCGPara);
  838. var
  839. ref : treference;
  840. begin
  841. cgpara.check_simple_location;
  842. paramanager.alloccgpara(list,cgpara);
  843. if cgpara.location^.shiftval<0 then
  844. a:=a shl -cgpara.location^.shiftval;
  845. case cgpara.location^.loc of
  846. LOC_REGISTER,LOC_CREGISTER:
  847. a_load_const_reg(list,cgpara.location^.size,a,cgpara.location^.register);
  848. LOC_REFERENCE,LOC_CREFERENCE:
  849. begin
  850. reference_reset_base(ref,cgpara.location^.reference.index,cgpara.location^.reference.offset,ctempposinvalid,cgpara.alignment,[]);
  851. a_load_const_ref(list,cgpara.location^.size,a,ref);
  852. end
  853. else
  854. internalerror(2010053109);
  855. end;
  856. end;
  857. procedure tcg.a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : TCGPara);
  858. var
  859. tmpref, ref: treference;
  860. tmpreg: tregister;
  861. location: pcgparalocation;
  862. orgsizeleft,
  863. sizeleft: tcgint;
  864. reghasvalue: boolean;
  865. begin
  866. location:=cgpara.location;
  867. tmpref:=r;
  868. sizeleft:=cgpara.intsize;
  869. while assigned(location) do
  870. begin
  871. paramanager.allocparaloc(list,location);
  872. case location^.loc of
  873. LOC_REGISTER,LOC_CREGISTER:
  874. begin
  875. { Parameter locations are often allocated in multiples of
  876. entire registers. If a parameter only occupies a part of
  877. such a register (e.g. a 16 bit int on a 32 bit
  878. architecture), the size of this parameter can only be
  879. determined by looking at the "size" parameter of this
  880. method -> if the size parameter is <= sizeof(aint), then
  881. we check that there is only one parameter location and
  882. then use this "size" to load the value into the parameter
  883. location }
  884. if (size<>OS_NO) and
  885. (tcgsize2size[size]<=sizeof(aint)) then
  886. begin
  887. cgpara.check_simple_location;
  888. a_load_ref_reg(list,size,location^.size,tmpref,location^.register);
  889. if location^.shiftval<0 then
  890. a_op_const_reg(list,OP_SHL,location^.size,-location^.shiftval,location^.register);
  891. end
  892. { there's a lot more data left, and the current paraloc's
  893. register is entirely filled with part of that data }
  894. else if (sizeleft>sizeof(aint)) then
  895. begin
  896. a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
  897. end
  898. { we're at the end of the data, and it can be loaded into
  899. the current location's register with a single regular
  900. load }
  901. else if sizeleft in [1,2,4,8] then
  902. begin
  903. a_load_ref_reg(list,int_cgsize(sizeleft),location^.size,tmpref,location^.register);
  904. if location^.shiftval<0 then
  905. a_op_const_reg(list,OP_SHL,location^.size,-location^.shiftval,location^.register);
  906. end
  907. { we're at the end of the data, and we need multiple loads
  908. to get it in the register because it's an irregular size }
  909. else
  910. begin
  911. { should be the last part }
  912. if assigned(location^.next) then
  913. internalerror(2010052907);
  914. { load the value piecewise to get it into the register }
  915. orgsizeleft:=sizeleft;
  916. reghasvalue:=false;
  917. {$ifdef cpu64bitalu}
  918. if sizeleft>=4 then
  919. begin
  920. a_load_ref_reg(list,OS_32,location^.size,tmpref,location^.register);
  921. dec(sizeleft,4);
  922. if target_info.endian=endian_big then
  923. a_op_const_reg(list,OP_SHL,location^.size,sizeleft*8,location^.register);
  924. inc(tmpref.offset,4);
  925. reghasvalue:=true;
  926. end;
  927. {$endif cpu64bitalu}
  928. if sizeleft>=2 then
  929. begin
  930. tmpreg:=getintregister(list,location^.size);
  931. a_load_ref_reg(list,OS_16,location^.size,tmpref,tmpreg);
  932. dec(sizeleft,2);
  933. if reghasvalue then
  934. begin
  935. if target_info.endian=endian_big then
  936. a_op_const_reg(list,OP_SHL,location^.size,sizeleft*8,tmpreg)
  937. else
  938. a_op_const_reg(list,OP_SHL,location^.size,(orgsizeleft-(sizeleft+2))*8,tmpreg);
  939. a_op_reg_reg(list,OP_OR,location^.size,tmpreg,location^.register);
  940. end
  941. else
  942. begin
  943. if target_info.endian=endian_big then
  944. a_op_const_reg_reg(list,OP_SHL,location^.size,sizeleft*8,tmpreg,location^.register)
  945. else
  946. a_load_reg_reg(list,location^.size,location^.size,tmpreg,location^.register);
  947. end;
  948. inc(tmpref.offset,2);
  949. reghasvalue:=true;
  950. end;
  951. if sizeleft=1 then
  952. begin
  953. tmpreg:=getintregister(list,location^.size);
  954. a_load_ref_reg(list,OS_8,location^.size,tmpref,tmpreg);
  955. dec(sizeleft,1);
  956. if reghasvalue then
  957. begin
  958. if target_info.endian=endian_little then
  959. a_op_const_reg(list,OP_SHL,location^.size,(orgsizeleft-(sizeleft+1))*8,tmpreg);
  960. a_op_reg_reg(list,OP_OR,location^.size,tmpreg,location^.register)
  961. end
  962. else
  963. a_load_reg_reg(list,location^.size,location^.size,tmpreg,location^.register);
  964. inc(tmpref.offset);
  965. end;
  966. if location^.shiftval<0 then
  967. a_op_const_reg(list,OP_SHL,location^.size,-location^.shiftval,location^.register);
  968. { the loop will already adjust the offset and sizeleft }
  969. dec(tmpref.offset,orgsizeleft);
  970. sizeleft:=orgsizeleft;
  971. end;
  972. end;
  973. LOC_REFERENCE,LOC_CREFERENCE:
  974. begin
  975. if assigned(location^.next) then
  976. internalerror(2010052906);
  977. reference_reset_base(ref,location^.reference.index,location^.reference.offset,ctempposinvalid,newalignment(cgpara.alignment,cgpara.intsize-sizeleft),[]);
  978. if (size <> OS_NO) and
  979. (tcgsize2size[size] <= sizeof(aint)) then
  980. a_load_ref_ref(list,size,location^.size,tmpref,ref)
  981. else
  982. { use concatcopy, because the parameter can be larger than }
  983. { what the OS_* constants can handle }
  984. g_concatcopy(list,tmpref,ref,sizeleft);
  985. end;
  986. LOC_MMREGISTER,LOC_CMMREGISTER:
  987. begin
  988. case location^.size of
  989. OS_F32,
  990. OS_F64,
  991. OS_F128:
  992. a_loadmm_ref_reg(list,location^.size,location^.size,tmpref,location^.register,mms_movescalar);
  993. OS_M8..OS_M128,
  994. OS_MS8..OS_MS128:
  995. a_loadmm_ref_reg(list,location^.size,location^.size,tmpref,location^.register,nil);
  996. else
  997. internalerror(2010053101);
  998. end;
  999. end
  1000. else
  1001. internalerror(2010053111);
  1002. end;
  1003. inc(tmpref.offset,tcgsize2size[location^.size]);
  1004. dec(sizeleft,tcgsize2size[location^.size]);
  1005. location:=location^.next;
  1006. end;
  1007. end;
  1008. procedure tcg.a_load_loc_cgpara(list : TAsmList;const l:tlocation;const cgpara : TCGPara);
  1009. begin
  1010. case l.loc of
  1011. LOC_REGISTER,
  1012. LOC_CREGISTER :
  1013. a_load_reg_cgpara(list,l.size,l.register,cgpara);
  1014. LOC_CONSTANT :
  1015. a_load_const_cgpara(list,l.size,l.value,cgpara);
  1016. LOC_CREFERENCE,
  1017. LOC_REFERENCE :
  1018. a_load_ref_cgpara(list,l.size,l.reference,cgpara);
  1019. else
  1020. internalerror(2002032211);
  1021. end;
  1022. end;
  1023. procedure tcg.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const cgpara : TCGPara);
  1024. var
  1025. hr : tregister;
  1026. begin
  1027. cgpara.check_simple_location;
  1028. if cgpara.location^.loc in [LOC_CREGISTER,LOC_REGISTER] then
  1029. begin
  1030. paramanager.allocparaloc(list,cgpara.location);
  1031. a_loadaddr_ref_reg(list,r,cgpara.location^.register)
  1032. end
  1033. else
  1034. begin
  1035. hr:=getaddressregister(list);
  1036. a_loadaddr_ref_reg(list,r,hr);
  1037. a_load_reg_cgpara(list,OS_ADDR,hr,cgpara);
  1038. end;
  1039. end;
  1040. procedure tcg.a_load_cgparaloc_ref(list : TAsmList;const paraloc : TCGParaLocation;const ref : treference;sizeleft : tcgint;align : longint);
  1041. var
  1042. href : treference;
  1043. hreg : tregister;
  1044. cgsize: tcgsize;
  1045. begin
  1046. case paraloc.loc of
  1047. LOC_REGISTER :
  1048. begin
  1049. hreg:=paraloc.register;
  1050. cgsize:=paraloc.size;
  1051. if paraloc.shiftval>0 then
  1052. a_op_const_reg_reg(list,OP_SHL,OS_INT,paraloc.shiftval,paraloc.register,paraloc.register)
  1053. { in case the original size was 3 or 5/6/7 bytes, the value was
  1054. shifted to the top of the to 4 resp. 8 byte register on the
  1055. caller side and needs to be stored with those bytes at the
  1056. start of the reference -> don't shift right }
  1057. else if (paraloc.shiftval<0) and
  1058. ((-paraloc.shiftval) in [8,16,32]) then
  1059. begin
  1060. a_op_const_reg_reg(list,OP_SHR,OS_INT,-paraloc.shiftval,paraloc.register,paraloc.register);
  1061. { convert to a register of 1/2/4 bytes in size, since the
  1062. original register had to be made larger to be able to hold
  1063. the shifted value }
  1064. cgsize:=int_cgsize(tcgsize2size[OS_INT]-(-paraloc.shiftval div 8));
  1065. if cgsize=OS_NO then
  1066. cgsize:=OS_INT;
  1067. hreg:=getintregister(list,cgsize);
  1068. a_load_reg_reg(list,OS_INT,cgsize,paraloc.register,hreg);
  1069. end;
  1070. { use the exact size to avoid overwriting of adjacent data }
  1071. if tcgsize2size[cgsize]<=sizeleft then
  1072. a_load_reg_ref(list,paraloc.size,cgsize,hreg,ref)
  1073. else
  1074. case sizeleft of
  1075. 1,2,4,8:
  1076. a_load_reg_ref(list,paraloc.size,int_cgsize(sizeleft),hreg,ref);
  1077. 3:
  1078. begin
  1079. if target_info.endian=endian_big then
  1080. begin
  1081. href:=ref;
  1082. inc(href.offset,2);
  1083. a_load_reg_ref(list,paraloc.size,OS_8,hreg,href);
  1084. a_op_const_reg_reg(list,OP_SHR,OS_INT,8,hreg,hreg);
  1085. a_load_reg_ref(list,paraloc.size,OS_16,hreg,ref);
  1086. end
  1087. else
  1088. begin
  1089. a_load_reg_ref(list,paraloc.size,OS_16,hreg,ref);
  1090. href:=ref;
  1091. inc(href.offset,2);
  1092. a_op_const_reg_reg(list,OP_SHR,cgsize,16,hreg,hreg);
  1093. a_load_reg_ref(list,paraloc.size,OS_8,hreg,href);
  1094. end
  1095. end;
  1096. 5:
  1097. begin
  1098. if target_info.endian=endian_big then
  1099. begin
  1100. href:=ref;
  1101. inc(href.offset,4);
  1102. a_load_reg_ref(list,paraloc.size,OS_8,hreg,href);
  1103. a_op_const_reg_reg(list,OP_SHR,OS_INT,8,hreg,hreg);
  1104. a_load_reg_ref(list,paraloc.size,OS_32,hreg,ref);
  1105. end
  1106. else
  1107. begin
  1108. a_load_reg_ref(list,paraloc.size,OS_32,hreg,ref);
  1109. href:=ref;
  1110. inc(href.offset,4);
  1111. a_op_const_reg_reg(list,OP_SHR,cgsize,32,hreg,hreg);
  1112. a_load_reg_ref(list,paraloc.size,OS_8,hreg,href);
  1113. end
  1114. end;
  1115. 6:
  1116. begin
  1117. if target_info.endian=endian_big then
  1118. begin
  1119. href:=ref;
  1120. inc(href.offset,4);
  1121. a_load_reg_ref(list,paraloc.size,OS_16,hreg,href);
  1122. a_op_const_reg_reg(list,OP_SHR,OS_INT,16,hreg,hreg);
  1123. a_load_reg_ref(list,paraloc.size,OS_32,hreg,ref);
  1124. end
  1125. else
  1126. begin
  1127. a_load_reg_ref(list,paraloc.size,OS_32,hreg,ref);
  1128. href:=ref;
  1129. inc(href.offset,4);
  1130. a_op_const_reg_reg(list,OP_SHR,cgsize,32,hreg,hreg);
  1131. a_load_reg_ref(list,paraloc.size,OS_16,hreg,href);
  1132. end
  1133. end;
  1134. 7:
  1135. begin
  1136. if target_info.endian=endian_big then
  1137. begin
  1138. href:=ref;
  1139. inc(href.offset,6);
  1140. a_load_reg_ref(list,paraloc.size,OS_8,hreg,href);
  1141. a_op_const_reg_reg(list,OP_SHR,OS_INT,8,hreg,hreg);
  1142. href:=ref;
  1143. inc(href.offset,4);
  1144. a_load_reg_ref(list,paraloc.size,OS_16,hreg,href);
  1145. a_op_const_reg_reg(list,OP_SHR,OS_INT,16,hreg,hreg);
  1146. a_load_reg_ref(list,paraloc.size,OS_32,hreg,ref);
  1147. end
  1148. else
  1149. begin
  1150. a_load_reg_ref(list,paraloc.size,OS_32,hreg,ref);
  1151. href:=ref;
  1152. inc(href.offset,4);
  1153. a_op_const_reg_reg(list,OP_SHR,cgsize,32,hreg,hreg);
  1154. a_load_reg_ref(list,paraloc.size,OS_16,hreg,href);
  1155. inc(href.offset,2);
  1156. a_op_const_reg_reg(list,OP_SHR,cgsize,16,hreg,hreg);
  1157. a_load_reg_ref(list,paraloc.size,OS_8,hreg,href);
  1158. end
  1159. end;
  1160. else
  1161. { other sizes not allowed }
  1162. Internalerror(2017080901);
  1163. end;
  1164. end;
  1165. LOC_MMREGISTER :
  1166. begin
  1167. case paraloc.size of
  1168. OS_F32,
  1169. OS_F64,
  1170. OS_F128:
  1171. a_loadmm_reg_ref(list,paraloc.size,paraloc.size,paraloc.register,ref,mms_movescalar);
  1172. OS_M8..OS_M128,
  1173. OS_MS8..OS_MS128:
  1174. a_loadmm_reg_ref(list,paraloc.size,paraloc.size,paraloc.register,ref,nil);
  1175. else
  1176. internalerror(2010053102);
  1177. end;
  1178. end;
  1179. LOC_FPUREGISTER :
  1180. a_loadfpu_reg_ref(list,paraloc.size,paraloc.size,paraloc.register,ref);
  1181. LOC_REFERENCE :
  1182. begin
  1183. reference_reset_base(href,paraloc.reference.index,paraloc.reference.offset,ctempposinvalid,align,[]);
  1184. { use concatcopy, because it can also be a float which fails when
  1185. load_ref_ref is used. Don't copy data when the references are equal }
  1186. if not((href.base=ref.base) and (href.offset=ref.offset)) then
  1187. g_concatcopy(list,href,ref,sizeleft);
  1188. end;
  1189. else
  1190. internalerror(2002081302);
  1191. end;
  1192. end;
  1193. procedure tcg.a_load_cgparaloc_anyreg(list: TAsmList;regsize: tcgsize;const paraloc: TCGParaLocation;reg: tregister;align: longint);
  1194. var
  1195. href : treference;
  1196. begin
  1197. case paraloc.loc of
  1198. LOC_REGISTER :
  1199. begin
  1200. if paraloc.shiftval<0 then
  1201. a_op_const_reg_reg(list,OP_SHR,OS_INT,-paraloc.shiftval,paraloc.register,paraloc.register);
  1202. case getregtype(reg) of
  1203. R_ADDRESSREGISTER,
  1204. R_INTREGISTER:
  1205. a_load_reg_reg(list,paraloc.size,regsize,paraloc.register,reg);
  1206. R_MMREGISTER:
  1207. a_loadmm_intreg_reg(list,paraloc.size,regsize,paraloc.register,reg,mms_movescalar);
  1208. R_FPUREGISTER:
  1209. a_loadfpu_intreg_reg(list,paraloc.size,regsize,paraloc.register,reg);
  1210. else
  1211. internalerror(2009112422);
  1212. end;
  1213. end;
  1214. LOC_MMREGISTER :
  1215. begin
  1216. case getregtype(reg) of
  1217. R_ADDRESSREGISTER,
  1218. R_INTREGISTER:
  1219. a_loadmm_reg_intreg(list,paraloc.size,regsize,paraloc.register,reg,mms_movescalar);
  1220. R_MMREGISTER:
  1221. begin
  1222. case paraloc.size of
  1223. OS_F32,
  1224. OS_F64,
  1225. OS_F128:
  1226. a_loadmm_reg_reg(list,paraloc.size,regsize,paraloc.register,reg,mms_movescalar);
  1227. OS_M8..OS_M128,
  1228. OS_MS8..OS_MS128:
  1229. a_loadmm_reg_reg(list,paraloc.size,paraloc.size,paraloc.register,reg,nil);
  1230. else
  1231. internalerror(2010053102);
  1232. end;
  1233. end;
  1234. else
  1235. internalerror(2010053104);
  1236. end;
  1237. end;
  1238. LOC_FPUREGISTER :
  1239. begin
  1240. case getregtype(reg) of
  1241. R_FPUREGISTER:
  1242. a_loadfpu_reg_reg(list,paraloc.size,regsize,paraloc.register,reg)
  1243. else
  1244. internalerror(2015031401);
  1245. end;
  1246. end;
  1247. LOC_REFERENCE :
  1248. begin
  1249. reference_reset_base(href,paraloc.reference.index,paraloc.reference.offset,ctempposinvalid,align,[]);
  1250. case getregtype(reg) of
  1251. R_ADDRESSREGISTER,
  1252. R_INTREGISTER :
  1253. a_load_ref_reg(list,paraloc.size,regsize,href,reg);
  1254. R_FPUREGISTER :
  1255. a_loadfpu_ref_reg(list,paraloc.size,regsize,href,reg);
  1256. R_MMREGISTER :
  1257. { not paraloc.size, because it may be OS_64 instead of
  1258. OS_F64 in case the parameter is passed using integer
  1259. conventions (e.g., on ARM) }
  1260. a_loadmm_ref_reg(list,regsize,regsize,href,reg,mms_movescalar);
  1261. else
  1262. internalerror(2004101012);
  1263. end;
  1264. end;
  1265. else
  1266. internalerror(2002081302);
  1267. end;
  1268. end;
  1269. {****************************************************************************
  1270. some generic implementations
  1271. ****************************************************************************}
  1272. { memory/register loading }
  1273. procedure tcg.a_load_reg_ref_unaligned(list : TAsmList;fromsize,tosize : tcgsize;register : tregister;const ref : treference);
  1274. var
  1275. tmpref : treference;
  1276. tmpreg : tregister;
  1277. i : longint;
  1278. begin
  1279. if ref.alignment<tcgsize2size[fromsize] then
  1280. begin
  1281. tmpref:=ref;
  1282. { we take care of the alignment now }
  1283. tmpref.alignment:=0;
  1284. case FromSize of
  1285. OS_16,OS_S16:
  1286. begin
  1287. tmpreg:=getintregister(list,OS_16);
  1288. a_load_reg_reg(list,fromsize,OS_16,register,tmpreg);
  1289. if target_info.endian=endian_big then
  1290. inc(tmpref.offset);
  1291. tmpreg:=makeregsize(list,tmpreg,OS_8);
  1292. a_load_reg_ref(list,OS_8,OS_8,tmpreg,tmpref);
  1293. tmpreg:=makeregsize(list,tmpreg,OS_16);
  1294. a_op_const_reg(list,OP_SHR,OS_16,8,tmpreg);
  1295. if target_info.endian=endian_big then
  1296. dec(tmpref.offset)
  1297. else
  1298. inc(tmpref.offset);
  1299. tmpreg:=makeregsize(list,tmpreg,OS_8);
  1300. a_load_reg_ref(list,OS_8,OS_8,tmpreg,tmpref);
  1301. end;
  1302. OS_32,OS_S32:
  1303. begin
  1304. { could add an optimised case for ref.alignment=2 }
  1305. tmpreg:=getintregister(list,OS_32);
  1306. a_load_reg_reg(list,fromsize,OS_32,register,tmpreg);
  1307. if target_info.endian=endian_big then
  1308. inc(tmpref.offset,3);
  1309. tmpreg:=makeregsize(list,tmpreg,OS_8);
  1310. a_load_reg_ref(list,OS_8,OS_8,tmpreg,tmpref);
  1311. tmpreg:=makeregsize(list,tmpreg,OS_32);
  1312. for i:=1 to 3 do
  1313. begin
  1314. a_op_const_reg(list,OP_SHR,OS_32,8,tmpreg);
  1315. if target_info.endian=endian_big then
  1316. dec(tmpref.offset)
  1317. else
  1318. inc(tmpref.offset);
  1319. tmpreg:=makeregsize(list,tmpreg,OS_8);
  1320. a_load_reg_ref(list,OS_8,OS_8,tmpreg,tmpref);
  1321. tmpreg:=makeregsize(list,tmpreg,OS_32);
  1322. end;
  1323. end
  1324. else
  1325. a_load_reg_ref(list,fromsize,tosize,register,tmpref);
  1326. end;
  1327. end
  1328. else
  1329. a_load_reg_ref(list,fromsize,tosize,register,ref);
  1330. end;
  1331. procedure tcg.a_load_ref_reg_unaligned(list : TAsmList;fromsize,tosize : tcgsize;const ref : treference;register : tregister);
  1332. var
  1333. tmpref : treference;
  1334. tmpreg,
  1335. tmpreg2 : tregister;
  1336. i : longint;
  1337. hisize : tcgsize;
  1338. begin
  1339. if ref.alignment in [1,2] then
  1340. begin
  1341. tmpref:=ref;
  1342. { we take care of the alignment now }
  1343. tmpref.alignment:=0;
  1344. case FromSize of
  1345. OS_16,OS_S16:
  1346. if ref.alignment=2 then
  1347. a_load_ref_reg(list,fromsize,tosize,tmpref,register)
  1348. else
  1349. begin
  1350. if FromSize=OS_16 then
  1351. hisize:=OS_8
  1352. else
  1353. hisize:=OS_S8;
  1354. { first load in tmpreg, because the target register }
  1355. { may be used in ref as well }
  1356. if target_info.endian=endian_little then
  1357. inc(tmpref.offset);
  1358. tmpreg:=getintregister(list,OS_8);
  1359. a_load_ref_reg(list,hisize,hisize,tmpref,tmpreg);
  1360. tmpreg:=makeregsize(list,tmpreg,FromSize);
  1361. a_op_const_reg(list,OP_SHL,FromSize,8,tmpreg);
  1362. if target_info.endian=endian_little then
  1363. dec(tmpref.offset)
  1364. else
  1365. inc(tmpref.offset);
  1366. tmpreg2:=makeregsize(list,register,OS_16);
  1367. a_load_ref_reg(list,OS_8,OS_16,tmpref,tmpreg2);
  1368. a_op_reg_reg(list,OP_OR,OS_16,tmpreg,tmpreg2);
  1369. a_load_reg_reg(list,fromsize,tosize,tmpreg2,register);
  1370. end;
  1371. OS_32,OS_S32:
  1372. if ref.alignment=2 then
  1373. begin
  1374. if target_info.endian=endian_little then
  1375. inc(tmpref.offset,2);
  1376. tmpreg:=getintregister(list,OS_32);
  1377. a_load_ref_reg(list,OS_16,OS_32,tmpref,tmpreg);
  1378. a_op_const_reg(list,OP_SHL,OS_32,16,tmpreg);
  1379. if target_info.endian=endian_little then
  1380. dec(tmpref.offset,2)
  1381. else
  1382. inc(tmpref.offset,2);
  1383. tmpreg2:=makeregsize(list,register,OS_32);
  1384. a_load_ref_reg(list,OS_16,OS_32,tmpref,tmpreg2);
  1385. a_op_reg_reg(list,OP_OR,OS_32,tmpreg,tmpreg2);
  1386. a_load_reg_reg(list,fromsize,tosize,tmpreg2,register);
  1387. end
  1388. else
  1389. begin
  1390. if target_info.endian=endian_little then
  1391. inc(tmpref.offset,3);
  1392. tmpreg:=getintregister(list,OS_32);
  1393. a_load_ref_reg(list,OS_8,OS_32,tmpref,tmpreg);
  1394. tmpreg2:=getintregister(list,OS_32);
  1395. for i:=1 to 3 do
  1396. begin
  1397. a_op_const_reg(list,OP_SHL,OS_32,8,tmpreg);
  1398. if target_info.endian=endian_little then
  1399. dec(tmpref.offset)
  1400. else
  1401. inc(tmpref.offset);
  1402. a_load_ref_reg(list,OS_8,OS_32,tmpref,tmpreg2);
  1403. a_op_reg_reg(list,OP_OR,OS_32,tmpreg2,tmpreg);
  1404. end;
  1405. a_load_reg_reg(list,fromsize,tosize,tmpreg,register);
  1406. end
  1407. else
  1408. a_load_ref_reg(list,fromsize,tosize,tmpref,register);
  1409. end;
  1410. end
  1411. else
  1412. a_load_ref_reg(list,fromsize,tosize,ref,register);
  1413. end;
  1414. procedure tcg.a_load_ref_ref(list : TAsmList;fromsize,tosize : tcgsize;const sref : treference;const dref : treference);
  1415. var
  1416. tmpreg: tregister;
  1417. begin
  1418. { verify if we have the same reference }
  1419. if references_equal(sref,dref) then
  1420. exit;
  1421. tmpreg:=getintregister(list,tosize);
  1422. a_load_ref_reg(list,fromsize,tosize,sref,tmpreg);
  1423. a_load_reg_ref(list,tosize,tosize,tmpreg,dref);
  1424. end;
  1425. procedure tcg.a_load_const_ref(list : TAsmList;size : tcgsize;a : tcgint;const ref : treference);
  1426. var
  1427. tmpreg: tregister;
  1428. begin
  1429. tmpreg:=getintregister(list,size);
  1430. a_load_const_reg(list,size,a,tmpreg);
  1431. a_load_reg_ref(list,size,size,tmpreg,ref);
  1432. end;
  1433. procedure tcg.a_load_const_loc(list : TAsmList;a : tcgint;const loc: tlocation);
  1434. begin
  1435. case loc.loc of
  1436. LOC_REFERENCE,LOC_CREFERENCE:
  1437. a_load_const_ref(list,loc.size,a,loc.reference);
  1438. LOC_REGISTER,LOC_CREGISTER:
  1439. a_load_const_reg(list,loc.size,a,loc.register);
  1440. else
  1441. internalerror(200203272);
  1442. end;
  1443. end;
  1444. procedure tcg.a_load_reg_loc(list : TAsmList;fromsize : tcgsize;reg : tregister;const loc: tlocation);
  1445. begin
  1446. case loc.loc of
  1447. LOC_REFERENCE,LOC_CREFERENCE:
  1448. a_load_reg_ref(list,fromsize,loc.size,reg,loc.reference);
  1449. LOC_REGISTER,LOC_CREGISTER:
  1450. a_load_reg_reg(list,fromsize,loc.size,reg,loc.register);
  1451. LOC_MMREGISTER,LOC_CMMREGISTER:
  1452. a_loadmm_intreg_reg(list,fromsize,loc.size,reg,loc.register,mms_movescalar);
  1453. else
  1454. internalerror(200203271);
  1455. end;
  1456. end;
  1457. procedure tcg.a_load_loc_reg(list : TAsmList; tosize: tcgsize; const loc: tlocation; reg : tregister);
  1458. begin
  1459. case loc.loc of
  1460. LOC_REFERENCE,LOC_CREFERENCE:
  1461. a_load_ref_reg(list,loc.size,tosize,loc.reference,reg);
  1462. LOC_REGISTER,LOC_CREGISTER:
  1463. a_load_reg_reg(list,loc.size,tosize,loc.register,reg);
  1464. LOC_CONSTANT:
  1465. a_load_const_reg(list,tosize,loc.value,reg);
  1466. LOC_MMREGISTER,LOC_CMMREGISTER:
  1467. a_loadmm_reg_intreg(list,loc.size,tosize,loc.register,reg,mms_movescalar);
  1468. else
  1469. internalerror(200109092);
  1470. end;
  1471. end;
  1472. procedure tcg.a_load_loc_ref(list : TAsmList;tosize: tcgsize; const loc: tlocation; const ref : treference);
  1473. begin
  1474. case loc.loc of
  1475. LOC_REFERENCE,LOC_CREFERENCE:
  1476. a_load_ref_ref(list,loc.size,tosize,loc.reference,ref);
  1477. LOC_REGISTER,LOC_CREGISTER:
  1478. a_load_reg_ref(list,loc.size,tosize,loc.register,ref);
  1479. LOC_CONSTANT:
  1480. a_load_const_ref(list,tosize,loc.value,ref);
  1481. else
  1482. internalerror(200109302);
  1483. end;
  1484. end;
  1485. procedure tcg.optimize_op_const(size: TCGSize; var op: topcg; var a : tcgint);
  1486. var
  1487. powerval : longint;
  1488. signext_a, zeroext_a: tcgint;
  1489. begin
  1490. case size of
  1491. OS_64,OS_S64:
  1492. begin
  1493. signext_a:=int64(a);
  1494. zeroext_a:=int64(a);
  1495. end;
  1496. OS_32,OS_S32:
  1497. begin
  1498. signext_a:=longint(a);
  1499. zeroext_a:=dword(a);
  1500. end;
  1501. OS_16,OS_S16:
  1502. begin
  1503. signext_a:=smallint(a);
  1504. zeroext_a:=word(a);
  1505. end;
  1506. OS_8,OS_S8:
  1507. begin
  1508. signext_a:=shortint(a);
  1509. zeroext_a:=byte(a);
  1510. end
  1511. else
  1512. begin
  1513. { Should we internalerror() here instead? }
  1514. signext_a:=a;
  1515. zeroext_a:=a;
  1516. end;
  1517. end;
  1518. case op of
  1519. OP_OR :
  1520. begin
  1521. { or with zero returns same result }
  1522. if a = 0 then
  1523. op:=OP_NONE
  1524. else
  1525. { or with max returns max }
  1526. if signext_a = -1 then
  1527. op:=OP_MOVE;
  1528. end;
  1529. OP_AND :
  1530. begin
  1531. { and with max returns same result }
  1532. if (signext_a = -1) then
  1533. op:=OP_NONE
  1534. else
  1535. { and with 0 returns 0 }
  1536. if a=0 then
  1537. op:=OP_MOVE;
  1538. end;
  1539. OP_XOR :
  1540. begin
  1541. { xor with zero returns same result }
  1542. if a = 0 then
  1543. op:=OP_NONE;
  1544. end;
  1545. OP_DIV :
  1546. begin
  1547. { division by 1 returns result }
  1548. if a = 1 then
  1549. op:=OP_NONE
  1550. else if ispowerof2(int64(zeroext_a), powerval) and not(cs_check_overflow in current_settings.localswitches) then
  1551. begin
  1552. a := powerval;
  1553. op:= OP_SHR;
  1554. end;
  1555. end;
  1556. OP_IDIV:
  1557. begin
  1558. if a = 1 then
  1559. op:=OP_NONE;
  1560. end;
  1561. OP_MUL,OP_IMUL:
  1562. begin
  1563. if a = 1 then
  1564. op:=OP_NONE
  1565. else
  1566. if a=0 then
  1567. op:=OP_MOVE
  1568. else if ispowerof2(int64(zeroext_a), powerval) and not(cs_check_overflow in current_settings.localswitches) then
  1569. begin
  1570. a := powerval;
  1571. op:= OP_SHL;
  1572. end;
  1573. end;
  1574. OP_ADD,OP_SUB:
  1575. begin
  1576. if a = 0 then
  1577. op:=OP_NONE;
  1578. end;
  1579. OP_SAR,OP_SHL,OP_SHR:
  1580. begin
  1581. if a = 0 then
  1582. op:=OP_NONE;
  1583. end;
  1584. OP_ROL,OP_ROR:
  1585. begin
  1586. case size of
  1587. OS_64,OS_S64:
  1588. a:=a and 63;
  1589. OS_32,OS_S32:
  1590. a:=a and 31;
  1591. OS_16,OS_S16:
  1592. a:=a and 15;
  1593. OS_8,OS_S8:
  1594. a:=a and 7;
  1595. end;
  1596. if a = 0 then
  1597. op:=OP_NONE;
  1598. end;
  1599. end;
  1600. end;
  1601. procedure tcg.a_loadfpu_loc_reg(list: TAsmList; tosize: tcgsize; const loc: tlocation; const reg: tregister);
  1602. begin
  1603. case loc.loc of
  1604. LOC_REFERENCE, LOC_CREFERENCE:
  1605. a_loadfpu_ref_reg(list,loc.size,tosize,loc.reference,reg);
  1606. LOC_FPUREGISTER, LOC_CFPUREGISTER:
  1607. a_loadfpu_reg_reg(list,loc.size,tosize,loc.register,reg);
  1608. else
  1609. internalerror(200203301);
  1610. end;
  1611. end;
  1612. procedure tcg.a_loadfpu_reg_loc(list: TAsmList; fromsize: tcgsize; const reg: tregister; const loc: tlocation);
  1613. begin
  1614. case loc.loc of
  1615. LOC_REFERENCE, LOC_CREFERENCE:
  1616. a_loadfpu_reg_ref(list,fromsize,loc.size,reg,loc.reference);
  1617. LOC_FPUREGISTER, LOC_CFPUREGISTER:
  1618. a_loadfpu_reg_reg(list,fromsize,loc.size,reg,loc.register);
  1619. else
  1620. internalerror(48991);
  1621. end;
  1622. end;
  1623. procedure tcg.a_loadfpu_ref_ref(list: TAsmList; fromsize, tosize: tcgsize; const ref1,ref2: treference);
  1624. var
  1625. reg: tregister;
  1626. regsize: tcgsize;
  1627. begin
  1628. if (fromsize>=tosize) then
  1629. regsize:=fromsize
  1630. else
  1631. regsize:=tosize;
  1632. reg:=getfpuregister(list,regsize);
  1633. a_loadfpu_ref_reg(list,fromsize,regsize,ref1,reg);
  1634. a_loadfpu_reg_ref(list,regsize,tosize,reg,ref2);
  1635. end;
  1636. procedure tcg.a_loadfpu_reg_cgpara(list : TAsmList;size : tcgsize;const r : tregister;const cgpara : TCGPara);
  1637. var
  1638. ref : treference;
  1639. begin
  1640. paramanager.alloccgpara(list,cgpara);
  1641. case cgpara.location^.loc of
  1642. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  1643. begin
  1644. cgpara.check_simple_location;
  1645. a_loadfpu_reg_reg(list,size,size,r,cgpara.location^.register);
  1646. end;
  1647. LOC_REFERENCE,LOC_CREFERENCE:
  1648. begin
  1649. cgpara.check_simple_location;
  1650. reference_reset_base(ref,cgpara.location^.reference.index,cgpara.location^.reference.offset,ctempposinvalid,cgpara.alignment,[]);
  1651. a_loadfpu_reg_ref(list,size,size,r,ref);
  1652. end;
  1653. LOC_REGISTER,LOC_CREGISTER:
  1654. begin
  1655. { paramfpu_ref does the check_simpe_location check here if necessary }
  1656. tg.GetTemp(list,TCGSize2Size[size],TCGSize2Size[size],tt_normal,ref);
  1657. a_loadfpu_reg_ref(list,size,size,r,ref);
  1658. a_loadfpu_ref_cgpara(list,size,ref,cgpara);
  1659. tg.Ungettemp(list,ref);
  1660. end;
  1661. else
  1662. internalerror(2010053112);
  1663. end;
  1664. end;
  1665. procedure tcg.a_loadfpu_ref_cgpara(list : TAsmList;size : tcgsize;const ref : treference;const cgpara : TCGPara);
  1666. var
  1667. href : treference;
  1668. hsize: tcgsize;
  1669. paraloc: PCGParaLocation;
  1670. begin
  1671. case cgpara.location^.loc of
  1672. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  1673. begin
  1674. paramanager.alloccgpara(list,cgpara);
  1675. paraloc:=cgpara.location;
  1676. href:=ref;
  1677. while assigned(paraloc) do
  1678. begin
  1679. if not(paraloc^.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER]) then
  1680. internalerror(2015031501);
  1681. a_loadfpu_ref_reg(list,paraloc^.size,paraloc^.size,href,paraloc^.register);
  1682. inc(href.offset,tcgsize2size[paraloc^.size]);
  1683. paraloc:=paraloc^.next;
  1684. end;
  1685. end;
  1686. LOC_REFERENCE,LOC_CREFERENCE:
  1687. begin
  1688. cgpara.check_simple_location;
  1689. reference_reset_base(href,cgpara.location^.reference.index,cgpara.location^.reference.offset,ctempposinvalid,cgpara.alignment,[]);
  1690. { concatcopy should choose the best way to copy the data }
  1691. g_concatcopy(list,ref,href,tcgsize2size[size]);
  1692. end;
  1693. LOC_REGISTER,LOC_CREGISTER:
  1694. begin
  1695. { force integer size }
  1696. hsize:=int_cgsize(tcgsize2size[size]);
  1697. {$ifndef cpu64bitalu}
  1698. if (hsize in [OS_S64,OS_64]) then
  1699. cg64.a_load64_ref_cgpara(list,ref,cgpara)
  1700. else
  1701. {$endif not cpu64bitalu}
  1702. begin
  1703. cgpara.check_simple_location;
  1704. a_load_ref_cgpara(list,hsize,ref,cgpara)
  1705. end;
  1706. end
  1707. else
  1708. internalerror(200402201);
  1709. end;
  1710. end;
  1711. procedure tcg.a_loadfpu_intreg_reg(list : TAsmList; fromsize,tosize : tcgsize; intreg,fpureg : tregister);
  1712. var
  1713. tmpref: treference;
  1714. begin
  1715. if not(tcgsize2size[fromsize] in [4,8]) or
  1716. not(tcgsize2size[tosize] in [4,8]) or
  1717. (tcgsize2size[fromsize]<>tcgsize2size[tosize]) then
  1718. internalerror(2017070902);
  1719. tg.gettemp(list,tcgsize2size[fromsize],tcgsize2size[fromsize],tt_normal,tmpref);
  1720. a_load_reg_ref(list,fromsize,fromsize,intreg,tmpref);
  1721. a_loadfpu_ref_reg(list,tosize,tosize,tmpref,fpureg);
  1722. tg.ungettemp(list,tmpref);
  1723. end;
  1724. procedure tcg.a_op_const_ref(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; const ref: TReference);
  1725. var
  1726. tmpreg : tregister;
  1727. tmpref : treference;
  1728. begin
  1729. if assigned(ref.symbol) then
  1730. begin
  1731. tmpreg:=getaddressregister(list);
  1732. a_loadaddr_ref_reg(list,ref,tmpreg);
  1733. reference_reset_base(tmpref,tmpreg,0,ref.temppos,ref.alignment,[]);
  1734. end
  1735. else
  1736. tmpref:=ref;
  1737. tmpreg:=getintregister(list,size);
  1738. a_load_ref_reg(list,size,size,tmpref,tmpreg);
  1739. a_op_const_reg(list,op,size,a,tmpreg);
  1740. a_load_reg_ref(list,size,size,tmpreg,tmpref);
  1741. end;
  1742. procedure tcg.a_op_const_loc(list : TAsmList; Op: TOpCG; a: tcgint; const loc: tlocation);
  1743. begin
  1744. case loc.loc of
  1745. LOC_REGISTER, LOC_CREGISTER:
  1746. a_op_const_reg(list,op,loc.size,a,loc.register);
  1747. LOC_REFERENCE, LOC_CREFERENCE:
  1748. a_op_const_ref(list,op,loc.size,a,loc.reference);
  1749. else
  1750. internalerror(200109061);
  1751. end;
  1752. end;
  1753. procedure tcg.a_op_reg_ref(list : TAsmList; Op: TOpCG; size: TCGSize;reg: TRegister; const ref: TReference);
  1754. var
  1755. tmpreg : tregister;
  1756. tmpref : treference;
  1757. begin
  1758. if assigned(ref.symbol) then
  1759. begin
  1760. tmpreg:=getaddressregister(list);
  1761. a_loadaddr_ref_reg(list,ref,tmpreg);
  1762. reference_reset_base(tmpref,tmpreg,0,ref.temppos,ref.alignment,[]);
  1763. end
  1764. else
  1765. tmpref:=ref;
  1766. tmpreg:=getintregister(list,size);
  1767. a_load_ref_reg(list,size,size,tmpref,tmpreg);
  1768. if op in [OP_NEG,OP_NOT] then
  1769. begin
  1770. if reg<>NR_NO then
  1771. internalerror(2017040901);
  1772. a_op_reg_reg(list,op,size,tmpreg,tmpreg);
  1773. end
  1774. else
  1775. a_op_reg_reg(list,op,size,reg,tmpreg);
  1776. a_load_reg_ref(list,size,size,tmpreg,tmpref);
  1777. end;
  1778. procedure tcg.a_op_ref_reg(list : TAsmList; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister);
  1779. var
  1780. tmpreg: tregister;
  1781. begin
  1782. case op of
  1783. OP_NOT,OP_NEG:
  1784. { handle it as "load ref,reg; op reg" }
  1785. begin
  1786. a_load_ref_reg(list,size,size,ref,reg);
  1787. a_op_reg_reg(list,op,size,reg,reg);
  1788. end;
  1789. else
  1790. begin
  1791. tmpreg:=getintregister(list,size);
  1792. a_load_ref_reg(list,size,size,ref,tmpreg);
  1793. a_op_reg_reg(list,op,size,tmpreg,reg);
  1794. end;
  1795. end;
  1796. end;
  1797. procedure tcg.a_op_reg_loc(list : TAsmList; Op: TOpCG; reg: tregister; const loc: tlocation);
  1798. begin
  1799. case loc.loc of
  1800. LOC_REGISTER, LOC_CREGISTER:
  1801. a_op_reg_reg(list,op,loc.size,reg,loc.register);
  1802. LOC_REFERENCE, LOC_CREFERENCE:
  1803. a_op_reg_ref(list,op,loc.size,reg,loc.reference);
  1804. else
  1805. internalerror(200109061);
  1806. end;
  1807. end;
  1808. procedure tcg.a_op_loc_reg(list : TAsmList; Op : TOpCG; size: TCGSize; const loc : tlocation; reg : tregister);
  1809. begin
  1810. case loc.loc of
  1811. LOC_REGISTER, LOC_CREGISTER:
  1812. a_op_reg_reg(list,op,size,loc.register,reg);
  1813. LOC_REFERENCE, LOC_CREFERENCE:
  1814. a_op_ref_reg(list,op,size,loc.reference,reg);
  1815. LOC_CONSTANT:
  1816. a_op_const_reg(list,op,size,loc.value,reg);
  1817. else
  1818. internalerror(2018031101);
  1819. end;
  1820. end;
  1821. procedure tcg.a_op_ref_loc(list : TAsmList; Op: TOpCG; const ref: TReference; const loc: tlocation);
  1822. var
  1823. tmpreg: tregister;
  1824. begin
  1825. case loc.loc of
  1826. LOC_REGISTER,LOC_CREGISTER:
  1827. a_op_ref_reg(list,op,loc.size,ref,loc.register);
  1828. LOC_REFERENCE,LOC_CREFERENCE:
  1829. begin
  1830. tmpreg:=getintregister(list,loc.size);
  1831. a_load_ref_reg(list,loc.size,loc.size,ref,tmpreg);
  1832. a_op_reg_ref(list,op,loc.size,tmpreg,loc.reference);
  1833. end;
  1834. else
  1835. internalerror(200109061);
  1836. end;
  1837. end;
  1838. procedure Tcg.a_op_const_reg_reg(list:TAsmList;op:Topcg;size:Tcgsize;
  1839. a:tcgint;src,dst:Tregister);
  1840. begin
  1841. optimize_op_const(size, op, a);
  1842. case op of
  1843. OP_NONE:
  1844. begin
  1845. if src <> dst then
  1846. a_load_reg_reg(list, size, size, src, dst);
  1847. exit;
  1848. end;
  1849. OP_MOVE:
  1850. begin
  1851. a_load_const_reg(list, size, a, dst);
  1852. exit;
  1853. end;
  1854. {$ifdef cpu8bitalu}
  1855. OP_SHL:
  1856. begin
  1857. if a=8 then
  1858. case size of
  1859. OS_S16,OS_16:
  1860. begin
  1861. a_load_reg_reg(list,OS_8,OS_8,src,GetNextReg(dst));
  1862. a_load_const_reg(list,OS_8,0,dst);
  1863. exit;
  1864. end;
  1865. end;
  1866. end;
  1867. OP_SHR:
  1868. begin
  1869. if a=8 then
  1870. case size of
  1871. OS_S16,OS_16:
  1872. begin
  1873. a_load_reg_reg(list,OS_8,OS_8,GetNextReg(src),dst);
  1874. a_load_const_reg(list,OS_8,0,GetNextReg(dst));
  1875. exit;
  1876. end;
  1877. end;
  1878. end;
  1879. {$endif cpu8bitalu}
  1880. {$ifdef cpu16bitalu}
  1881. OP_SHL:
  1882. begin
  1883. if a=16 then
  1884. case size of
  1885. OS_S32,OS_32:
  1886. begin
  1887. a_load_reg_reg(list,OS_16,OS_16,src,GetNextReg(dst));
  1888. a_load_const_reg(list,OS_16,0,dst);
  1889. exit;
  1890. end;
  1891. end;
  1892. end;
  1893. OP_SHR:
  1894. begin
  1895. if a=16 then
  1896. case size of
  1897. OS_S32,OS_32:
  1898. begin
  1899. a_load_reg_reg(list,OS_16,OS_16,GetNextReg(src),dst);
  1900. a_load_const_reg(list,OS_16,0,GetNextReg(dst));
  1901. exit;
  1902. end;
  1903. end;
  1904. end;
  1905. {$endif cpu16bitalu}
  1906. end;
  1907. a_load_reg_reg(list,size,size,src,dst);
  1908. a_op_const_reg(list,op,size,a,dst);
  1909. end;
  1910. procedure tcg.a_op_reg_reg_reg(list: TAsmList; op: TOpCg;
  1911. size: tcgsize; src1, src2, dst: tregister);
  1912. var
  1913. tmpreg: tregister;
  1914. begin
  1915. if (dst<>src1) then
  1916. begin
  1917. a_load_reg_reg(list,size,size,src2,dst);
  1918. a_op_reg_reg(list,op,size,src1,dst);
  1919. end
  1920. else
  1921. begin
  1922. { can we do a direct operation on the target register ? }
  1923. if op in [OP_ADD,OP_MUL,OP_AND,OP_MOVE,OP_XOR,OP_IMUL,OP_OR] then
  1924. a_op_reg_reg(list,op,size,src2,dst)
  1925. else
  1926. begin
  1927. tmpreg:=getintregister(list,size);
  1928. a_load_reg_reg(list,size,size,src2,tmpreg);
  1929. a_op_reg_reg(list,op,size,src1,tmpreg);
  1930. a_load_reg_reg(list,size,size,tmpreg,dst);
  1931. end;
  1932. end;
  1933. end;
  1934. procedure tcg.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);
  1935. begin
  1936. a_op_const_reg_reg(list,op,size,a,src,dst);
  1937. ovloc.loc:=LOC_VOID;
  1938. end;
  1939. procedure tcg.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);
  1940. begin
  1941. a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  1942. ovloc.loc:=LOC_VOID;
  1943. end;
  1944. procedure tcg.a_cmp_const_reg_label(list: TAsmList; size: tcgsize;
  1945. cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);
  1946. var
  1947. tmpreg: tregister;
  1948. begin
  1949. tmpreg:=getintregister(list,size);
  1950. a_load_const_reg(list,size,a,tmpreg);
  1951. a_cmp_reg_reg_label(list,size,cmp_op,tmpreg,reg,l);
  1952. end;
  1953. procedure tcg.a_cmp_const_ref_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;const ref : treference;
  1954. l : tasmlabel);
  1955. var
  1956. tmpreg: tregister;
  1957. begin
  1958. tmpreg:=getintregister(list,size);
  1959. a_load_ref_reg(list,size,size,ref,tmpreg);
  1960. a_cmp_const_reg_label(list,size,cmp_op,a,tmpreg,l);
  1961. end;
  1962. procedure tcg.a_cmp_const_loc_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;const loc : tlocation;
  1963. l : tasmlabel);
  1964. begin
  1965. case loc.loc of
  1966. LOC_REGISTER,LOC_CREGISTER:
  1967. a_cmp_const_reg_label(list,size,cmp_op,a,loc.register,l);
  1968. LOC_REFERENCE,LOC_CREFERENCE:
  1969. a_cmp_const_ref_label(list,size,cmp_op,a,loc.reference,l);
  1970. else
  1971. internalerror(200109061);
  1972. end;
  1973. end;
  1974. procedure tcg.a_cmp_ref_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp; const ref: treference; reg : tregister; l : tasmlabel);
  1975. var
  1976. tmpreg: tregister;
  1977. begin
  1978. tmpreg:=getintregister(list,size);
  1979. a_load_ref_reg(list,size,size,ref,tmpreg);
  1980. a_cmp_reg_reg_label(list,size,cmp_op,tmpreg,reg,l);
  1981. end;
  1982. procedure tcg.a_cmp_reg_ref_label(list : TAsmList;size : tcgsize;cmp_op : topcmp; reg : tregister; const ref: treference; l : tasmlabel);
  1983. var
  1984. tmpreg: tregister;
  1985. begin
  1986. tmpreg:=getintregister(list,size);
  1987. a_load_ref_reg(list,size,size,ref,tmpreg);
  1988. a_cmp_reg_reg_label(list,size,cmp_op,reg,tmpreg,l);
  1989. end;
  1990. procedure tcg.a_cmp_reg_loc_label(list : TAsmList;size : tcgsize;cmp_op : topcmp; reg: tregister; const loc: tlocation; l : tasmlabel);
  1991. begin
  1992. a_cmp_loc_reg_label(list,size,swap_opcmp(cmp_op),loc,reg,l);
  1993. end;
  1994. procedure tcg.a_cmp_loc_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp; const loc: tlocation; reg : tregister; l : tasmlabel);
  1995. begin
  1996. case loc.loc of
  1997. LOC_REGISTER,
  1998. LOC_CREGISTER:
  1999. a_cmp_reg_reg_label(list,size,cmp_op,loc.register,reg,l);
  2000. LOC_REFERENCE,
  2001. LOC_CREFERENCE :
  2002. a_cmp_ref_reg_label(list,size,cmp_op,loc.reference,reg,l);
  2003. LOC_CONSTANT:
  2004. a_cmp_const_reg_label(list,size,cmp_op,loc.value,reg,l);
  2005. else
  2006. internalerror(200203231);
  2007. end;
  2008. end;
  2009. procedure tcg.a_cmp_ref_loc_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;const ref: treference;const loc : tlocation;
  2010. l : tasmlabel);
  2011. var
  2012. tmpreg: tregister;
  2013. begin
  2014. case loc.loc of
  2015. LOC_REGISTER,LOC_CREGISTER:
  2016. a_cmp_ref_reg_label(list,size,cmp_op,ref,loc.register,l);
  2017. LOC_REFERENCE,LOC_CREFERENCE:
  2018. begin
  2019. tmpreg:=getintregister(list,size);
  2020. a_load_ref_reg(list,size,size,loc.reference,tmpreg);
  2021. a_cmp_ref_reg_label(list,size,cmp_op,ref,tmpreg,l);
  2022. end;
  2023. else
  2024. internalerror(200109061);
  2025. end;
  2026. end;
  2027. procedure tcg.a_loadmm_loc_reg(list: TAsmList; size: tcgsize; const loc: tlocation; const reg: tregister;shuffle : pmmshuffle);
  2028. begin
  2029. case loc.loc of
  2030. LOC_MMREGISTER,LOC_CMMREGISTER:
  2031. a_loadmm_reg_reg(list,loc.size,size,loc.register,reg,shuffle);
  2032. LOC_REFERENCE,LOC_CREFERENCE:
  2033. a_loadmm_ref_reg(list,loc.size,size,loc.reference,reg,shuffle);
  2034. LOC_REGISTER,LOC_CREGISTER:
  2035. a_loadmm_intreg_reg(list,loc.size,size,loc.register,reg,shuffle);
  2036. else
  2037. internalerror(200310121);
  2038. end;
  2039. end;
  2040. procedure tcg.a_loadmm_reg_loc(list: TAsmList; size: tcgsize; const reg: tregister; const loc: tlocation;shuffle : pmmshuffle);
  2041. begin
  2042. case loc.loc of
  2043. LOC_MMREGISTER,LOC_CMMREGISTER:
  2044. a_loadmm_reg_reg(list,size,loc.size,reg,loc.register,shuffle);
  2045. LOC_REFERENCE,LOC_CREFERENCE:
  2046. a_loadmm_reg_ref(list,size,loc.size,reg,loc.reference,shuffle);
  2047. else
  2048. internalerror(200310122);
  2049. end;
  2050. end;
  2051. procedure tcg.a_loadmm_reg_cgpara(list: TAsmList; size: tcgsize; reg: tregister;const cgpara : TCGPara;shuffle : pmmshuffle);
  2052. var
  2053. href : treference;
  2054. {$ifndef cpu64bitalu}
  2055. tmpreg : tregister;
  2056. reg64 : tregister64;
  2057. {$endif not cpu64bitalu}
  2058. begin
  2059. {$ifndef cpu64bitalu}
  2060. if not(cgpara.location^.loc in [LOC_REGISTER,LOC_CREGISTER]) or
  2061. (size<>OS_F64) then
  2062. {$endif not cpu64bitalu}
  2063. cgpara.check_simple_location;
  2064. paramanager.alloccgpara(list,cgpara);
  2065. case cgpara.location^.loc of
  2066. LOC_MMREGISTER,LOC_CMMREGISTER:
  2067. a_loadmm_reg_reg(list,size,cgpara.location^.size,reg,cgpara.location^.register,shuffle);
  2068. LOC_REFERENCE,LOC_CREFERENCE:
  2069. begin
  2070. reference_reset_base(href,cgpara.location^.reference.index,cgpara.location^.reference.offset,ctempposinvalid,cgpara.alignment,[]);
  2071. a_loadmm_reg_ref(list,size,cgpara.location^.size,reg,href,shuffle);
  2072. end;
  2073. LOC_REGISTER,LOC_CREGISTER:
  2074. begin
  2075. if assigned(shuffle) and
  2076. not shufflescalar(shuffle) then
  2077. internalerror(2009112510);
  2078. {$ifndef cpu64bitalu}
  2079. if (size=OS_F64) then
  2080. begin
  2081. if not assigned(cgpara.location^.next) or
  2082. assigned(cgpara.location^.next^.next) then
  2083. internalerror(2009112512);
  2084. case cgpara.location^.next^.loc of
  2085. LOC_REGISTER,LOC_CREGISTER:
  2086. tmpreg:=cgpara.location^.next^.register;
  2087. LOC_REFERENCE,LOC_CREFERENCE:
  2088. tmpreg:=getintregister(list,OS_32);
  2089. else
  2090. internalerror(2009112910);
  2091. end;
  2092. if (target_info.endian=ENDIAN_BIG) then
  2093. begin
  2094. { paraloc^ -> high
  2095. paraloc^.next -> low }
  2096. reg64.reghi:=cgpara.location^.register;
  2097. reg64.reglo:=tmpreg;
  2098. end
  2099. else
  2100. begin
  2101. { paraloc^ -> low
  2102. paraloc^.next -> high }
  2103. reg64.reglo:=cgpara.location^.register;
  2104. reg64.reghi:=tmpreg;
  2105. end;
  2106. cg64.a_loadmm_reg_intreg64(list,size,reg,reg64);
  2107. if (cgpara.location^.next^.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  2108. begin
  2109. if not(cgpara.location^.next^.size in [OS_32,OS_S32]) then
  2110. internalerror(2009112911);
  2111. reference_reset_base(href,cgpara.location^.next^.reference.index,cgpara.location^.next^.reference.offset,ctempposinvalid,cgpara.alignment,[]);
  2112. a_load_reg_ref(list,OS_32,cgpara.location^.next^.size,tmpreg,href);
  2113. end;
  2114. end
  2115. else
  2116. {$endif not cpu64bitalu}
  2117. a_loadmm_reg_intreg(list,size,cgpara.location^.size,reg,cgpara.location^.register,mms_movescalar);
  2118. end
  2119. else
  2120. internalerror(200310123);
  2121. end;
  2122. end;
  2123. procedure tcg.a_loadmm_ref_cgpara(list: TAsmList; size: tcgsize;const ref: treference;const cgpara : TCGPara;shuffle : pmmshuffle);
  2124. var
  2125. hr : tregister;
  2126. hs : tmmshuffle;
  2127. begin
  2128. cgpara.check_simple_location;
  2129. hr:=getmmregister(list,cgpara.location^.size);
  2130. a_loadmm_ref_reg(list,size,cgpara.location^.size,ref,hr,shuffle);
  2131. if realshuffle(shuffle) then
  2132. begin
  2133. hs:=shuffle^;
  2134. removeshuffles(hs);
  2135. a_loadmm_reg_cgpara(list,cgpara.location^.size,hr,cgpara,@hs);
  2136. end
  2137. else
  2138. a_loadmm_reg_cgpara(list,cgpara.location^.size,hr,cgpara,shuffle);
  2139. end;
  2140. procedure tcg.a_loadmm_loc_cgpara(list: TAsmList;const loc: tlocation; const cgpara : TCGPara;shuffle : pmmshuffle);
  2141. begin
  2142. case loc.loc of
  2143. LOC_MMREGISTER,LOC_CMMREGISTER:
  2144. a_loadmm_reg_cgpara(list,loc.size,loc.register,cgpara,shuffle);
  2145. LOC_REFERENCE,LOC_CREFERENCE:
  2146. a_loadmm_ref_cgpara(list,loc.size,loc.reference,cgpara,shuffle);
  2147. else
  2148. internalerror(200310123);
  2149. end;
  2150. end;
  2151. procedure tcg.a_opmm_ref_reg(list: TAsmList; Op: TOpCG; size : tcgsize;const ref: treference; reg: tregister;shuffle : pmmshuffle);
  2152. var
  2153. hr : tregister;
  2154. hs : tmmshuffle;
  2155. begin
  2156. hr:=getmmregister(list,size);
  2157. a_loadmm_ref_reg(list,size,size,ref,hr,shuffle);
  2158. if realshuffle(shuffle) then
  2159. begin
  2160. hs:=shuffle^;
  2161. removeshuffles(hs);
  2162. a_opmm_reg_reg(list,op,size,hr,reg,@hs);
  2163. end
  2164. else
  2165. a_opmm_reg_reg(list,op,size,hr,reg,shuffle);
  2166. end;
  2167. procedure tcg.a_opmm_reg_ref(list: TAsmList; Op: TOpCG; size : tcgsize;reg: tregister; const ref: treference; shuffle : pmmshuffle);
  2168. var
  2169. hr : tregister;
  2170. hs : tmmshuffle;
  2171. begin
  2172. hr:=getmmregister(list,size);
  2173. a_loadmm_ref_reg(list,size,size,ref,hr,shuffle);
  2174. if realshuffle(shuffle) then
  2175. begin
  2176. hs:=shuffle^;
  2177. removeshuffles(hs);
  2178. a_opmm_reg_reg(list,op,size,reg,hr,@hs);
  2179. a_loadmm_reg_ref(list,size,size,hr,ref,@hs);
  2180. end
  2181. else
  2182. begin
  2183. a_opmm_reg_reg(list,op,size,reg,hr,shuffle);
  2184. a_loadmm_reg_ref(list,size,size,hr,ref,shuffle);
  2185. end;
  2186. end;
  2187. procedure tcg.a_loadmm_intreg_reg(list: tasmlist; fromsize,tosize: tcgsize; intreg,mmreg: tregister; shuffle: pmmshuffle);
  2188. var
  2189. tmpref: treference;
  2190. begin
  2191. if (tcgsize2size[fromsize]<>4) or
  2192. (tcgsize2size[tosize]<>4) then
  2193. internalerror(2009112503);
  2194. tg.gettemp(list,4,4,tt_normal,tmpref);
  2195. a_load_reg_ref(list,fromsize,fromsize,intreg,tmpref);
  2196. a_loadmm_ref_reg(list,tosize,tosize,tmpref,mmreg,shuffle);
  2197. tg.ungettemp(list,tmpref);
  2198. end;
  2199. procedure tcg.a_loadmm_reg_intreg(list: tasmlist; fromsize,tosize: tcgsize; mmreg,intreg: tregister; shuffle: pmmshuffle);
  2200. var
  2201. tmpref: treference;
  2202. begin
  2203. if (tcgsize2size[fromsize]<>4) or
  2204. (tcgsize2size[tosize]<>4) then
  2205. internalerror(2009112504);
  2206. tg.gettemp(list,8,8,tt_normal,tmpref);
  2207. a_loadmm_reg_ref(list,fromsize,fromsize,mmreg,tmpref,shuffle);
  2208. a_load_ref_reg(list,tosize,tosize,tmpref,intreg);
  2209. tg.ungettemp(list,tmpref);
  2210. end;
  2211. procedure tcg.a_opmm_loc_reg(list: TAsmList; Op: TOpCG; size : tcgsize;const loc: tlocation; reg: tregister;shuffle : pmmshuffle);
  2212. begin
  2213. case loc.loc of
  2214. LOC_CMMREGISTER,LOC_MMREGISTER:
  2215. a_opmm_reg_reg(list,op,size,loc.register,reg,shuffle);
  2216. LOC_CREFERENCE,LOC_REFERENCE:
  2217. a_opmm_ref_reg(list,op,size,loc.reference,reg,shuffle);
  2218. else
  2219. internalerror(200312232);
  2220. end;
  2221. end;
  2222. procedure tcg.a_opmm_loc_reg_reg(list: TAsmList; Op: TOpCG; size : tcgsize;const loc: tlocation; src,dst: tregister;shuffle : pmmshuffle);
  2223. begin
  2224. case loc.loc of
  2225. LOC_CMMREGISTER,LOC_MMREGISTER:
  2226. a_opmm_reg_reg_reg(list,op,size,loc.register,src,dst,shuffle);
  2227. LOC_CREFERENCE,LOC_REFERENCE:
  2228. a_opmm_ref_reg_reg(list,op,size,loc.reference,src,dst,shuffle);
  2229. else
  2230. internalerror(200312232);
  2231. end;
  2232. end;
  2233. procedure tcg.a_opmm_reg_reg_reg(list : TAsmList;Op : TOpCG;size : tcgsize;
  2234. src1,src2,dst : tregister;shuffle : pmmshuffle);
  2235. begin
  2236. internalerror(2013061102);
  2237. end;
  2238. procedure tcg.a_opmm_ref_reg_reg(list : TAsmList;Op : TOpCG;size : tcgsize;
  2239. const ref : treference;src,dst : tregister;shuffle : pmmshuffle);
  2240. begin
  2241. internalerror(2013061101);
  2242. end;
  2243. procedure tcg.g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : tcgint);
  2244. begin
  2245. g_concatcopy(list,source,dest,len);
  2246. end;
  2247. procedure tcg.g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);
  2248. begin
  2249. g_overflowCheck(list,loc,def);
  2250. end;
  2251. {$ifdef cpuflags}
  2252. procedure tcg.g_flags2ref(list: TAsmList; size: TCgSize; const f: tresflags; const ref:TReference);
  2253. var
  2254. tmpreg : tregister;
  2255. begin
  2256. tmpreg:=getintregister(list,size);
  2257. g_flags2reg(list,size,f,tmpreg);
  2258. a_load_reg_ref(list,size,size,tmpreg,ref);
  2259. end;
  2260. {$endif cpuflags}
  2261. {*****************************************************************************
  2262. Entry/Exit Code Functions
  2263. *****************************************************************************}
  2264. procedure tcg.g_save_registers(list:TAsmList);
  2265. var
  2266. href : treference;
  2267. size : longint;
  2268. r : integer;
  2269. regs_to_save_int,
  2270. regs_to_save_address,
  2271. regs_to_save_mm : tcpuregisterarray;
  2272. begin
  2273. regs_to_save_int:=paramanager.get_saved_registers_int(current_procinfo.procdef.proccalloption);
  2274. regs_to_save_address:=paramanager.get_saved_registers_address(current_procinfo.procdef.proccalloption);
  2275. regs_to_save_mm:=paramanager.get_saved_registers_mm(current_procinfo.procdef.proccalloption);
  2276. { calculate temp. size }
  2277. size:=0;
  2278. for r:=low(regs_to_save_int) to high(regs_to_save_int) do
  2279. if regs_to_save_int[r] in rg[R_INTREGISTER].used_in_proc then
  2280. inc(size,sizeof(aint));
  2281. if uses_registers(R_ADDRESSREGISTER) then
  2282. for r:=low(regs_to_save_int) to high(regs_to_save_int) do
  2283. if regs_to_save_int[r] in rg[R_ADDRESSREGISTER].used_in_proc then
  2284. inc(size,sizeof(aint));
  2285. { mm registers }
  2286. if uses_registers(R_MMREGISTER) then
  2287. begin
  2288. { Make sure we reserve enough space to do the alignment based on the offset
  2289. later on. We can't use the size for this, because the alignment of the start
  2290. of the temp is smaller than needed for an OS_VECTOR }
  2291. inc(size,tcgsize2size[OS_VECTOR]);
  2292. for r:=low(regs_to_save_mm) to high(regs_to_save_mm) do
  2293. if regs_to_save_mm[r] in rg[R_MMREGISTER].used_in_proc then
  2294. inc(size,tcgsize2size[OS_VECTOR]);
  2295. end;
  2296. if size>0 then
  2297. begin
  2298. tg.GetTemp(list,size,sizeof(aint),tt_noreuse,current_procinfo.save_regs_ref);
  2299. include(current_procinfo.flags,pi_has_saved_regs);
  2300. { Copy registers to temp }
  2301. href:=current_procinfo.save_regs_ref;
  2302. for r:=low(regs_to_save_int) to high(regs_to_save_int) do
  2303. begin
  2304. if regs_to_save_int[r] in rg[R_INTREGISTER].used_in_proc then
  2305. begin
  2306. a_load_reg_ref(list,OS_ADDR,OS_ADDR,newreg(R_INTREGISTER,regs_to_save_int[r],R_SUBWHOLE),href);
  2307. inc(href.offset,sizeof(aint));
  2308. end;
  2309. include(rg[R_INTREGISTER].preserved_by_proc,regs_to_save_int[r]);
  2310. end;
  2311. if uses_registers(R_ADDRESSREGISTER) then
  2312. for r:=low(regs_to_save_address) to high(regs_to_save_address) do
  2313. begin
  2314. if regs_to_save_address[r] in rg[R_ADDRESSREGISTER].used_in_proc then
  2315. begin
  2316. a_load_reg_ref(list,OS_ADDR,OS_ADDR,newreg(R_ADDRESSREGISTER,regs_to_save_address[r],R_SUBWHOLE),href);
  2317. inc(href.offset,sizeof(aint));
  2318. end;
  2319. include(rg[R_ADDRESSREGISTER].preserved_by_proc,regs_to_save_address[r]);
  2320. end;
  2321. if uses_registers(R_MMREGISTER) then
  2322. begin
  2323. if (href.offset mod tcgsize2size[OS_VECTOR])<>0 then
  2324. inc(href.offset,tcgsize2size[OS_VECTOR]-(href.offset mod tcgsize2size[OS_VECTOR]));
  2325. for r:=low(regs_to_save_mm) to high(regs_to_save_mm) do
  2326. begin
  2327. { the array has to be declared even if no MM registers are saved
  2328. (such as with SSE on i386), and since 0-element arrays don't
  2329. exist, they contain a single RS_INVALID element in that case
  2330. }
  2331. if regs_to_save_mm[r]<>RS_INVALID then
  2332. begin
  2333. if regs_to_save_mm[r] in rg[R_MMREGISTER].used_in_proc then
  2334. begin
  2335. a_loadmm_reg_ref(list,OS_VECTOR,OS_VECTOR,newreg(R_MMREGISTER,regs_to_save_mm[r],R_SUBMMWHOLE),href,nil);
  2336. inc(href.offset,tcgsize2size[OS_VECTOR]);
  2337. end;
  2338. include(rg[R_MMREGISTER].preserved_by_proc,regs_to_save_mm[r]);
  2339. end;
  2340. end;
  2341. end;
  2342. end;
  2343. end;
  2344. procedure tcg.g_restore_registers(list:TAsmList);
  2345. var
  2346. href : treference;
  2347. r : integer;
  2348. hreg : tregister;
  2349. regs_to_save_int,
  2350. regs_to_save_address,
  2351. regs_to_save_mm : tcpuregisterarray;
  2352. begin
  2353. if not(pi_has_saved_regs in current_procinfo.flags) then
  2354. exit;
  2355. regs_to_save_int:=paramanager.get_saved_registers_int(current_procinfo.procdef.proccalloption);
  2356. regs_to_save_address:=paramanager.get_saved_registers_address(current_procinfo.procdef.proccalloption);
  2357. regs_to_save_mm:=paramanager.get_saved_registers_mm(current_procinfo.procdef.proccalloption);
  2358. { Copy registers from temp }
  2359. href:=current_procinfo.save_regs_ref;
  2360. for r:=low(regs_to_save_int) to high(regs_to_save_int) do
  2361. if regs_to_save_int[r] in rg[R_INTREGISTER].used_in_proc then
  2362. begin
  2363. hreg:=newreg(R_INTREGISTER,regs_to_save_int[r],R_SUBWHOLE);
  2364. { Allocate register so the optimizer does not remove the load }
  2365. a_reg_alloc(list,hreg);
  2366. a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,hreg);
  2367. inc(href.offset,sizeof(aint));
  2368. end;
  2369. if uses_registers(R_ADDRESSREGISTER) then
  2370. for r:=low(regs_to_save_address) to high(regs_to_save_address) do
  2371. if regs_to_save_address[r] in rg[R_ADDRESSREGISTER].used_in_proc then
  2372. begin
  2373. hreg:=newreg(R_ADDRESSREGISTER,regs_to_save_address[r],R_SUBWHOLE);
  2374. { Allocate register so the optimizer does not remove the load }
  2375. a_reg_alloc(list,hreg);
  2376. a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,hreg);
  2377. inc(href.offset,sizeof(aint));
  2378. end;
  2379. if uses_registers(R_MMREGISTER) then
  2380. begin
  2381. if (href.offset mod tcgsize2size[OS_VECTOR])<>0 then
  2382. inc(href.offset,tcgsize2size[OS_VECTOR]-(href.offset mod tcgsize2size[OS_VECTOR]));
  2383. for r:=low(regs_to_save_mm) to high(regs_to_save_mm) do
  2384. begin
  2385. if regs_to_save_mm[r] in rg[R_MMREGISTER].used_in_proc then
  2386. begin
  2387. hreg:=newreg(R_MMREGISTER,regs_to_save_mm[r],R_SUBMMWHOLE);
  2388. { Allocate register so the optimizer does not remove the load }
  2389. a_reg_alloc(list,hreg);
  2390. a_loadmm_ref_reg(list,OS_VECTOR,OS_VECTOR,href,hreg,nil);
  2391. inc(href.offset,tcgsize2size[OS_VECTOR]);
  2392. end;
  2393. end;
  2394. end;
  2395. tg.UnGetTemp(list,current_procinfo.save_regs_ref);
  2396. end;
  2397. procedure tcg.g_profilecode(list : TAsmList);
  2398. begin
  2399. end;
  2400. procedure tcg.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);
  2401. var
  2402. hsym : tsym;
  2403. href : treference;
  2404. paraloc : Pcgparalocation;
  2405. begin
  2406. { calculate the parameter info for the procdef }
  2407. procdef.init_paraloc_info(callerside);
  2408. hsym:=tsym(procdef.parast.Find('self'));
  2409. if not(assigned(hsym) and
  2410. (hsym.typ=paravarsym)) then
  2411. internalerror(200305251);
  2412. paraloc:=tparavarsym(hsym).paraloc[callerside].location;
  2413. while paraloc<>nil do
  2414. with paraloc^ do
  2415. begin
  2416. case loc of
  2417. LOC_REGISTER:
  2418. a_op_const_reg(list,OP_SUB,size,ioffset,register);
  2419. LOC_REFERENCE:
  2420. begin
  2421. { offset in the wrapper needs to be adjusted for the stored
  2422. return address }
  2423. reference_reset_base(href,reference.index,reference.offset+sizeof(pint),ctempposinvalid,sizeof(pint),[]);
  2424. a_op_const_ref(list,OP_SUB,size,ioffset,href);
  2425. end
  2426. else
  2427. internalerror(200309189);
  2428. end;
  2429. paraloc:=next;
  2430. end;
  2431. end;
  2432. procedure tcg.a_call_name_static(list : TAsmList;const s : string);
  2433. begin
  2434. a_call_name(list,s,false);
  2435. end;
  2436. function tcg.g_indirect_sym_load(list:TAsmList;const symname: string; const flags: tindsymflags): tregister;
  2437. var
  2438. l: tasmsymbol;
  2439. ref: treference;
  2440. nlsymname: string;
  2441. symtyp: TAsmsymtype;
  2442. begin
  2443. result := NR_NO;
  2444. case target_info.system of
  2445. system_powerpc_darwin,
  2446. system_i386_darwin,
  2447. system_i386_iphonesim,
  2448. system_powerpc64_darwin,
  2449. system_arm_darwin:
  2450. begin
  2451. nlsymname:='L'+symname+'$non_lazy_ptr';
  2452. l:=current_asmdata.getasmsymbol(nlsymname);
  2453. if not(assigned(l)) then
  2454. begin
  2455. if is_data in flags then
  2456. symtyp:=AT_DATA
  2457. else
  2458. symtyp:=AT_FUNCTION;
  2459. new_section(current_asmdata.asmlists[al_picdata],sec_data_nonlazy,'',sizeof(pint));
  2460. l:=current_asmdata.DefineAsmSymbol(nlsymname,AB_LOCAL,AT_DATA,voidpointertype);
  2461. current_asmdata.asmlists[al_picdata].concat(tai_symbol.create(l,0));
  2462. if not(is_weak in flags) then
  2463. current_asmdata.asmlists[al_picdata].concat(tai_directive.Create(asd_indirect_symbol,current_asmdata.RefAsmSymbol(symname,symtyp).Name))
  2464. else
  2465. current_asmdata.asmlists[al_picdata].concat(tai_directive.Create(asd_indirect_symbol,current_asmdata.WeakRefAsmSymbol(symname,symtyp).Name));
  2466. {$ifdef cpu64bitaddr}
  2467. current_asmdata.asmlists[al_picdata].concat(tai_const.create_64bit(0));
  2468. {$else cpu64bitaddr}
  2469. current_asmdata.asmlists[al_picdata].concat(tai_const.create_32bit(0));
  2470. {$endif cpu64bitaddr}
  2471. end;
  2472. result := getaddressregister(list);
  2473. reference_reset_symbol(ref,l,0,sizeof(pint),[]);
  2474. { a_load_ref_reg will turn this into a pic-load if needed }
  2475. a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,result);
  2476. end;
  2477. end;
  2478. end;
  2479. procedure tcg.g_maybe_got_init(list: TAsmList);
  2480. begin
  2481. end;
  2482. procedure tcg.g_maybe_tls_init(list: TAsmList);
  2483. begin
  2484. end;
  2485. procedure tcg.g_call(list: TAsmList;const s: string);
  2486. begin
  2487. allocallcpuregisters(list);
  2488. a_call_name(list,s,false);
  2489. deallocallcpuregisters(list);
  2490. end;
  2491. procedure tcg.g_local_unwind(list: TAsmList; l: TAsmLabel);
  2492. begin
  2493. a_jmp_always(list,l);
  2494. end;
  2495. procedure tcg.a_loadmm_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister; shuffle: pmmshuffle);
  2496. begin
  2497. internalerror(200807231);
  2498. end;
  2499. procedure tcg.a_loadmm_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister; shuffle: pmmshuffle);
  2500. begin
  2501. internalerror(200807232);
  2502. end;
  2503. procedure tcg.a_loadmm_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference; shuffle: pmmshuffle);
  2504. begin
  2505. internalerror(200807233);
  2506. end;
  2507. procedure tcg.a_opmm_reg_reg(list: TAsmList; Op: TOpCG; size: tcgsize; src, dst: tregister; shuffle: pmmshuffle);
  2508. begin
  2509. internalerror(200807234);
  2510. end;
  2511. function tcg.getflagregister(list: TAsmList; size: Tcgsize): Tregister;
  2512. begin
  2513. Result:=TRegister(0);
  2514. internalerror(200807238);
  2515. end;
  2516. procedure tcg.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister);
  2517. begin
  2518. internalerror(2014070601);
  2519. end;
  2520. procedure tcg.g_stackpointer_alloc(list: TAsmList; size: longint);
  2521. begin
  2522. internalerror(2014070602);
  2523. end;
  2524. procedure tcg.a_mul_reg_reg_pair(list: TAsmList; size: TCgSize; src1,src2,dstlo,dsthi: TRegister);
  2525. begin
  2526. internalerror(2014060801);
  2527. end;
  2528. procedure tcg.g_div_const_reg_reg(list:tasmlist; size: TCgSize; a: tcgint; src,dst: tregister);
  2529. var
  2530. divreg: tregister;
  2531. magic: aInt;
  2532. u_magic: aWord;
  2533. u_shift: byte;
  2534. u_add: boolean;
  2535. begin
  2536. divreg:=getintregister(list,OS_INT);
  2537. if (size in [OS_S32,OS_S64]) then
  2538. begin
  2539. calc_divconst_magic_signed(tcgsize2size[size]*8,a,magic,u_shift);
  2540. { load magic value }
  2541. a_load_const_reg(list,OS_INT,magic,divreg);
  2542. { multiply, discarding low bits }
  2543. a_mul_reg_reg_pair(list,size,src,divreg,NR_NO,dst);
  2544. { add/subtract numerator }
  2545. if (a>0) and (magic<0) then
  2546. a_op_reg_reg_reg(list,OP_ADD,OS_INT,src,dst,dst)
  2547. else if (a<0) and (magic>0) then
  2548. a_op_reg_reg_reg(list,OP_SUB,OS_INT,src,dst,dst);
  2549. { shift shift places to the right (arithmetic) }
  2550. a_op_const_reg_reg(list,OP_SAR,OS_INT,u_shift,dst,dst);
  2551. { extract and add sign bit }
  2552. if (a>=0) then
  2553. a_op_const_reg_reg(list,OP_SHR,OS_INT,tcgsize2size[size]*8-1,src,divreg)
  2554. else
  2555. a_op_const_reg_reg(list,OP_SHR,OS_INT,tcgsize2size[size]*8-1,dst,divreg);
  2556. a_op_reg_reg_reg(list,OP_ADD,OS_INT,dst,divreg,dst);
  2557. end
  2558. else if (size in [OS_32,OS_64]) then
  2559. begin
  2560. calc_divconst_magic_unsigned(tcgsize2size[size]*8,a,u_magic,u_add,u_shift);
  2561. { load magic in divreg }
  2562. a_load_const_reg(list,OS_INT,tcgint(u_magic),divreg);
  2563. { multiply, discarding low bits }
  2564. a_mul_reg_reg_pair(list,size,src,divreg,NR_NO,dst);
  2565. if (u_add) then
  2566. begin
  2567. { Calculate "(numerator+result) shr u_shift", avoiding possible overflow }
  2568. a_op_reg_reg_reg(list,OP_SUB,OS_INT,dst,src,divreg);
  2569. { divreg=(numerator-result) }
  2570. a_op_const_reg_reg(list,OP_SHR,OS_INT,1,divreg,divreg);
  2571. { divreg=(numerator-result)/2 }
  2572. a_op_reg_reg_reg(list,OP_ADD,OS_INT,divreg,dst,divreg);
  2573. { divreg=(numerator+result)/2, already shifted by 1, so decrease u_shift. }
  2574. a_op_const_reg_reg(list,OP_SHR,OS_INT,u_shift-1,divreg,dst);
  2575. end
  2576. else
  2577. a_op_const_reg_reg(list,OP_SHR,OS_INT,u_shift,dst,dst);
  2578. end
  2579. else
  2580. InternalError(2014060601);
  2581. end;
  2582. procedure tcg.g_check_for_fpu_exception(list: TAsmList);
  2583. begin
  2584. { empty by default }
  2585. end;
  2586. {*****************************************************************************
  2587. TCG64
  2588. *****************************************************************************}
  2589. {$ifndef cpu64bitalu}
  2590. function joinreg64(reglo,reghi : tregister) : tregister64;
  2591. begin
  2592. result.reglo:=reglo;
  2593. result.reghi:=reghi;
  2594. end;
  2595. procedure tcg64.a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64; regsrc,regdst : tregister64);
  2596. begin
  2597. a_load64_reg_reg(list,regsrc,regdst);
  2598. a_op64_const_reg(list,op,size,value,regdst);
  2599. end;
  2600. procedure tcg64.a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
  2601. var
  2602. tmpreg64 : tregister64;
  2603. begin
  2604. { when src1=dst then we need to first create a temp to prevent
  2605. overwriting src1 with src2 }
  2606. if (regsrc1.reghi=regdst.reghi) or
  2607. (regsrc1.reglo=regdst.reghi) or
  2608. (regsrc1.reghi=regdst.reglo) or
  2609. (regsrc1.reglo=regdst.reglo) then
  2610. begin
  2611. tmpreg64.reglo:=cg.getintregister(list,OS_32);
  2612. tmpreg64.reghi:=cg.getintregister(list,OS_32);
  2613. a_load64_reg_reg(list,regsrc2,tmpreg64);
  2614. a_op64_reg_reg(list,op,size,regsrc1,tmpreg64);
  2615. a_load64_reg_reg(list,tmpreg64,regdst);
  2616. end
  2617. else
  2618. begin
  2619. a_load64_reg_reg(list,regsrc2,regdst);
  2620. a_op64_reg_reg(list,op,size,regsrc1,regdst);
  2621. end;
  2622. end;
  2623. procedure tcg64.a_op64_const_subsetref(list : TAsmList; Op : TOpCG; size : TCGSize; a : int64; const sref: tsubsetreference);
  2624. var
  2625. tmpreg64 : tregister64;
  2626. begin
  2627. tmpreg64.reglo:=cg.getintregister(list,OS_32);
  2628. tmpreg64.reghi:=cg.getintregister(list,OS_32);
  2629. a_load64_subsetref_reg(list,sref,tmpreg64);
  2630. a_op64_const_reg(list,op,size,a,tmpreg64);
  2631. a_load64_reg_subsetref(list,tmpreg64,sref);
  2632. end;
  2633. procedure tcg64.a_op64_reg_subsetref(list : TAsmList; Op : TOpCG; size : TCGSize; reg: tregister64; const sref: tsubsetreference);
  2634. var
  2635. tmpreg64 : tregister64;
  2636. begin
  2637. tmpreg64.reglo:=cg.getintregister(list,OS_32);
  2638. tmpreg64.reghi:=cg.getintregister(list,OS_32);
  2639. a_load64_subsetref_reg(list,sref,tmpreg64);
  2640. a_op64_reg_reg(list,op,size,reg,tmpreg64);
  2641. a_load64_reg_subsetref(list,tmpreg64,sref);
  2642. end;
  2643. procedure tcg64.a_op64_ref_subsetref(list : TAsmList; Op : TOpCG; size : TCGSize; const ref: treference; const sref: tsubsetreference);
  2644. var
  2645. tmpreg64 : tregister64;
  2646. begin
  2647. tmpreg64.reglo:=cg.getintregister(list,OS_32);
  2648. tmpreg64.reghi:=cg.getintregister(list,OS_32);
  2649. a_load64_subsetref_reg(list,sref,tmpreg64);
  2650. a_op64_ref_reg(list,op,size,ref,tmpreg64);
  2651. a_load64_reg_subsetref(list,tmpreg64,sref);
  2652. end;
  2653. procedure tcg64.a_op64_subsetref_subsetref(list : TAsmList; Op : TOpCG; size : TCGSize; const ssref,dsref: tsubsetreference);
  2654. var
  2655. tmpreg64 : tregister64;
  2656. begin
  2657. tmpreg64.reglo:=cg.getintregister(list,OS_32);
  2658. tmpreg64.reghi:=cg.getintregister(list,OS_32);
  2659. a_load64_subsetref_reg(list,ssref,tmpreg64);
  2660. a_op64_reg_subsetref(list,op,size,tmpreg64,dsref);
  2661. end;
  2662. procedure tcg64.a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  2663. begin
  2664. a_op64_const_reg_reg(list,op,size,value,regsrc,regdst);
  2665. ovloc.loc:=LOC_VOID;
  2666. end;
  2667. procedure tcg64.a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  2668. begin
  2669. a_op64_reg_reg_reg(list,op,size,regsrc1,regsrc2,regdst);
  2670. ovloc.loc:=LOC_VOID;
  2671. end;
  2672. procedure tcg64.a_load64_loc_subsetref(list : TAsmList;const l: tlocation; const sref : tsubsetreference);
  2673. begin
  2674. case l.loc of
  2675. LOC_REFERENCE, LOC_CREFERENCE:
  2676. a_load64_ref_subsetref(list,l.reference,sref);
  2677. LOC_REGISTER,LOC_CREGISTER:
  2678. a_load64_reg_subsetref(list,l.register64,sref);
  2679. LOC_CONSTANT :
  2680. a_load64_const_subsetref(list,l.value64,sref);
  2681. LOC_SUBSETREF,LOC_CSUBSETREF:
  2682. a_load64_subsetref_subsetref(list,l.sref,sref);
  2683. else
  2684. internalerror(2006082210);
  2685. end;
  2686. end;
  2687. procedure tcg64.a_load64_subsetref_loc(list: TAsmlist; const sref: tsubsetreference; const l: tlocation);
  2688. begin
  2689. case l.loc of
  2690. LOC_REFERENCE, LOC_CREFERENCE:
  2691. a_load64_subsetref_ref(list,sref,l.reference);
  2692. LOC_REGISTER,LOC_CREGISTER:
  2693. a_load64_subsetref_reg(list,sref,l.register64);
  2694. LOC_SUBSETREF,LOC_CSUBSETREF:
  2695. a_load64_subsetref_subsetref(list,sref,l.sref);
  2696. else
  2697. internalerror(2006082211);
  2698. end;
  2699. end;
  2700. {$else cpu64bitalu}
  2701. function joinreg128(reglo, reghi: tregister): tregister128;
  2702. begin
  2703. result.reglo:=reglo;
  2704. result.reghi:=reghi;
  2705. end;
  2706. procedure splitparaloc128(const cgpara:tcgpara;var cgparalo,cgparahi:tcgpara);
  2707. var
  2708. paraloclo,
  2709. paralochi : pcgparalocation;
  2710. begin
  2711. if not(cgpara.size in [OS_128,OS_S128]) then
  2712. internalerror(2012090604);
  2713. if not assigned(cgpara.location) then
  2714. internalerror(2012090605);
  2715. { init lo/hi para }
  2716. cgparahi.reset;
  2717. if cgpara.size=OS_S128 then
  2718. cgparahi.size:=OS_S64
  2719. else
  2720. cgparahi.size:=OS_64;
  2721. cgparahi.intsize:=8;
  2722. cgparahi.alignment:=cgpara.alignment;
  2723. paralochi:=cgparahi.add_location;
  2724. cgparalo.reset;
  2725. cgparalo.size:=OS_64;
  2726. cgparalo.intsize:=8;
  2727. cgparalo.alignment:=cgpara.alignment;
  2728. paraloclo:=cgparalo.add_location;
  2729. { 2 parameter fields? }
  2730. if assigned(cgpara.location^.next) then
  2731. begin
  2732. { Order for multiple locations is always
  2733. paraloc^ -> high
  2734. paraloc^.next -> low }
  2735. if (target_info.endian=ENDIAN_BIG) then
  2736. begin
  2737. { paraloc^ -> high
  2738. paraloc^.next -> low }
  2739. move(cgpara.location^,paralochi^,sizeof(paralochi^));
  2740. move(cgpara.location^.next^,paraloclo^,sizeof(paraloclo^));
  2741. end
  2742. else
  2743. begin
  2744. { paraloc^ -> low
  2745. paraloc^.next -> high }
  2746. move(cgpara.location^,paraloclo^,sizeof(paraloclo^));
  2747. move(cgpara.location^.next^,paralochi^,sizeof(paralochi^));
  2748. end;
  2749. end
  2750. else
  2751. begin
  2752. { single parameter, this can only be in memory }
  2753. if cgpara.location^.loc<>LOC_REFERENCE then
  2754. internalerror(2012090606);
  2755. move(cgpara.location^,paraloclo^,sizeof(paraloclo^));
  2756. move(cgpara.location^,paralochi^,sizeof(paralochi^));
  2757. { for big endian low is at +8, for little endian high }
  2758. if target_info.endian = endian_big then
  2759. begin
  2760. inc(cgparalo.location^.reference.offset,8);
  2761. cgparalo.alignment:=newalignment(cgparalo.alignment,8);
  2762. end
  2763. else
  2764. begin
  2765. inc(cgparahi.location^.reference.offset,8);
  2766. cgparahi.alignment:=newalignment(cgparahi.alignment,8);
  2767. end;
  2768. end;
  2769. { fix size }
  2770. paraloclo^.size:=cgparalo.size;
  2771. paraloclo^.next:=nil;
  2772. paralochi^.size:=cgparahi.size;
  2773. paralochi^.next:=nil;
  2774. end;
  2775. procedure tcg128.a_load128_reg_reg(list: TAsmList; regsrc,
  2776. regdst: tregister128);
  2777. begin
  2778. cg.a_load_reg_reg(list,OS_64,OS_64,regsrc.reglo,regdst.reglo);
  2779. cg.a_load_reg_reg(list,OS_64,OS_64,regsrc.reghi,regdst.reghi);
  2780. end;
  2781. procedure tcg128.a_load128_reg_ref(list: TAsmList; reg: tregister128;
  2782. const ref: treference);
  2783. var
  2784. tmpreg: tregister;
  2785. tmpref: treference;
  2786. begin
  2787. if target_info.endian = endian_big then
  2788. begin
  2789. tmpreg:=reg.reglo;
  2790. reg.reglo:=reg.reghi;
  2791. reg.reghi:=tmpreg;
  2792. end;
  2793. cg.a_load_reg_ref(list,OS_64,OS_64,reg.reglo,ref);
  2794. tmpref := ref;
  2795. inc(tmpref.offset,8);
  2796. cg.a_load_reg_ref(list,OS_64,OS_64,reg.reghi,tmpref);
  2797. end;
  2798. procedure tcg128.a_load128_ref_reg(list: TAsmList; const ref: treference;
  2799. reg: tregister128);
  2800. var
  2801. tmpreg: tregister;
  2802. tmpref: treference;
  2803. begin
  2804. if target_info.endian = endian_big then
  2805. begin
  2806. tmpreg := reg.reglo;
  2807. reg.reglo := reg.reghi;
  2808. reg.reghi := tmpreg;
  2809. end;
  2810. tmpref := ref;
  2811. if (tmpref.base=reg.reglo) then
  2812. begin
  2813. tmpreg:=cg.getaddressregister(list);
  2814. cg.a_load_reg_reg(list,OS_ADDR,OS_ADDR,tmpref.base,tmpreg);
  2815. tmpref.base:=tmpreg;
  2816. end
  2817. else
  2818. { this works only for the i386, thus the i386 needs to override }
  2819. { this method and this method must be replaced by a more generic }
  2820. { implementation FK }
  2821. if (tmpref.index=reg.reglo) then
  2822. begin
  2823. tmpreg:=cg.getaddressregister(list);
  2824. cg.a_load_reg_reg(list,OS_ADDR,OS_ADDR,tmpref.index,tmpreg);
  2825. tmpref.index:=tmpreg;
  2826. end;
  2827. cg.a_load_ref_reg(list,OS_64,OS_64,tmpref,reg.reglo);
  2828. inc(tmpref.offset,8);
  2829. cg.a_load_ref_reg(list,OS_64,OS_64,tmpref,reg.reghi);
  2830. end;
  2831. procedure tcg128.a_load128_loc_ref(list: TAsmList; const l: tlocation;
  2832. const ref: treference);
  2833. begin
  2834. case l.loc of
  2835. LOC_REGISTER,LOC_CREGISTER:
  2836. a_load128_reg_ref(list,l.register128,ref);
  2837. { not yet implemented:
  2838. LOC_CONSTANT :
  2839. a_load128_const_ref(list,l.value128,ref);
  2840. LOC_SUBSETREF, LOC_CSUBSETREF:
  2841. a_load64_subsetref_ref(list,l.sref,ref); }
  2842. else
  2843. internalerror(201209061);
  2844. end;
  2845. end;
  2846. procedure tcg128.a_load128_reg_loc(list: TAsmList; reg: tregister128;
  2847. const l: tlocation);
  2848. begin
  2849. case l.loc of
  2850. LOC_REFERENCE, LOC_CREFERENCE:
  2851. a_load128_reg_ref(list,reg,l.reference);
  2852. LOC_REGISTER,LOC_CREGISTER:
  2853. a_load128_reg_reg(list,reg,l.register128);
  2854. { not yet implemented:
  2855. LOC_SUBSETREF, LOC_CSUBSETREF:
  2856. a_load64_reg_subsetref(list,reg,l.sref);
  2857. LOC_MMREGISTER, LOC_CMMREGISTER:
  2858. a_loadmm_intreg64_reg(list,l.size,reg,l.register); }
  2859. else
  2860. internalerror(201209062);
  2861. end;
  2862. end;
  2863. procedure tcg128.a_load128_const_reg(list: TAsmList; valuelo,
  2864. valuehi: int64; reg: tregister128);
  2865. begin
  2866. cg.a_load_const_reg(list,OS_64,aint(valuelo),reg.reglo);
  2867. cg.a_load_const_reg(list,OS_64,aint(valuehi),reg.reghi);
  2868. end;
  2869. procedure tcg128.a_load128_loc_cgpara(list: TAsmList; const l: tlocation;
  2870. const paraloc: TCGPara);
  2871. begin
  2872. case l.loc of
  2873. LOC_REGISTER,
  2874. LOC_CREGISTER :
  2875. a_load128_reg_cgpara(list,l.register128,paraloc);
  2876. {not yet implemented:
  2877. LOC_CONSTANT :
  2878. a_load128_const_cgpara(list,l.value64,paraloc);
  2879. }
  2880. LOC_CREFERENCE,
  2881. LOC_REFERENCE :
  2882. a_load128_ref_cgpara(list,l.reference,paraloc);
  2883. else
  2884. internalerror(2012090603);
  2885. end;
  2886. end;
  2887. procedure tcg128.a_load128_reg_cgpara(list : TAsmList;reg : tregister128;const paraloc : tcgpara);
  2888. var
  2889. tmplochi,tmploclo: tcgpara;
  2890. begin
  2891. tmploclo.init;
  2892. tmplochi.init;
  2893. splitparaloc128(paraloc,tmploclo,tmplochi);
  2894. cg.a_load_reg_cgpara(list,OS_64,reg.reghi,tmplochi);
  2895. cg.a_load_reg_cgpara(list,OS_64,reg.reglo,tmploclo);
  2896. tmploclo.done;
  2897. tmplochi.done;
  2898. end;
  2899. procedure tcg128.a_load128_ref_cgpara(list : TAsmList;const r : treference;const paraloc : tcgpara);
  2900. var
  2901. tmprefhi,tmpreflo : treference;
  2902. tmploclo,tmplochi : tcgpara;
  2903. begin
  2904. tmploclo.init;
  2905. tmplochi.init;
  2906. splitparaloc128(paraloc,tmploclo,tmplochi);
  2907. tmprefhi:=r;
  2908. tmpreflo:=r;
  2909. if target_info.endian=endian_big then
  2910. inc(tmpreflo.offset,8)
  2911. else
  2912. inc(tmprefhi.offset,8);
  2913. cg.a_load_ref_cgpara(list,OS_64,tmprefhi,tmplochi);
  2914. cg.a_load_ref_cgpara(list,OS_64,tmpreflo,tmploclo);
  2915. tmploclo.done;
  2916. tmplochi.done;
  2917. end;
  2918. {$endif cpu64bitalu}
  2919. function asmsym2indsymflags(sym: TAsmSymbol): tindsymflags;
  2920. begin
  2921. result:=[];
  2922. if sym.typ<>AT_FUNCTION then
  2923. include(result,is_data);
  2924. if sym.bind=AB_WEAK_EXTERNAL then
  2925. include(result,is_weak);
  2926. end;
  2927. procedure destroy_codegen;
  2928. begin
  2929. cg.free;
  2930. cg:=nil;
  2931. {$ifdef cpu64bitalu}
  2932. cg128.free;
  2933. cg128:=nil;
  2934. {$else cpu64bitalu}
  2935. cg64.free;
  2936. cg64:=nil;
  2937. {$endif cpu64bitalu}
  2938. end;
  2939. end.