cgobj.pas 144 KB

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