hlcgllvm.pas 80 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035
  1. {
  2. Copyright (c) 2010, 2013 by Jonas Maebe
  3. Member of the Free Pascal development team
  4. This unit implements the LLVM high level code generator
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit hlcgllvm;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. globtype,cclasses,
  23. aasmbase,aasmdata,
  24. symbase,symconst,symtype,symdef,symsym,
  25. cpubase, hlcgobj, cgbase, cgutils, parabase, tgobj;
  26. type
  27. { thlcgllvm }
  28. thlcgllvm = class(thlcgobj)
  29. constructor create;
  30. procedure temp_to_ref(p: ptemprecord; out ref: treference); override;
  31. procedure a_load_ref_cgpara(list: TAsmList; size: tdef; const r: treference; const cgpara: TCGPara); override;
  32. procedure a_load_const_cgpara(list: TAsmList; tosize: tdef; a: tcgint; const cgpara: TCGPara); override;
  33. protected
  34. procedure a_load_ref_cgpara_init_src(list: TAsmList; const para: tcgpara; const initialref: treference; var refsize: tdef; out newref: treference);
  35. public
  36. procedure getcpuregister(list: TAsmList; r: Tregister); override;
  37. procedure ungetcpuregister(list: TAsmList; r: Tregister); override;
  38. procedure alloccpuregisters(list: TAsmList; rt: Tregistertype; const r: Tcpuregisterset); override;
  39. procedure deallocallcpuregisters(list: TAsmList); override;
  40. procedure a_bit_test_reg_reg_reg(list: TAsmList; bitnumbersize, valuesize, destsize: tdef; bitnumber, value, destreg: tregister); override;
  41. procedure a_bit_set_reg_reg(list: TAsmList; doset: boolean; bitnumbersize, destsize: tdef; bitnumber, dest: tregister); override;
  42. protected
  43. procedure a_call_common(list: TAsmList; pd: tabstractprocdef; const paras: array of pcgpara; const forceresdef: tdef; out res: tregister; out hlretdef: tdef; out llvmretdef: tdef; out callparas: tfplist);
  44. public
  45. function a_call_name(list : TAsmList;pd : tprocdef;const s : TSymStr; const paras: array of pcgpara; forceresdef: tdef; weak: boolean): tcgpara;override;
  46. function a_call_reg(list: TAsmList; pd: tabstractprocdef; reg: tregister; const paras: array of pcgpara): tcgpara; override;
  47. procedure a_load_const_reg(list : TAsmList;tosize : tdef;a : tcgint;register : tregister);override;
  48. procedure a_load_const_ref(list: TAsmList; tosize: tdef; a: tcgint; const ref: treference);override;
  49. procedure a_load_reg_ref(list : TAsmList;fromsize, tosize : tdef;register : tregister;const ref : treference);override;
  50. procedure a_load_reg_reg(list : TAsmList;fromsize, tosize : tdef;reg1,reg2 : tregister);override;
  51. protected
  52. procedure gen_load_refaddrfull_anyreg(list: TAsmList; fromsize, tosize : tdef; const simpleref: treference; register: tregister; shuffle: pmmshuffle);
  53. function handle_agg_load_ref_anyreg(list: TasmList; var fromsize, tosize: tdef; var simpleref: treference; register: tregister; shuffle: pmmshuffle): boolean;
  54. public
  55. procedure a_load_ref_reg(list : TAsmList;fromsize, tosize : tdef;const ref : treference;register : tregister);override;
  56. procedure a_load_ref_ref(list: TAsmList; fromsize, tosize: tdef; const sref: treference; const dref: treference); override;
  57. protected
  58. procedure a_loadaddr_ref_reg_intern(list : TAsmList;fromsize, tosize : tdef;const ref : treference;r : tregister; makefromsizepointer: boolean);
  59. public
  60. procedure a_loadaddr_ref_reg(list : TAsmList;fromsize, tosize : tdef;const ref : treference;r : tregister);override;
  61. procedure a_op_const_reg(list: TAsmList; Op: TOpCG; size: tdef; a: tcgint; reg: TRegister); override;
  62. procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tdef; a: tcgint; src, dst: tregister); override;
  63. procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tdef; src1, src2, dst: tregister); override;
  64. procedure a_op_reg_reg(list: TAsmList; Op: TOpCG; size: tdef; reg1, reg2: TRegister); override;
  65. procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tdef; a: tcgint; src, dst: tregister;setflags : boolean;var ovloc : tlocation); override;
  66. procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tdef; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation); override;
  67. procedure a_cmp_const_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel); override;
  68. procedure a_cmp_reg_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel); override;
  69. procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
  70. procedure g_concatcopy(list : TAsmList;size: tdef; const source,dest : treference);override;
  71. procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; reg: tregister); override;
  72. procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tdef; reg: tregister; const ref: treference); override;
  73. procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister); override;
  74. procedure gen_proc_symbol(list: TAsmList); override;
  75. procedure gen_proc_symbol_end(list: TAsmList); override;
  76. procedure handle_external_proc(list: TAsmList; pd: tprocdef; const importname: TSymStr); override;
  77. procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean); override;
  78. procedure g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean); override;
  79. protected
  80. procedure gen_load_uninitialized_function_result(list: TAsmList; pd: tprocdef; resdef: tdef; const resloc: tcgpara); override;
  81. public
  82. procedure g_overflowcheck(list: TAsmList; const Loc: tlocation; def: tdef); override;
  83. procedure g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;var ovloc : tlocation); override;
  84. procedure g_ptrtypecast_reg(list: TAsmList; fromdef, todef: tdef; var reg: tregister); override;
  85. procedure g_ptrtypecast_ref(list: TAsmList; fromdef, todef: tdef; var ref: treference); override;
  86. procedure g_set_addr_nonbitpacked_field_ref(list: TAsmList; recdef: tabstractrecorddef; field: tfieldvarsym; var recref: treference); override;
  87. procedure a_loadmm_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; reg: tregister; shuffle: pmmshuffle); override;
  88. procedure a_loadmm_reg_ref(list: TAsmList; fromsize, tosize: tdef; reg: tregister; const ref: treference; shuffle: pmmshuffle); override;
  89. procedure a_loadmm_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister; shuffle: pmmshuffle); override;
  90. procedure a_opmm_reg_reg(list: TAsmList; Op: TOpCG; size: tdef; src, dst: tregister; shuffle: pmmshuffle); override;
  91. procedure a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize: tdef; intreg, mmreg: tregister; shuffle: pmmshuffle); override;
  92. procedure a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize: tdef; mmreg, intreg: tregister; shuffle: pmmshuffle); override;
  93. function get_call_result_cgpara(pd: tabstractprocdef; forceresdef: tdef): tcgpara; override;
  94. protected
  95. procedure gen_load_loc_function_result(list: TAsmList; vardef: tdef; const l: tlocation); override;
  96. public
  97. procedure gen_load_loc_cgpara(list: TAsmList; vardef: tdef; const l: tlocation; const cgpara: tcgpara); override;
  98. procedure gen_load_cgpara_loc(list: TAsmList; vardef: tdef; const para: TCGPara; var destloc: tlocation; reusepara: boolean); override;
  99. {$ifdef cpuflags}
  100. { llvm doesn't have flags, but cpuflags is defined in case the real cpu
  101. has flags and we have to override the abstract methods to prevent
  102. warnings }
  103. procedure a_jmp_flags(list: TAsmList; const f: TResFlags; l: tasmlabel); override;
  104. procedure g_flags2reg(list: TAsmList; size: tdef; const f: tresflags; reg: TRegister); override;
  105. procedure g_flags2ref(list: TAsmList; size: tdef; const f: tresflags; const ref: TReference); override;
  106. {$endif cpuflags}
  107. { unimplemented or unnecessary routines }
  108. procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tdef; src, dst: tregister); override;
  109. procedure g_stackpointer_alloc(list: TAsmList; size: longint); override;
  110. procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint); override;
  111. procedure g_adjust_self_value(list: TAsmList; procdef: tprocdef; ioffset: aint); override;
  112. procedure g_local_unwind(list: TAsmList; l: TAsmLabel); override;
  113. procedure gen_stack_check_size_para(list: TAsmList); override;
  114. procedure gen_stack_check_call(list: TAsmList); override;
  115. procedure varsym_set_localloc(list: TAsmList; vs: tabstractnormalvarsym); override;
  116. procedure paravarsym_set_initialloc_to_paraloc(vs: tparavarsym); override;
  117. procedure g_external_wrapper(list: TAsmList; procdef: tprocdef; const externalname: string); override;
  118. { def is a pointerdef or implicit pointer type (class, classref, procvar,
  119. dynamic array, ...). }
  120. function make_simple_ref_ptr(list: TAsmList; const ref: treference; ptrdef: tdef): treference;
  121. { def is the type of the data stored in memory pointed to by ref, not
  122. a pointer to this type }
  123. function make_simple_ref(list: TAsmList; const ref: treference; def: tdef): treference;
  124. protected
  125. procedure paraloctoloc(const paraloc: pcgparalocation; out hloc: tlocation);
  126. procedure set_call_function_result(const list: TAsmList; const pd: tabstractprocdef; const llvmretdef, hlretdef: tdef; const resval: tregister; var retpara: tcgpara);
  127. end;
  128. procedure create_hlcodegen;
  129. implementation
  130. uses
  131. verbose,cutils,globals,fmodule,constexp,systems,
  132. defutil,llvmdef,llvmsym,
  133. aasmtai,aasmcpu,
  134. aasmllvm,llvmbase,tgllvm,
  135. symtable,symllvm,
  136. paramgr,llvmpara,
  137. procinfo,cpuinfo,cgobj,cgllvm,cghlcpu,
  138. cgcpu,hlcgcpu;
  139. const
  140. topcg2llvmop: array[topcg] of tllvmop =
  141. { OP_NONE OP_MOVE OP_ADD OP_AND OP_DIV OP_IDIV OP_IMUL OP_MUL }
  142. (la_none, la_none, la_add, la_and, la_udiv, la_sdiv, la_mul, la_mul,
  143. { OP_NEG OP_NOT OP_OR OP_SAR OP_SHL OP_SHR OP_SUB OP_XOR }
  144. la_none, la_none, la_or, la_ashr, la_shl, la_lshr, la_sub, la_xor,
  145. { OP_ROL OP_ROR }
  146. la_none, la_none);
  147. constructor thlcgllvm.create;
  148. begin
  149. inherited
  150. end;
  151. procedure thlcgllvm.temp_to_ref(p: ptemprecord; out ref: treference);
  152. begin
  153. { on the LLVM target, every temp is independent and encoded via a
  154. separate temp register whose superregister number is stored in p^.pos }
  155. reference_reset_base(ref,voidstackpointertype,newreg(R_TEMPREGISTER,p^.pos,R_SUBWHOLE),0,p^.alignment);
  156. end;
  157. procedure thlcgllvm.a_load_ref_cgpara(list: TAsmList; size: tdef; const r: treference; const cgpara: TCGPara);
  158. var
  159. tmpref, initialref, ref: treference;
  160. fielddef,
  161. orgsize: tdef;
  162. location: pcgparalocation;
  163. sizeleft,
  164. totaloffset: asizeint;
  165. paralocidx: longint;
  166. userecord: boolean;
  167. begin
  168. location:=cgpara.location;
  169. sizeleft:=cgpara.intsize;
  170. totaloffset:=0;
  171. orgsize:=size;
  172. a_load_ref_cgpara_init_src(list,cgpara,r,size,initialref);
  173. userecord:=
  174. (orgsize<>size) and
  175. assigned(cgpara.location^.next);
  176. paralocidx:=0;
  177. while assigned(location) do
  178. begin
  179. if userecord then
  180. begin
  181. { llvmparadef is a record in this case, with every field
  182. corresponding to a single paraloc (fielddef is unused, because
  183. it will be equivalent to location^.def -- see below) }
  184. g_setup_load_field_by_name(list,trecorddef(size),'F'+tostr(paralocidx),initialref,tmpref,fielddef);
  185. end
  186. else
  187. tmpref:=initialref;
  188. paramanager.allocparaloc(list,location);
  189. case location^.loc of
  190. LOC_REGISTER,LOC_CREGISTER:
  191. begin
  192. { byval parameter -> load the address rather than the value }
  193. if not location^.llvmvalueloc then
  194. a_loadaddr_ref_reg(list,tpointerdef(location^.def).pointeddef,location^.def,tmpref,location^.register)
  195. { if this parameter is split into multiple paralocs via
  196. record fields, load the current paraloc. The type of the
  197. paraloc and of the current record field will match by
  198. construction (the record is build from the paraloc
  199. types) }
  200. else if userecord then
  201. a_load_ref_reg(list,location^.def,location^.def,tmpref,location^.register)
  202. { if the parameter is passed in a single paraloc, the
  203. paraloc's type may be different from the declared type
  204. -> use the original complete parameter size as source so
  205. we can insert a type conversion if necessary }
  206. else
  207. a_load_ref_reg(list,size,location^.def,tmpref,location^.register)
  208. end;
  209. LOC_REFERENCE,LOC_CREFERENCE:
  210. begin
  211. if assigned(location^.next) then
  212. internalerror(2010052906);
  213. reference_reset_base(ref,cpointerdef.getreusable(size),location^.reference.index,location^.reference.offset,newalignment(cgpara.alignment,cgpara.intsize-sizeleft));
  214. if (def_cgsize(size)<>OS_NO) and
  215. (size.size=sizeleft) and
  216. (sizeleft<=sizeof(aint)) then
  217. a_load_ref_ref(list,size,location^.def,tmpref,ref)
  218. else
  219. { use concatcopy, because the parameter can be larger than }
  220. { what the OS_* constants can handle }
  221. g_concatcopy(list,location^.def,tmpref,ref);
  222. end;
  223. LOC_MMREGISTER,LOC_CMMREGISTER:
  224. begin
  225. case location^.size of
  226. OS_F32,
  227. OS_F64,
  228. OS_F128:
  229. a_loadmm_ref_reg(list,location^.def,location^.def,tmpref,location^.register,mms_movescalar);
  230. OS_M8..OS_M128,
  231. OS_MS8..OS_MS128,
  232. OS_32..OS_128,
  233. { OS_NO is for records of non-power-of-two sizes that have to
  234. be passed in MM registers -> never scalar floats }
  235. OS_NO:
  236. a_loadmm_ref_reg(list,location^.def,location^.def,tmpref,location^.register,nil);
  237. else
  238. internalerror(2010053101);
  239. end;
  240. end
  241. else
  242. internalerror(2010053111);
  243. end;
  244. inc(totaloffset,tcgsize2size[location^.size]);
  245. dec(sizeleft,tcgsize2size[location^.size]);
  246. location:=location^.next;
  247. inc(paralocidx);
  248. end;
  249. end;
  250. procedure thlcgllvm.a_load_const_cgpara(list: TAsmList; tosize: tdef; a: tcgint; const cgpara: TCGPara);
  251. begin
  252. if is_ordinal(cgpara.def) then
  253. begin
  254. cgpara.check_simple_location;
  255. paramanager.alloccgpara(list,cgpara);
  256. if cgpara.location^.shiftval<0 then
  257. a:=a shl -cgpara.location^.shiftval;
  258. cgpara.location^.llvmloc.loc:=LOC_CONSTANT;
  259. cgpara.location^.llvmloc.value:=a;
  260. end
  261. else
  262. inherited;
  263. end;
  264. procedure thlcgllvm.a_load_ref_cgpara_init_src(list: TAsmList; const para: tcgpara; const initialref: treference; var refsize: tdef; out newref: treference);
  265. var
  266. newrefsize: tdef;
  267. reg: tregister;
  268. begin
  269. newrefsize:=llvmgetcgparadef(para,true);
  270. if refsize<>newrefsize then
  271. begin
  272. reg:=getaddressregister(list,cpointerdef.getreusable(newrefsize));
  273. a_loadaddr_ref_reg(list,refsize,cpointerdef.getreusable(newrefsize),initialref,reg);
  274. reference_reset_base(newref,cpointerdef.getreusable(newrefsize),reg,0,initialref.alignment);
  275. refsize:=newrefsize;
  276. end
  277. else
  278. newref:=initialref;
  279. end;
  280. procedure thlcgllvm.getcpuregister(list: TAsmList; r: Tregister);
  281. begin
  282. { don't do anything }
  283. end;
  284. procedure thlcgllvm.ungetcpuregister(list: TAsmList; r: Tregister);
  285. begin
  286. { don't do anything }
  287. end;
  288. procedure thlcgllvm.alloccpuregisters(list: TAsmList; rt: Tregistertype; const r: Tcpuregisterset);
  289. begin
  290. { don't do anything }
  291. end;
  292. procedure thlcgllvm.deallocallcpuregisters(list: TAsmList);
  293. begin
  294. { don't do anything }
  295. end;
  296. procedure thlcgllvm.a_bit_test_reg_reg_reg(list: TAsmList; bitnumbersize, valuesize, destsize: tdef; bitnumber, value, destreg: tregister);
  297. var
  298. tmpbitnumberreg: tregister;
  299. begin
  300. { unlike other architectures, llvm requires the bitnumber register to
  301. have the same size as the shifted register }
  302. if bitnumbersize.size<>valuesize.size then
  303. begin
  304. tmpbitnumberreg:=hlcg.getintregister(list,valuesize);
  305. a_load_reg_reg(list,bitnumbersize,valuesize,bitnumber,tmpbitnumberreg);
  306. bitnumbersize:=valuesize;
  307. bitnumber:=tmpbitnumberreg;
  308. end;
  309. inherited;
  310. end;
  311. procedure thlcgllvm.a_bit_set_reg_reg(list: TAsmList; doset: boolean; bitnumbersize, destsize: tdef; bitnumber, dest: tregister);
  312. var
  313. tmpbitnumberreg: tregister;
  314. begin
  315. { unlike other architectures, llvm requires the bitnumber register to
  316. have the same size as the shifted register }
  317. if bitnumbersize.size<>destsize.size then
  318. begin
  319. tmpbitnumberreg:=hlcg.getintregister(list,destsize);
  320. a_load_reg_reg(list,bitnumbersize,destsize,bitnumber,tmpbitnumberreg);
  321. bitnumbersize:=destsize;
  322. bitnumber:=tmpbitnumberreg;
  323. end;
  324. inherited;
  325. end;
  326. function get_call_pd(pd: tabstractprocdef): tdef;
  327. begin
  328. if (pd.typ=procdef) or
  329. not pd.is_addressonly then
  330. { we get a pointerdef rather than a procvardef so that if we have to
  331. insert an external declaration for this procdef in llvmtype, we don't
  332. have to create another procdef from the procvardef we've just created.
  333. With a pointerdef, we can just get the pointeddef again. A pointerdef
  334. is also much cheaper to create, and in llvm a provardef is a "function
  335. pointer", so a pointer to a procdef is the same as a procvar as far
  336. as llvm is concerned }
  337. result:=cpointerdef.getreusable(pd)
  338. else
  339. result:=pd
  340. end;
  341. procedure thlcgllvm.a_call_common(list: TAsmList; pd: tabstractprocdef; const paras: array of pcgpara; const forceresdef: tdef; out res: tregister; out hlretdef: tdef; out llvmretdef: tdef; out callparas: tfplist);
  342. procedure load_ref_anyreg(def: tdef; const ref: treference; reg: tregister; var callpara: pllvmcallpara);
  343. begin
  344. case getregtype(reg) of
  345. R_INTREGISTER,
  346. R_ADDRESSREGISTER:
  347. begin
  348. a_load_ref_reg(list,def,def,ref,reg);
  349. callpara^.loc:=LOC_REGISTER;
  350. end;
  351. R_FPUREGISTER:
  352. begin
  353. a_loadfpu_ref_reg(list,def,def,ref,reg);
  354. callpara^.loc:=LOC_FPUREGISTER;
  355. end;
  356. R_MMREGISTER:
  357. begin
  358. a_loadmm_ref_reg(list,def,def,ref,reg,mms_movescalar);
  359. callpara^.loc:=LOC_MMREGISTER;
  360. end;
  361. else
  362. internalerror(2014012213);
  363. end;
  364. end;
  365. var
  366. i: longint;
  367. href: treference;
  368. callpara: pllvmcallpara;
  369. paraloc: pcgparalocation;
  370. begin
  371. callparas:=tfplist.Create;
  372. for i:=0 to high(paras) do
  373. begin
  374. paraloc:=paras[i]^.location;
  375. while assigned(paraloc) and
  376. (paraloc^.loc<>LOC_VOID) do
  377. begin
  378. new(callpara);
  379. callpara^.def:=paraloc^.def;
  380. llvmextractvalueextinfo(paras[i]^.def, callpara^.def, callpara^.valueext);
  381. if paraloc^.llvmloc.loc=LOC_CONSTANT then
  382. begin
  383. callpara^.loc:=LOC_CONSTANT;
  384. callpara^.value:=paraloc^.llvmloc.value;
  385. end
  386. else
  387. begin
  388. callpara^.loc:=paraloc^.loc;
  389. case callpara^.loc of
  390. LOC_REFERENCE:
  391. begin
  392. if paraloc^.llvmvalueloc then
  393. internalerror(2014012307)
  394. else
  395. begin
  396. reference_reset_base(href, cpointerdef.getreusable(callpara^.def), paraloc^.reference.index, paraloc^.reference.offset, paraloc^.def.alignment);
  397. res:=getregisterfordef(list, paraloc^.def);
  398. load_ref_anyreg(callpara^.def, href, res, callpara);
  399. end;
  400. callpara^.reg:=res
  401. end;
  402. LOC_REGISTER,
  403. LOC_FPUREGISTER,
  404. LOC_MMREGISTER:
  405. begin
  406. { undo explicit value extension }
  407. if callpara^.valueext<>lve_none then
  408. begin
  409. res:=getregisterfordef(list, callpara^.def);
  410. a_load_reg_reg(list, paraloc^.def, callpara^.def, paraloc^.register, res);
  411. paraloc^.register:=res;
  412. end;
  413. callpara^.reg:=paraloc^.register
  414. end;
  415. else
  416. internalerror(2014010605);
  417. end;
  418. end;
  419. callparas.add(callpara);
  420. paraloc:=paraloc^.next;
  421. end;
  422. end;
  423. { the Pascal level may expect a different returndef compared to the
  424. declared one }
  425. if not assigned(forceresdef) then
  426. hlretdef:=pd.returndef
  427. else
  428. hlretdef:=forceresdef;
  429. { llvm will always expect the original return def }
  430. if not paramanager.ret_in_param(hlretdef, pd) then
  431. llvmretdef:=llvmgetcgparadef(pd.funcretloc[callerside], true)
  432. else
  433. llvmretdef:=voidtype;
  434. if not is_void(llvmretdef) then
  435. res:=getregisterfordef(list, llvmretdef)
  436. else
  437. res:=NR_NO;
  438. { if this is a complex procvar, get the non-tmethod-like equivalent }
  439. if (pd.typ=procvardef) and
  440. not pd.is_addressonly then
  441. pd:=tprocvardef(cprocvardef.getreusableprocaddr(pd));
  442. end;
  443. function thlcgllvm.a_call_name(list: TAsmList; pd: tprocdef; const s: TSymStr; const paras: array of pcgpara; forceresdef: tdef; weak: boolean): tcgpara;
  444. var
  445. callparas: tfplist;
  446. llvmretdef,
  447. hlretdef: tdef;
  448. res: tregister;
  449. begin
  450. a_call_common(list,pd,paras,forceresdef,res,hlretdef,llvmretdef,callparas);
  451. list.concat(taillvm.call_size_name_paras(get_call_pd(pd),res,llvmretdef,current_asmdata.RefAsmSymbol(s),callparas));
  452. result:=get_call_result_cgpara(pd,forceresdef);
  453. set_call_function_result(list,pd,llvmretdef,hlretdef,res,result);
  454. end;
  455. function thlcgllvm.a_call_reg(list: TAsmList; pd: tabstractprocdef; reg: tregister; const paras: array of pcgpara): tcgpara;
  456. var
  457. callparas: tfplist;
  458. llvmretdef,
  459. hlretdef: tdef;
  460. res: tregister;
  461. begin
  462. a_call_common(list,pd,paras,nil,res,hlretdef,llvmretdef,callparas);
  463. list.concat(taillvm.call_size_reg_paras(get_call_pd(pd),res,llvmretdef,reg,callparas));
  464. result:=get_call_result_cgpara(pd,nil);
  465. set_call_function_result(list,pd,llvmretdef,hlretdef,res,result);
  466. end;
  467. procedure thlcgllvm.a_load_const_reg(list: TAsmList; tosize: tdef; a: tcgint; register: tregister);
  468. begin
  469. list.concat(taillvm.op_reg_size_const_size(llvmconvop(ptrsinttype,tosize,false),register,ptrsinttype,a,tosize))
  470. end;
  471. procedure thlcgllvm.a_load_const_ref(list: TAsmList; tosize: tdef; a: tcgint; const ref: treference);
  472. var
  473. sref: treference;
  474. begin
  475. { llvm instructions do not support pointer constants -> only directly
  476. encode for integers; a_load_const_reg() handles pointers properly }
  477. if is_ordinal(tosize) or
  478. is_64bit(tosize) then
  479. begin
  480. sref:=make_simple_ref(list,ref,tosize);
  481. list.concat(taillvm.op_size_const_size_ref(la_store,tosize,a,cpointerdef.getreusable(tosize),sref))
  482. end
  483. else
  484. inherited;
  485. end;
  486. function def2intdef(fromsize, tosize: tdef): tdef;
  487. begin
  488. { we cannot zero-extend from/to anything but ordinal/enum
  489. types }
  490. if not(tosize.typ in [orddef,enumdef]) then
  491. internalerror(2014012305);
  492. { will give an internalerror if def_cgsize() returns OS_NO, which is
  493. what we want }
  494. result:=cgsize_orddef(def_cgsize(fromsize));
  495. end;
  496. procedure thlcgllvm.a_load_reg_ref(list: TAsmList; fromsize, tosize: tdef; register: tregister; const ref: treference);
  497. var
  498. tmpref,
  499. sref: treference;
  500. hreg,
  501. hreg2: tregister;
  502. tmpsize: tdef;
  503. begin
  504. sref:=make_simple_ref(list,ref,tosize);
  505. hreg:=register;
  506. (* typecast the pointer to the value instead of the value itself if
  507. they have the same size but are of different kinds, because we can't
  508. e.g. typecast a loaded <{i32, i32}> to an i64 *)
  509. if (llvmaggregatetype(fromsize) or
  510. llvmaggregatetype(tosize)) and
  511. (fromsize<>tosize) then
  512. begin
  513. if fromsize.size>tosize.size then
  514. begin
  515. { if source size is larger than the target size, we have to
  516. truncate it before storing. Unfortunately, we cannot truncate
  517. records (nor bitcast them to integers), so we first have to
  518. store them to memory and then bitcast the pointer to them
  519. We can't truncate an integer to 3/5/6/7 bytes either, so also
  520. pass via a temp in that case
  521. }
  522. if (fromsize.typ in [arraydef,recorddef]) or
  523. (tosize.size in [3,5,6,7]) then
  524. begin
  525. { store struct/array-in-register to memory }
  526. tg.gethltemp(list,fromsize,fromsize.size,tt_normal,tmpref);
  527. a_load_reg_ref(list,fromsize,fromsize,register,tmpref);
  528. { typecast pointer to memory into pointer to integer type }
  529. hreg:=getaddressregister(list,cpointerdef.getreusable(tosize));
  530. a_loadaddr_ref_reg(list,fromsize,cpointerdef.getreusable(tosize),tmpref,hreg);
  531. reference_reset_base(sref,cpointerdef.getreusable(tosize),hreg,0,tmpref.alignment);
  532. { load the integer from the temp into the destination }
  533. a_load_ref_ref(list,tosize,tosize,sref,ref);
  534. tg.ungettemp(list,tmpref);
  535. end
  536. else
  537. begin
  538. tmpsize:=def2intdef(tosize,fromsize);
  539. hreg:=getintregister(list,tmpsize);
  540. { truncate the integer }
  541. a_load_reg_reg(list,fromsize,tmpsize,register,hreg);
  542. { store it to memory (it will now be of the same size as the
  543. struct, and hence another path will be followed in this
  544. method) }
  545. a_load_reg_ref(list,tmpsize,tosize,hreg,sref);
  546. end;
  547. exit;
  548. end
  549. else
  550. begin
  551. hreg2:=getaddressregister(list,cpointerdef.getreusable(fromsize));
  552. a_loadaddr_ref_reg(list,tosize,cpointerdef.getreusable(fromsize),sref,hreg2);
  553. reference_reset_base(sref,cpointerdef.getreusable(fromsize),hreg2,0,sref.alignment);
  554. tosize:=fromsize;
  555. end;
  556. end
  557. else if fromsize<>tosize then
  558. begin
  559. hreg:=getregisterfordef(list,tosize);
  560. a_load_reg_reg(list,fromsize,tosize,register,hreg);
  561. end;
  562. list.concat(taillvm.op_size_reg_size_ref(la_store,tosize,hreg,cpointerdef.getreusable(tosize),sref));
  563. end;
  564. procedure thlcgllvm.a_load_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister);
  565. var
  566. op: tllvmop;
  567. tmpreg: tregister;
  568. tmpintdef: tdef;
  569. begin
  570. op:=llvmconvop(fromsize,tosize,true);
  571. { converting from pointer to something else and vice versa is only
  572. possible via an intermediate pass to integer. Same for "something else"
  573. to pointer. }
  574. case op of
  575. la_ptrtoint_to_x,
  576. la_x_to_inttoptr:
  577. begin
  578. { convert via an integer with the same size as "x" }
  579. if op=la_ptrtoint_to_x then
  580. begin
  581. tmpintdef:=cgsize_orddef(def_cgsize(tosize));
  582. op:=la_bitcast
  583. end
  584. else
  585. begin
  586. tmpintdef:=cgsize_orddef(def_cgsize(fromsize));
  587. op:=la_inttoptr;
  588. end;
  589. tmpreg:=getintregister(list,tmpintdef);
  590. a_load_reg_reg(list,fromsize,tmpintdef,reg1,tmpreg);
  591. reg1:=tmpreg;
  592. fromsize:=tmpintdef;
  593. end;
  594. end;
  595. { reg2 = bitcast fromsize reg1 to tosize }
  596. list.concat(taillvm.op_reg_size_reg_size(op,reg2,fromsize,reg1,tosize));
  597. end;
  598. procedure thlcgllvm.gen_load_refaddrfull_anyreg(list: TAsmList; fromsize, tosize: tdef; const simpleref: treference; register: tregister; shuffle: pmmshuffle);
  599. var
  600. tmpref,
  601. tmpref2: treference;
  602. begin
  603. { can't bitcast records/arrays }
  604. if (llvmaggregatetype(fromsize) or
  605. llvmaggregatetype(tosize)) and
  606. (fromsize<>tosize) then
  607. begin
  608. if fromsize.size>tosize.size then
  609. begin
  610. tg.gethltemp(list,fromsize,fromsize.size,tt_normal,tmpref);
  611. tmpref2:=tmpref;
  612. g_ptrtypecast_ref(list,cpointerdef.getreusable(fromsize),cpointerdef.getreusable(tosize),tmpref2);
  613. end
  614. else
  615. begin
  616. tg.gethltemp(list,tosize,tosize.size,tt_normal,tmpref);
  617. tmpref2:=tmpref;
  618. g_ptrtypecast_ref(list,cpointerdef.getreusable(tosize),cpointerdef.getreusable(fromsize),tmpref);
  619. end;
  620. list.concat(taillvm.op_size_ref_size_ref(la_store,fromsize,simpleref,cpointerdef.getreusable(fromsize),tmpref));
  621. case getregtype(register) of
  622. R_INTREGISTER,
  623. R_ADDRESSREGISTER:
  624. a_load_ref_reg(list,tosize,tosize,tmpref2,register);
  625. R_FPUREGISTER:
  626. a_loadfpu_ref_reg(list,tosize,tosize,tmpref2,register);
  627. R_MMREGISTER:
  628. a_loadmm_ref_reg(list,tosize,tosize,tmpref2,register,shuffle);
  629. else
  630. internalerror(2016061901);
  631. end;
  632. tg.ungettemp(list,tmpref);
  633. end
  634. else
  635. list.concat(taillvm.op_reg_size_ref_size(llvmconvop(fromsize,tosize,false),register,fromsize,simpleref,tosize))
  636. end;
  637. function thlcgllvm.handle_agg_load_ref_anyreg(list: TasmList; var fromsize, tosize: tdef; var simpleref: treference; register: tregister; shuffle: pmmshuffle): boolean;
  638. var
  639. tmpref,
  640. tmpref2: treference;
  641. firstshuffle: pmmshuffle;
  642. begin
  643. if fromsize.size<tosize.size then
  644. begin
  645. { allocate a temp of size tosize, typecast it to the
  646. (smaller) fromsize, load the source in it, and then
  647. load the destination from it. The extra bits will contain
  648. garbage, but they should never be used. }
  649. tg.gethltemp(list,tosize,tosize.size,tt_persistent,tmpref);
  650. tmpref2:=tmpref;
  651. g_ptrtypecast_ref(list,cpointerdef.getreusable(tosize),cpointerdef.getreusable(fromsize),tmpref2);
  652. case getregtype(register) of
  653. R_INTREGISTER,
  654. R_ADDRESSREGISTER:
  655. begin
  656. a_load_ref_ref(list,fromsize,fromsize,simpleref,tmpref2);
  657. a_load_ref_reg(list,tosize,tosize,tmpref,register);
  658. end;
  659. R_FPUREGISTER:
  660. begin
  661. a_loadfpu_ref_ref(list,fromsize,fromsize,simpleref,tmpref2);
  662. a_loadfpu_ref_reg(list,tosize,tosize,tmpref,register);
  663. end;
  664. R_MMREGISTER:
  665. begin
  666. { don't shuffle twice }
  667. if shuffle=mms_movescalar then
  668. firstshuffle:=shuffle
  669. else
  670. firstshuffle:=nil;
  671. a_loadmm_ref_ref(list,fromsize,fromsize,simpleref,tmpref2,firstshuffle);
  672. a_loadmm_ref_reg(list,tosize,tosize,tmpref,register,shuffle);
  673. end;
  674. end;
  675. tg.ungettemp(list,tmpref);
  676. result:=true;
  677. end
  678. else
  679. begin
  680. (* typecast the pointer to the value instead of the value
  681. itself if tosize<=fromsize but they are of different
  682. kinds, because we can't e.g. bitcast a loaded <{i32, i32}>
  683. to an i64 *)
  684. g_ptrtypecast_ref(list,cpointerdef.getreusable(fromsize),cpointerdef.getreusable(tosize),simpleref);
  685. fromsize:=tosize;
  686. result:=false;
  687. end;
  688. end;
  689. procedure thlcgllvm.a_load_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; register: tregister);
  690. var
  691. sref: treference;
  692. hreg: tregister;
  693. begin
  694. sref:=make_simple_ref(list,ref,fromsize);
  695. { "named register"? }
  696. if sref.refaddr=addr_full then
  697. gen_load_refaddrfull_anyreg(list,fromsize,tosize,sref,register,nil)
  698. else
  699. begin
  700. if ((fromsize.typ in [arraydef,recorddef]) or
  701. (tosize.typ in [arraydef,recorddef])) and
  702. (fromsize<>tosize) then
  703. begin
  704. if handle_agg_load_ref_anyreg(list,fromsize,tosize,sref,register,nil) then
  705. exit;
  706. end;
  707. hreg:=register;
  708. if fromsize<>tosize then
  709. hreg:=getregisterfordef(list,fromsize);
  710. list.concat(taillvm.op_reg_size_ref(la_load,hreg,cpointerdef.getreusable(fromsize),sref));
  711. if hreg<>register then
  712. a_load_reg_reg(list,fromsize,tosize,hreg,register);
  713. end;
  714. end;
  715. procedure thlcgllvm.a_load_ref_ref(list: TAsmList; fromsize, tosize: tdef; const sref: treference; const dref: treference);
  716. var
  717. sdref: treference;
  718. begin
  719. if (fromsize=tosize) and
  720. (sref.refaddr=addr_full) then
  721. begin
  722. sdref:=make_simple_ref(list,dref,tosize);
  723. list.concat(taillvm.op_size_ref_size_ref(la_store,fromsize,sref,cpointerdef.getreusable(tosize),sdref));
  724. end
  725. else
  726. inherited
  727. end;
  728. procedure thlcgllvm.a_loadaddr_ref_reg_intern(list: TAsmList; fromsize, tosize: tdef; const ref: treference; r: tregister; makefromsizepointer: boolean);
  729. var
  730. sref: treference;
  731. begin
  732. { can't take the address of a 'named register' }
  733. if ref.refaddr=addr_full then
  734. internalerror(2013102306);
  735. if makefromsizepointer then
  736. fromsize:=cpointerdef.getreusable(fromsize);
  737. sref:=make_simple_ref_ptr(list,ref,fromsize);
  738. list.concat(taillvm.op_reg_size_ref_size(la_bitcast,r,fromsize,sref,tosize));
  739. end;
  740. procedure thlcgllvm.a_loadaddr_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; r: tregister);
  741. begin
  742. a_loadaddr_ref_reg_intern(list,fromsize,tosize,ref,r,true);
  743. end;
  744. procedure thlcgllvm.a_op_const_reg(list: TAsmList; Op: TOpCG; size: tdef; a: tcgint; reg: TRegister);
  745. begin
  746. a_op_const_reg_reg(list,op,size,a,reg,reg);
  747. end;
  748. procedure thlcgllvm.a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tdef; a: tcgint; src, dst: tregister);
  749. var
  750. tmpreg: tregister;
  751. begin
  752. if (def2regtyp(size)=R_INTREGISTER) and
  753. (topcg2llvmop[op]<>la_none) then
  754. list.concat(taillvm.op_reg_size_reg_const(topcg2llvmop[op],dst,size,src,a))
  755. else
  756. begin
  757. { default implementation is not SSA-safe }
  758. tmpreg:=getregisterfordef(list,size);
  759. a_load_const_reg(list,size,a,tmpreg);
  760. a_op_reg_reg_reg(list,op,size,tmpreg,src,dst);
  761. end;
  762. end;
  763. procedure thlcgllvm.a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tdef; src1, src2, dst: tregister);
  764. var
  765. orgdst,
  766. tmpreg1,
  767. tmpreg2,
  768. tmpreg3: tregister;
  769. opsize: tdef;
  770. begin
  771. orgdst:=dst;
  772. opsize:=size;
  773. { always perform using integer registers, because math operations on
  774. pointers are not supported (except via getelementptr, possible future
  775. optimization) }
  776. if def2regtyp(size)=R_ADDRESSREGISTER then
  777. begin
  778. opsize:=ptruinttype;
  779. tmpreg1:=getintregister(list,ptruinttype);
  780. a_load_reg_reg(list,size,ptruinttype,src1,tmpreg1);
  781. src1:=tmpreg1;
  782. tmpreg1:=getintregister(list,ptruinttype);
  783. a_load_reg_reg(list,size,ptruinttype,src2,tmpreg1);
  784. src2:=tmpreg1;
  785. dst:=getintregister(list,ptruinttype);
  786. end;
  787. if topcg2llvmop[op]<>la_none then
  788. list.concat(taillvm.op_reg_size_reg_reg(topcg2llvmop[op],dst,opsize,src2,src1))
  789. else
  790. begin
  791. case op of
  792. OP_NEG:
  793. { %dst = sub size 0, %src1 }
  794. list.concat(taillvm.op_reg_size_const_reg(la_sub,dst,opsize,0,src1));
  795. OP_NOT:
  796. { %dst = xor size -1, %src1 }
  797. list.concat(taillvm.op_reg_size_const_reg(la_xor,dst,opsize,-1,src1));
  798. OP_ROL:
  799. begin
  800. tmpreg1:=getintregister(list,opsize);
  801. tmpreg2:=getintregister(list,opsize);
  802. tmpreg3:=getintregister(list,opsize);
  803. { tmpreg1 := (tcgsize2size[size]*8 - (src1 and (tcgsize2size[size]*8-1) }
  804. list.concat(taillvm.op_reg_size_const_reg(la_and,tmpreg1,opsize,opsize.size*8-1,src1));
  805. list.concat(taillvm.op_reg_size_const_reg(la_sub,tmpreg2,opsize,opsize.size*8,tmpreg1));
  806. { tmpreg3 := src2 shr tmpreg2 }
  807. a_op_reg_reg_reg(list,OP_SHR,opsize,tmpreg2,src2,tmpreg3);
  808. { tmpreg2:= src2 shl tmpreg1 }
  809. tmpreg2:=getintregister(list,opsize);
  810. a_op_reg_reg_reg(list,OP_SHL,opsize,tmpreg1,src2,tmpreg2);
  811. { dst := tmpreg2 or tmpreg3 }
  812. a_op_reg_reg_reg(list,OP_OR,opsize,tmpreg2,tmpreg3,dst);
  813. end;
  814. OP_ROR:
  815. begin
  816. tmpreg1:=getintregister(list,size);
  817. tmpreg2:=getintregister(list,size);
  818. tmpreg3:=getintregister(list,size);
  819. { tmpreg1 := (tcgsize2size[size]*8 - (src1 and (tcgsize2size[size]*8-1) }
  820. list.concat(taillvm.op_reg_size_const_reg(la_and,tmpreg1,opsize,opsize.size*8-1,src1));
  821. list.concat(taillvm.op_reg_size_const_reg(la_sub,tmpreg2,opsize,opsize.size*8,tmpreg1));
  822. { tmpreg3 := src2 shl tmpreg2 }
  823. a_op_reg_reg_reg(list,OP_SHL,opsize,tmpreg2,src2,tmpreg3);
  824. { tmpreg2:= src2 shr tmpreg1 }
  825. tmpreg2:=getintregister(list,opsize);
  826. a_op_reg_reg_reg(list,OP_SHR,opsize,tmpreg1,src2,tmpreg2);
  827. { dst := tmpreg2 or tmpreg3 }
  828. a_op_reg_reg_reg(list,OP_OR,opsize,tmpreg2,tmpreg3,dst);
  829. end;
  830. else
  831. internalerror(2010081310);
  832. end;
  833. end;
  834. if dst<>orgdst then
  835. a_load_reg_reg(list,opsize,size,dst,orgdst);
  836. end;
  837. procedure thlcgllvm.a_op_reg_reg(list: TAsmList; Op: TOpCG; size: tdef; reg1, reg2: TRegister);
  838. begin
  839. a_op_reg_reg_reg(list,op,size,reg1,reg2,reg2);
  840. end;
  841. procedure thlcgllvm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tdef; a: tcgint; src, dst: tregister; setflags: boolean; var ovloc: tlocation);
  842. var
  843. hreg: tregister;
  844. begin
  845. if not setflags then
  846. begin
  847. inherited;
  848. exit;
  849. end;
  850. hreg:=getintregister(list,size);
  851. a_load_const_reg(list,size,a,hreg);
  852. a_op_reg_reg_reg_checkoverflow(list,op,size,hreg,src,dst,setflags,ovloc);
  853. end;
  854. procedure thlcgllvm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tdef; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation);
  855. var
  856. calcsize: tdef;
  857. tmpsrc1,
  858. tmpsrc2,
  859. tmpdst: tregister;
  860. signed,
  861. docheck: boolean;
  862. begin
  863. docheck:=size.size>=ossinttype.size;
  864. if not setflags or
  865. not docheck then
  866. begin
  867. inherited a_op_reg_reg_reg_checkoverflow(list,op,size,src1,src2,dst,false,ovloc);
  868. exit;
  869. end;
  870. { extend values to twice their original width (one bit extra is enough,
  871. but adding support for 9/17/33/65 bit types just for this is overkill) }
  872. signed:=is_signed(size);
  873. case size.size of
  874. 1:
  875. if signed then
  876. calcsize:=s16inttype
  877. else
  878. calcsize:=u16inttype;
  879. 2:
  880. if signed then
  881. calcsize:=s32inttype
  882. else
  883. calcsize:=u32inttype;
  884. 4:
  885. if signed then
  886. calcsize:=s64inttype
  887. else
  888. calcsize:=u64inttype;
  889. 8:
  890. if signed then
  891. calcsize:=s128inttype
  892. else
  893. calcsize:=u128inttype;
  894. else
  895. internalerror(2015122503);
  896. end;
  897. tmpsrc1:=getintregister(list,calcsize);
  898. a_load_reg_reg(list,size,calcsize,src1,tmpsrc1);
  899. tmpsrc2:=getintregister(list,calcsize);
  900. a_load_reg_reg(list,size,calcsize,src2,tmpsrc2);
  901. tmpdst:=getintregister(list,calcsize);
  902. { perform the calculation with twice the width }
  903. a_op_reg_reg_reg(list,op,calcsize,tmpsrc1,tmpsrc2,tmpdst);
  904. { signed/unsigned overflow occurs if signed/unsigned truncation of the
  905. result is different from the actual result -> extend again and compare }
  906. a_load_reg_reg(list,calcsize,size,tmpdst,dst);
  907. tmpsrc1:=getintregister(list,calcsize);
  908. a_load_reg_reg(list,size,calcsize,dst,tmpsrc1);
  909. location_reset(ovloc,LOC_REGISTER,OS_8);
  910. ovloc.register:=getintregister(list,llvmbool1type);
  911. list.concat(taillvm.op_reg_cond_size_reg_reg(la_icmp,ovloc.register,OC_NE,calcsize,tmpsrc1,tmpdst));
  912. end;
  913. procedure thlcgllvm.a_cmp_const_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);
  914. var
  915. tmpreg : tregister;
  916. invert: boolean;
  917. fallthroughlab, falselab, tmplab: tasmlabel;
  918. begin
  919. { since all comparisons return their results in a register, we'll often
  920. get comparisons against true/false -> optimise }
  921. if (size=pasbool8type) and
  922. (cmp_op in [OC_EQ,OC_NE]) then
  923. begin
  924. { convert to an llvmbool1type and use directly }
  925. tmpreg:=getintregister(list,llvmbool1type);
  926. a_load_reg_reg(list,size,llvmbool1type,reg,tmpreg);
  927. case cmp_op of
  928. OC_EQ:
  929. invert:=a=0;
  930. OC_NE:
  931. invert:=a=1;
  932. else
  933. { avoid uninitialised warning }
  934. internalerror(2015031504);
  935. end;
  936. current_asmdata.getjumplabel(falselab);
  937. fallthroughlab:=falselab;
  938. if invert then
  939. begin
  940. tmplab:=l;
  941. l:=falselab;
  942. falselab:=tmplab;
  943. end;
  944. list.concat(taillvm.op_size_reg_lab_lab(la_br,llvmbool1type,tmpreg,l,falselab));
  945. a_label(list,fallthroughlab);
  946. exit;
  947. end;
  948. tmpreg:=getregisterfordef(list,size);
  949. a_load_const_reg(list,size,a,tmpreg);
  950. a_cmp_reg_reg_label(list,size,cmp_op,tmpreg,reg,l);
  951. end;
  952. procedure thlcgllvm.a_cmp_reg_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel);
  953. var
  954. resreg: tregister;
  955. falselab: tasmlabel;
  956. begin
  957. if getregtype(reg1)<>getregtype(reg2) then
  958. internalerror(2012111105);
  959. resreg:=getintregister(list,llvmbool1type);
  960. current_asmdata.getjumplabel(falselab);
  961. { invert order of registers. In FPC, cmp_reg_reg(reg1,reg2) means that
  962. e.g. OC_GT is true if "subl %reg1,%reg2" in x86 AT&T is >0. In LLVM,
  963. OC_GT is true if op1>op2 }
  964. list.concat(taillvm.op_reg_cond_size_reg_reg(la_icmp,resreg,cmp_op,size,reg2,reg1));
  965. list.concat(taillvm.op_size_reg_lab_lab(la_br,llvmbool1type,resreg,l,falselab));
  966. a_label(list,falselab);
  967. end;
  968. procedure thlcgllvm.a_jmp_always(list: TAsmList; l: tasmlabel);
  969. begin
  970. { implement in tcg because required by the overridden a_label; doesn't use
  971. any high level stuff anyway }
  972. cg.a_jmp_always(list,l);
  973. end;
  974. procedure thlcgllvm.g_concatcopy(list: TAsmList; size: tdef; const source, dest: treference);
  975. var
  976. pd: tprocdef;
  977. sourcepara, destpara, sizepara, alignpara, volatilepara: tcgpara;
  978. maxalign: longint;
  979. begin
  980. { perform small copies directly; not larger ones, because then llvm
  981. will try to load the entire large datastructure into registers and
  982. starts spilling like crazy; too small copies must not be done via
  983. llvm.memcpy either, because then you get crashes in llvm }
  984. if (size.typ in [orddef,floatdef,enumdef]) or
  985. (size.size<=2*sizeof(aint)) then
  986. begin
  987. a_load_ref_ref(list,size,size,source,dest);
  988. exit;
  989. end;
  990. pd:=search_system_proc('llvm_memcpy64');
  991. sourcepara.init;
  992. destpara.init;
  993. sizepara.init;
  994. alignpara.init;
  995. volatilepara.init;
  996. paramanager.getintparaloc(list,pd,1,destpara);
  997. paramanager.getintparaloc(list,pd,2,sourcepara);
  998. paramanager.getintparaloc(list,pd,3,sizepara);
  999. paramanager.getintparaloc(list,pd,4,alignpara);
  1000. paramanager.getintparaloc(list,pd,5,volatilepara);
  1001. a_loadaddr_ref_cgpara(list,size,dest,destpara);
  1002. a_loadaddr_ref_cgpara(list,size,source,sourcepara);
  1003. a_load_const_cgpara(list,u64inttype,size.size,sizepara);
  1004. maxalign:=newalignment(source.alignment,dest.alignment);
  1005. a_load_const_cgpara(list,u32inttype,maxalign,alignpara);
  1006. { we don't know anything about volatility here, should become an extra
  1007. parameter to g_concatcopy }
  1008. a_load_const_cgpara(list,llvmbool1type,0,volatilepara);
  1009. g_call_system_proc(list,pd,[@destpara,@sourcepara,@sizepara,@alignpara,@volatilepara],nil).resetiftemp;
  1010. sourcepara.done;
  1011. destpara.done;
  1012. sizepara.done;
  1013. alignpara.done;
  1014. volatilepara.done;
  1015. end;
  1016. procedure thlcgllvm.a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; reg: tregister);
  1017. var
  1018. tmpreg: tregister;
  1019. href: treference;
  1020. fromcompcurr,
  1021. tocompcurr: boolean;
  1022. begin
  1023. href:=make_simple_ref(list,ref,fromsize);
  1024. { named register -> use generic code }
  1025. if ref.refaddr=addr_full then
  1026. begin
  1027. gen_load_refaddrfull_anyreg(list,fromsize,tosize,href,reg,mms_movescalar);
  1028. exit
  1029. end;
  1030. { comp and currency are handled by the x87 in this case. They cannot
  1031. be represented directly in llvm, and llvmdef translates them into i64
  1032. (since that's their storage size and internally they also are int64).
  1033. Solve this by changing the type to s80real once they are loaded into
  1034. a register. }
  1035. fromcompcurr:=tfloatdef(fromsize).floattype in [s64comp,s64currency];
  1036. tocompcurr:=tfloatdef(tosize).floattype in [s64comp,s64currency];
  1037. if tocompcurr then
  1038. tosize:=s80floattype;
  1039. { don't generate different code for loading e.g. extended into cextended,
  1040. but to take care of loading e.g. comp (=int64) into double }
  1041. if (fromsize.size<>tosize.size) then
  1042. tmpreg:=getfpuregister(list,fromsize)
  1043. else
  1044. tmpreg:=reg;
  1045. { handle aggregate loads (happens if a struct needs to be passed in a
  1046. floating point register) }
  1047. if (fromsize.typ in [arraydef,recorddef]) or
  1048. (tosize.typ in [arraydef,recorddef]) then
  1049. begin
  1050. if handle_agg_load_ref_anyreg(list,fromsize,tosize,href,reg,mms_movescalar) then
  1051. exit;
  1052. end;
  1053. { %tmpreg = load size* %ref }
  1054. list.concat(taillvm.op_reg_size_ref(la_load,tmpreg,cpointerdef.getreusable(fromsize),href));
  1055. if tmpreg<>reg then
  1056. if fromcompcurr then
  1057. { treat as extended as long as it's in a register }
  1058. list.concat(taillvm.op_reg_size_reg_size(la_sitofp,reg,fromsize,tmpreg,tosize))
  1059. else
  1060. a_loadfpu_reg_reg(list,fromsize,tosize,tmpreg,reg);
  1061. end;
  1062. procedure thlcgllvm.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tdef; reg: tregister; const ref: treference);
  1063. var
  1064. tmpreg: tregister;
  1065. href: treference;
  1066. fromcompcurr,
  1067. tocompcurr: boolean;
  1068. begin
  1069. { see comment in a_loadfpu_ref_reg }
  1070. fromcompcurr:=tfloatdef(fromsize).floattype in [s64comp,s64currency];
  1071. tocompcurr:=tfloatdef(tosize).floattype in [s64comp,s64currency];
  1072. if fromcompcurr then
  1073. fromsize:=s80floattype;
  1074. href:=make_simple_ref(list,ref,tosize);
  1075. { don't generate different code for loading e.g. extended into cextended,
  1076. but to take care of storing e.g. comp (=int64) into double }
  1077. if (fromsize.size<>tosize.size) then
  1078. begin
  1079. tmpreg:=getfpuregister(list,tosize);
  1080. if tocompcurr then
  1081. { store back an int64 rather than an extended }
  1082. list.concat(taillvm.op_reg_size_reg_size(la_fptosi,tmpreg,fromsize,reg,tosize))
  1083. else
  1084. a_loadfpu_reg_reg(list,fromsize,tosize,reg,tmpreg);
  1085. end
  1086. else
  1087. tmpreg:=reg;
  1088. { store tosize tmpreg, tosize* href }
  1089. list.concat(taillvm.op_size_reg_size_ref(la_store,tosize,tmpreg,cpointerdef.getreusable(tosize),href));
  1090. end;
  1091. procedure thlcgllvm.a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister);
  1092. var
  1093. op: tllvmop;
  1094. begin
  1095. op:=llvmconvop(fromsize,tosize,true);
  1096. { reg2 = bitcast fromllsize reg1 to tollsize }
  1097. list.concat(taillvm.op_reg_size_reg_size(op,reg2,fromsize,reg1,tosize));
  1098. end;
  1099. procedure thlcgllvm.gen_proc_symbol(list: TAsmList);
  1100. var
  1101. item: TCmdStrListItem;
  1102. mangledname: TSymStr;
  1103. asmsym: tasmsymbol;
  1104. begin
  1105. if po_external in current_procinfo.procdef.procoptions then
  1106. exit;
  1107. item:=TCmdStrListItem(current_procinfo.procdef.aliasnames.first);
  1108. mangledname:=current_procinfo.procdef.mangledname;
  1109. { predefine the real function name as local/global, so the aliases can
  1110. refer to the symbol and get the binding correct }
  1111. if (cs_profile in current_settings.moduleswitches) or
  1112. (po_global in current_procinfo.procdef.procoptions) then
  1113. asmsym:=current_asmdata.DefineAsmSymbol(mangledname,AB_GLOBAL,AT_FUNCTION)
  1114. else
  1115. asmsym:=current_asmdata.DefineAsmSymbol(mangledname,AB_LOCAL,AT_FUNCTION);
  1116. while assigned(item) do
  1117. begin
  1118. if mangledname<>item.Str then
  1119. list.concat(taillvmalias.create(asmsym,item.str,current_procinfo.procdef,asmsym.bind));
  1120. item:=TCmdStrListItem(item.next);
  1121. end;
  1122. list.concat(taillvmdecl.createdef(asmsym,current_procinfo.procdef,nil,sec_code,current_procinfo.procdef.alignment));
  1123. end;
  1124. procedure thlcgllvm.gen_proc_symbol_end(list: TAsmList);
  1125. begin
  1126. list.concat(Tai_symbol_end.Createname(current_procinfo.procdef.mangledname));
  1127. { todo: darwin main proc, or handle in other way? }
  1128. end;
  1129. procedure thlcgllvm.handle_external_proc(list: TAsmList; pd: tprocdef; const importname: TSymStr);
  1130. begin
  1131. { don't do anything, because at this point we can't know yet for certain
  1132. whether the aliased routine is internal to the current routine or not.
  1133. If it's internal, we would have to generate an llvm alias, while if it's
  1134. external, we would have to generate a declaration. Additionally, aliases
  1135. cannot refer to declarations, so always creating aliases doesn't work
  1136. either -> handle in llvmtype }
  1137. end;
  1138. procedure thlcgllvm.g_proc_entry(list: TAsmList; localsize: longint; nostackframe: boolean);
  1139. begin
  1140. list.concatlist(ttgllvm(tg).alloclist)
  1141. { rest: todo }
  1142. end;
  1143. procedure thlcgllvm.g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean);
  1144. var
  1145. retdef: tdef;
  1146. retreg,
  1147. hreg: tregister;
  1148. retpara: tcgpara;
  1149. begin
  1150. { the function result type is the type of the first location, which can
  1151. differ from the real result type (e.g. int64 for a record consisting of
  1152. two longint fields on x86-64 -- we are responsible for lowering the
  1153. result types like that) }
  1154. retpara:=get_call_result_cgpara(current_procinfo.procdef,nil);
  1155. retpara.check_simple_location;
  1156. retdef:=retpara.location^.def;
  1157. if is_void(retdef) or
  1158. { don't check retdef here, it is e.g. a pshortstring in case it's
  1159. shortstring that's returned in a parameter }
  1160. paramanager.ret_in_param(current_procinfo.procdef.returndef,current_procinfo.procdef) then
  1161. list.concat(taillvm.op_size(la_ret,voidtype))
  1162. else
  1163. begin
  1164. case retpara.location^.loc of
  1165. LOC_REGISTER,
  1166. LOC_FPUREGISTER,
  1167. LOC_MMREGISTER:
  1168. begin
  1169. { sign/zeroextension of function results is handled implicitly
  1170. via the signext/zeroext modifiers of the result, rather than
  1171. in the code generator -> remove any explicit extensions here }
  1172. retreg:=retpara.location^.register;
  1173. if (current_procinfo.procdef.returndef.typ in [orddef,enumdef]) and
  1174. (retdef.typ in [orddef,enumdef]) then
  1175. begin
  1176. if (current_procinfo.procdef.returndef.size<retpara.location^.def.size) then
  1177. begin
  1178. hreg:=getintregister(list,current_procinfo.procdef.returndef);
  1179. a_load_reg_reg(list,retdef,current_procinfo.procdef.returndef,retreg,hreg);
  1180. retreg:=hreg;
  1181. retdef:=current_procinfo.procdef.returndef;
  1182. end;
  1183. end;
  1184. list.concat(taillvm.op_size_reg(la_ret,retdef,retreg))
  1185. end;
  1186. LOC_VOID:
  1187. begin
  1188. { zero-sized records: return an undefined zero-sized record of
  1189. the correct type }
  1190. list.concat(taillvm.op_size_undef(la_ret,retdef));
  1191. end
  1192. else
  1193. { todo: complex returns }
  1194. internalerror(2012111106);
  1195. end;
  1196. end;
  1197. retpara.resetiftemp;
  1198. end;
  1199. procedure thlcgllvm.gen_load_uninitialized_function_result(list: TAsmList; pd: tprocdef; resdef: tdef; const resloc: tcgpara);
  1200. begin
  1201. if not paramanager.ret_in_param(resdef,pd) then
  1202. begin
  1203. case resloc.location^.loc of
  1204. LOC_REGISTER,
  1205. LOC_FPUREGISTER,
  1206. LOC_MMREGISTER:
  1207. begin
  1208. if not llvmaggregatetype(resdef) then
  1209. list.concat(taillvm.op_reg_size_undef(la_bitcast,resloc.location^.register,llvmgetcgparadef(resloc,true)))
  1210. else
  1211. { bitcast doesn't work for aggregates -> just load from the
  1212. (uninitialised) function result memory location }
  1213. gen_load_loc_function_result(list,resdef,tabstractnormalvarsym(pd.funcretsym).localloc)
  1214. end;
  1215. { for empty record returns }
  1216. LOC_VOID:
  1217. ;
  1218. else
  1219. internalerror(2015042301);
  1220. end;
  1221. end;
  1222. end;
  1223. procedure thlcgllvm.g_overflowcheck(list: TAsmList; const Loc: tlocation; def: tdef);
  1224. begin
  1225. { not possible, need ovloc }
  1226. internalerror(2012111107);
  1227. end;
  1228. procedure thlcgllvm.g_overflowCheck_loc(List: TAsmList; const Loc: TLocation; def: TDef; var ovloc: tlocation);
  1229. var
  1230. hl: tasmlabel;
  1231. begin
  1232. if not(cs_check_overflow in current_settings.localswitches) then
  1233. exit;
  1234. if ovloc.size<>OS_8 then
  1235. internalerror(2015122504);
  1236. current_asmdata.getjumplabel(hl);
  1237. a_cmp_const_loc_label(list,llvmbool1type,OC_EQ,0,ovloc,hl);
  1238. g_call_system_proc(list,'fpc_overflow',[],nil);
  1239. a_label(list,hl);
  1240. end;
  1241. procedure thlcgllvm.g_ptrtypecast_reg(list: TAsmList; fromdef, todef: tdef; var reg: tregister);
  1242. var
  1243. hreg: tregister;
  1244. begin
  1245. { will insert a bitcast if necessary }
  1246. if fromdef<>todef then
  1247. begin
  1248. hreg:=getregisterfordef(list,todef);
  1249. a_load_reg_reg(list,fromdef,todef,reg,hreg);
  1250. reg:=hreg;
  1251. end;
  1252. end;
  1253. procedure thlcgllvm.g_ptrtypecast_ref(list: TAsmList; fromdef, todef: tdef; var ref: treference);
  1254. var
  1255. hreg: tregister;
  1256. begin
  1257. hreg:=getaddressregister(list,todef);
  1258. a_loadaddr_ref_reg_intern(list,fromdef,todef,ref,hreg,false);
  1259. reference_reset_base(ref,todef,hreg,0,ref.alignment);
  1260. end;
  1261. procedure thlcgllvm.g_set_addr_nonbitpacked_field_ref(list: TAsmList; recdef: tabstractrecorddef; field: tfieldvarsym; var recref: treference);
  1262. var
  1263. parentdef,
  1264. subscriptdef,
  1265. currentstructdef,
  1266. llvmfielddef: tdef;
  1267. newbase: tregister;
  1268. implicitpointer: boolean;
  1269. begin
  1270. implicitpointer:=is_implicit_pointer_object_type(recdef);
  1271. currentstructdef:=recdef;
  1272. { in case the field is part of a parent of the current object,
  1273. index into the parents until we're at the parent containing the
  1274. field; if it's an implicit pointer type, these embedded parents
  1275. will be of the structure type of the class rather than of the
  1276. class time itself -> one indirection fewer }
  1277. while field.owner<>tabstractrecorddef(currentstructdef).symtable do
  1278. begin
  1279. { only objectdefs have parents and hence the owner of the
  1280. fieldvarsym can be different from the current def's owner }
  1281. parentdef:=tobjectdef(currentstructdef).childof;
  1282. if implicitpointer then
  1283. newbase:=getaddressregister(list,parentdef)
  1284. else
  1285. newbase:=getaddressregister(list,cpointerdef.getreusable(parentdef));
  1286. recref:=make_simple_ref(list,recref,recdef);
  1287. if implicitpointer then
  1288. subscriptdef:=currentstructdef
  1289. else
  1290. subscriptdef:=cpointerdef.getreusable(currentstructdef);
  1291. { recurse into the first field }
  1292. list.concat(taillvm.getelementptr_reg_size_ref_size_const(newbase,subscriptdef,recref,s32inttype,0,true));
  1293. reference_reset_base(recref,subscriptdef,newbase,field.offsetfromllvmfield,newalignment(recref.alignment,field.fieldoffset));
  1294. { go to the parent }
  1295. currentstructdef:=parentdef;
  1296. end;
  1297. { get the type of the corresponding field in the llvm shadow
  1298. definition }
  1299. llvmfielddef:=tabstractrecordsymtable(tabstractrecorddef(currentstructdef).symtable).llvmst[field].def;
  1300. if implicitpointer then
  1301. subscriptdef:=currentstructdef
  1302. else
  1303. subscriptdef:=cpointerdef.getreusable(currentstructdef);
  1304. { load the address of that shadow field }
  1305. newbase:=getaddressregister(list,cpointerdef.getreusable(llvmfielddef));
  1306. recref:=make_simple_ref(list,recref,recdef);
  1307. list.concat(taillvm.getelementptr_reg_size_ref_size_const(newbase,subscriptdef,recref,s32inttype,field.llvmfieldnr,true));
  1308. reference_reset_base(recref,subscriptdef,newbase,field.offsetfromllvmfield,newalignment(recref.alignment,field.fieldoffset+field.offsetfromllvmfield));
  1309. { in case of an 80 bits extended type, typecast from an array of 10
  1310. bytes (used because otherwise llvm will allocate the ABI-defined
  1311. size for extended, which is usually larger) into an extended }
  1312. if (llvmfielddef.typ=floatdef) and
  1313. (tfloatdef(llvmfielddef).floattype=s80real) then
  1314. g_ptrtypecast_ref(list,cpointerdef.getreusable(carraydef.getreusable(u8inttype,10)),cpointerdef.getreusable(s80floattype),recref);
  1315. { if it doesn't match the requested field exactly (variant record),
  1316. adjust the type of the pointer }
  1317. if (field.offsetfromllvmfield<>0) or
  1318. (llvmfielddef<>field.vardef) then
  1319. g_ptrtypecast_ref(list,cpointerdef.getreusable(llvmfielddef),cpointerdef.getreusable(field.vardef),recref);
  1320. end;
  1321. procedure thlcgllvm.a_loadmm_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; reg: tregister; shuffle: pmmshuffle);
  1322. var
  1323. href: treference;
  1324. begin
  1325. if shuffle=mms_movescalar then
  1326. a_loadfpu_ref_reg(list,fromsize,tosize,ref,reg)
  1327. else
  1328. begin
  1329. href:=make_simple_ref(list,ref,fromsize);
  1330. if ref.refaddr=addr_full then
  1331. gen_load_refaddrfull_anyreg(list,fromsize,tosize,href,reg,shuffle)
  1332. else
  1333. begin
  1334. { handle aggregate loads (happens if a struct needs to be passed
  1335. in an mmregister) }
  1336. if (fromsize.typ in [arraydef,recorddef]) or
  1337. (tosize.typ in [arraydef,recorddef]) then
  1338. begin
  1339. if handle_agg_load_ref_anyreg(list,fromsize,tosize,href,reg,mms_movescalar) then
  1340. exit;
  1341. end;
  1342. if fromsize<>tosize then
  1343. g_ptrtypecast_ref(list,cpointerdef.create(fromsize),cpointerdef.create(tosize),href);
  1344. { %reg = load size* %ref }
  1345. list.concat(taillvm.op_reg_size_ref(la_load,reg,cpointerdef.getreusable(tosize),href));
  1346. end;
  1347. end;
  1348. end;
  1349. procedure thlcgllvm.a_loadmm_reg_ref(list: TAsmList; fromsize, tosize: tdef; reg: tregister; const ref: treference; shuffle: pmmshuffle);
  1350. var
  1351. href: treference;
  1352. begin
  1353. if shuffle=mms_movescalar then
  1354. a_loadfpu_reg_ref(list,fromsize,tosize,reg,ref)
  1355. else
  1356. begin
  1357. { todo }
  1358. if fromsize<>tosize then
  1359. internalerror(2013060220);
  1360. href:=make_simple_ref(list,ref,tosize);
  1361. { store tosize reg, tosize* href }
  1362. list.concat(taillvm.op_size_reg_size_ref(la_store,tosize,reg,cpointerdef.getreusable(tosize),href))
  1363. end;
  1364. end;
  1365. procedure thlcgllvm.a_loadmm_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister; shuffle: pmmshuffle);
  1366. begin
  1367. if shuffle=mms_movescalar then
  1368. a_loadfpu_reg_reg(list,fromsize,tosize,reg1,reg2)
  1369. else
  1370. { reg2 = bitcast fromllsize reg1 to tollsize }
  1371. list.concat(taillvm.op_reg_size_reg_size(la_bitcast,reg2,fromsize,reg1,tosize));
  1372. end;
  1373. procedure thlcgllvm.a_opmm_reg_reg(list: TAsmList; Op: TOpCG; size: tdef; src, dst: tregister; shuffle: pmmshuffle);
  1374. begin
  1375. if (op=OP_XOR) and
  1376. (src=dst) then
  1377. a_load_const_reg(list,size,0,dst)
  1378. else
  1379. { todo }
  1380. internalerror(2013060221);
  1381. end;
  1382. procedure thlcgllvm.a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize: tdef; intreg, mmreg: tregister; shuffle: pmmshuffle);
  1383. begin
  1384. internalerror(2013060222);
  1385. end;
  1386. procedure thlcgllvm.a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize: tdef; mmreg, intreg: tregister; shuffle: pmmshuffle);
  1387. begin
  1388. internalerror(2013060223);
  1389. end;
  1390. function thlcgllvm.get_call_result_cgpara(pd: tabstractprocdef; forceresdef: tdef): tcgpara;
  1391. var
  1392. paraloc: pcgparalocation;
  1393. begin
  1394. result:=inherited;
  1395. { we'll change the paraloc, make sure we don't modify the original one }
  1396. if not result.temporary then
  1397. begin
  1398. result:=result.getcopy;
  1399. result.temporary:=true;
  1400. end;
  1401. { get the LLVM representation of the function result (e.g. a
  1402. struct with two i64 fields for a record with 4 i32 fields) }
  1403. result.def:=llvmgetcgparadef(result,true);
  1404. if assigned(result.location^.next) then
  1405. begin
  1406. { unify the result into a sinlge location; unlike for parameters,
  1407. we are not responsible for splitting up results into multiple
  1408. locations }
  1409. { set the first location to the type of the function result }
  1410. result.location^.def:=result.def;
  1411. result.location^.size:=result.size;
  1412. { free all extra paralocs }
  1413. while assigned(result.location^.next) do
  1414. begin
  1415. paraloc:=result.location^.next^.next;
  1416. freemem(result.location^.next);
  1417. result.location^.next:=paraloc;
  1418. end;
  1419. end;
  1420. paraloc:=result.location;
  1421. paraloc^.def:=result.def;
  1422. case paraloc^.loc of
  1423. LOC_VOID:
  1424. ;
  1425. LOC_REGISTER,
  1426. LOC_FPUREGISTER,
  1427. LOC_MMREGISTER:
  1428. begin
  1429. paraloc^.llvmloc.loc:=paraloc^.loc;
  1430. paraloc^.llvmloc.reg:=paraloc^.register;
  1431. paraloc^.llvmvalueloc:=true;
  1432. end;
  1433. LOC_REFERENCE:
  1434. if not paramanager.ret_in_param(pd.returndef,pd) then
  1435. { TODO, if this can happen at all }
  1436. internalerror(2014011901);
  1437. else
  1438. internalerror(2014011902);
  1439. end;
  1440. end;
  1441. procedure thlcgllvm.gen_load_loc_function_result(list: TAsmList; vardef: tdef; const l: tlocation);
  1442. begin
  1443. gen_load_loc_cgpara(list,vardef,l,get_call_result_cgpara(current_procinfo.procdef,nil));
  1444. end;
  1445. procedure thlcgllvm.gen_load_loc_cgpara(list: TAsmList; vardef: tdef; const l: tlocation; const cgpara: tcgpara);
  1446. var
  1447. memloc: tlocation;
  1448. begin
  1449. if not(cgpara.location^.llvmvalueloc) then
  1450. begin
  1451. memloc:=l;
  1452. location_force_mem(list,memloc,vardef);
  1453. a_loadaddr_ref_cgpara(list,vardef,memloc.reference,cgpara);
  1454. end
  1455. else
  1456. inherited;
  1457. end;
  1458. procedure thlcgllvm.gen_load_cgpara_loc(list: TAsmList; vardef: tdef; const para: TCGPara; var destloc: tlocation; reusepara: boolean);
  1459. var
  1460. ploc : pcgparalocation;
  1461. hloc : tlocation;
  1462. href, href2 : treference;
  1463. hreg : tregister;
  1464. fielddef,
  1465. llvmparadef : tdef;
  1466. index : longint;
  1467. offset : pint;
  1468. userecord : boolean;
  1469. begin
  1470. { ignore e.g. empty records }
  1471. if (para.location^.loc=LOC_VOID) then
  1472. exit;
  1473. { If the parameter location is reused we don't need to copy
  1474. anything }
  1475. if (destloc.loc=LOC_REFERENCE) and
  1476. reusepara then
  1477. exit;
  1478. { get the equivalent llvm def used to pass the parameter (e.g. a record
  1479. with two int64 fields for passing a record consisiting of 8 bytes on
  1480. x86-64) }
  1481. llvmparadef:=llvmgetcgparadef(para,true);
  1482. userecord:=
  1483. (llvmparadef<>para.def) and
  1484. assigned(para.location^.next);
  1485. if userecord then
  1486. begin
  1487. { llvmparadef is a record in this case, with every field corresponding
  1488. to a single paraloc }
  1489. if destloc.loc<>LOC_REFERENCE then
  1490. tg.gethltemp(list,llvmparadef,llvmparadef.size,tt_normal,href)
  1491. else
  1492. begin
  1493. hreg:=getaddressregister(list,cpointerdef.getreusable(llvmparadef));
  1494. a_loadaddr_ref_reg(list,vardef,cpointerdef.getreusable(llvmparadef),destloc.reference,hreg);
  1495. reference_reset_base(href,cpointerdef.getreusable(llvmparadef),hreg,0,destloc.reference.alignment);
  1496. end;
  1497. index:=0;
  1498. ploc:=para.location;
  1499. repeat
  1500. paraloctoloc(ploc,hloc);
  1501. g_setup_load_field_by_name(list,trecorddef(llvmparadef),'F'+tostr(index),href,href2,fielddef);
  1502. a_load_loc_ref(list,ploc^.def,fielddef,hloc,href2);
  1503. inc(index);
  1504. ploc:=ploc^.next;
  1505. until not assigned(ploc);
  1506. if destloc.loc<>LOC_REFERENCE then
  1507. tg.ungettemp(list,href);
  1508. end
  1509. else
  1510. begin
  1511. para.check_simple_location;
  1512. paraloctoloc(para.location,hloc);
  1513. case destloc.loc of
  1514. LOC_REFERENCE :
  1515. begin
  1516. case def2regtyp(llvmparadef) of
  1517. R_INTREGISTER,
  1518. R_ADDRESSREGISTER:
  1519. a_load_loc_ref(list,llvmparadef,vardef,hloc,destloc.reference);
  1520. R_FPUREGISTER:
  1521. a_loadfpu_loc_ref(list,llvmparadef,vardef,hloc,destloc.reference);
  1522. R_MMREGISTER:
  1523. a_loadmm_loc_ref(list,llvmparadef,vardef,hloc,destloc.reference,nil);
  1524. else
  1525. internalerror(2014080801);
  1526. end;
  1527. end;
  1528. LOC_REGISTER:
  1529. begin
  1530. a_load_loc_reg(list,llvmparadef,vardef,hloc,destloc.register);
  1531. end;
  1532. LOC_FPUREGISTER:
  1533. begin
  1534. a_loadfpu_loc_reg(list,llvmparadef,vardef,hloc,destloc.register);
  1535. end;
  1536. LOC_MMREGISTER:
  1537. begin
  1538. a_loadmm_loc_reg(list,llvmparadef,vardef,hloc,destloc.register,nil);
  1539. end;
  1540. { TODO other possible locations }
  1541. else
  1542. internalerror(2013102304);
  1543. end;
  1544. end;
  1545. end;
  1546. procedure thlcgllvm.a_jmp_flags(list: TAsmList; const f: TResFlags; l: tasmlabel);
  1547. begin
  1548. internalerror(2013060224);
  1549. end;
  1550. procedure thlcgllvm.g_flags2reg(list: TAsmList; size: tdef; const f: tresflags; reg: TRegister);
  1551. begin
  1552. internalerror(2013060225);
  1553. end;
  1554. procedure thlcgllvm.g_flags2ref(list: TAsmList; size: tdef; const f: tresflags; const ref: TReference);
  1555. begin
  1556. internalerror(2013060226);
  1557. end;
  1558. procedure thlcgllvm.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tdef; src, dst: tregister);
  1559. begin
  1560. internalerror(2012090201);
  1561. end;
  1562. procedure thlcgllvm.g_stackpointer_alloc(list: TAsmList; size: longint);
  1563. begin
  1564. internalerror(2012090203);
  1565. end;
  1566. procedure thlcgllvm.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  1567. begin
  1568. internalerror(2012090204);
  1569. end;
  1570. procedure thlcgllvm.g_adjust_self_value(list: TAsmList; procdef: tprocdef; ioffset: aint);
  1571. begin
  1572. internalerror(2012090205);
  1573. end;
  1574. procedure thlcgllvm.g_local_unwind(list: TAsmList; l: TAsmLabel);
  1575. begin
  1576. internalerror(2012090206);
  1577. end;
  1578. procedure thlcgllvm.gen_stack_check_size_para(list: TAsmList);
  1579. begin
  1580. { this is implemented in a very hackish way, whereby first the call
  1581. to fpc_stackcheck() is emitted, then the prolog is generated and
  1582. registers are allocated, and finally the code to load the parameter
  1583. is inserted before the call to fpc_stackcheck(). Since parameters are
  1584. explicitly passed to call instructions for llvm, that does not work
  1585. here. It could be solved by patching the call instruction later, but
  1586. that's a lot of engineering for functionality that's only marginally
  1587. useful at best. }
  1588. end;
  1589. procedure thlcgllvm.gen_stack_check_call(list: TAsmList);
  1590. begin
  1591. { see explanation in thlcgllvm.gen_stack_check_size_para() }
  1592. end;
  1593. function thlcgllvm.make_simple_ref(list: TAsmList; const ref: treference; def: tdef): treference;
  1594. begin
  1595. result:=make_simple_ref_ptr(list,ref,cpointerdef.create(def));
  1596. end;
  1597. function thlcgllvm.make_simple_ref_ptr(list: TAsmList; const ref: treference; ptrdef: tdef): treference;
  1598. var
  1599. ptrindex: tcgint;
  1600. hreg1,
  1601. hreg2: tregister;
  1602. tmpref: treference;
  1603. pointedsize: asizeint;
  1604. begin
  1605. { already simple? }
  1606. if (not assigned(ref.symbol) or
  1607. (ref.base=NR_NO)) and
  1608. (ref.index=NR_NO) and
  1609. (ref.offset=0) then
  1610. begin
  1611. result:=ref;
  1612. exit;
  1613. end;
  1614. case ptrdef.typ of
  1615. pointerdef:
  1616. begin
  1617. pointedsize:=tpointerdef(ptrdef).pointeddef.size;
  1618. { void, formaldef }
  1619. if pointedsize=0 then
  1620. pointedsize:=1;
  1621. end;
  1622. else
  1623. begin
  1624. { pointedsize is only used if the offset <> 0, to see whether we
  1625. can use getelementptr if it's an exact multiple -> set pointedsize
  1626. to a value that will never be a multiple as we can't "index" other
  1627. types }
  1628. pointedsize:=ref.offset+1;
  1629. end;
  1630. end;
  1631. hreg2:=getaddressregister(list,ptrdef);
  1632. { symbol+offset or base+offset with offset a multiple of the size ->
  1633. use getelementptr }
  1634. if (ref.index=NR_NO) and
  1635. (ref.offset mod pointedsize=0) then
  1636. begin
  1637. ptrindex:=ref.offset div pointedsize;
  1638. if assigned(ref.symbol) then
  1639. reference_reset_symbol(tmpref,ref.symbol,0,ref.alignment)
  1640. else
  1641. reference_reset_base(tmpref,ptrdef,ref.base,0,ref.alignment);
  1642. list.concat(taillvm.getelementptr_reg_size_ref_size_const(hreg2,ptrdef,tmpref,ptruinttype,ptrindex,assigned(ref.symbol)));
  1643. reference_reset_base(result,ptrdef,hreg2,0,ref.alignment);
  1644. exit;
  1645. end;
  1646. { for now, perform all calculations using plain pointer arithmetic. Later
  1647. we can look into optimizations based on getelementptr for structured
  1648. accesses (if only to prevent running out of virtual registers).
  1649. Assumptions:
  1650. * symbol/base register: always type "ptrdef"
  1651. * index/offset: always type "ptruinttype" (llvm bitcode has no sign information, so sign doesn't matter) }
  1652. hreg1:=getintregister(list,ptruinttype);
  1653. if assigned(ref.symbol) then
  1654. begin
  1655. if ref.base<>NR_NO then
  1656. internalerror(2012111301);
  1657. reference_reset_symbol(tmpref,ref.symbol,0,ref.alignment);
  1658. list.concat(taillvm.getelementptr_reg_size_ref_size_const(hreg1,ptrdef,tmpref,ptruinttype,0,true));
  1659. end
  1660. else if ref.base<>NR_NO then
  1661. begin
  1662. a_load_reg_reg(list,ptrdef,ptruinttype,ref.base,hreg1);
  1663. end
  1664. else
  1665. { todo: support for absolute addresses on embedded platforms }
  1666. internalerror(2012111302);
  1667. if ref.index<>NR_NO then
  1668. begin
  1669. { SSA... }
  1670. hreg2:=getintregister(list,ptruinttype);
  1671. a_op_reg_reg_reg(list,OP_ADD,ptruinttype,ref.index,hreg1,hreg2);
  1672. hreg1:=hreg2;
  1673. end;
  1674. if ref.offset<>0 then
  1675. begin
  1676. hreg2:=getintregister(list,ptruinttype);
  1677. a_op_const_reg_reg(list,OP_ADD,ptruinttype,ref.offset,hreg1,hreg2);
  1678. hreg1:=hreg2;
  1679. end;
  1680. hreg2:=getaddressregister(list,ptrdef);
  1681. a_load_reg_reg(list,ptruinttype,ptrdef,hreg1,hreg2);
  1682. reference_reset_base(result,ptrdef,hreg2,0,ref.alignment);
  1683. end;
  1684. procedure thlcgllvm.set_call_function_result(const list: TAsmList; const pd: tabstractprocdef; const llvmretdef, hlretdef: tdef; const resval: tregister; var retpara: tcgpara);
  1685. var
  1686. hreg: tregister;
  1687. rettemp: treference;
  1688. begin
  1689. if not is_void(hlretdef) and
  1690. not paramanager.ret_in_param(hlretdef, pd) then
  1691. begin
  1692. { should already be a copy, because it currently describes the llvm
  1693. return location }
  1694. if not retpara.temporary then
  1695. internalerror(2014020101);
  1696. if llvmaggregatetype(hlretdef) then
  1697. begin
  1698. { to ease the handling of aggregate types here, we just store
  1699. everything to memory rather than potentially dealing with aggregates
  1700. in "registers" }
  1701. tg.gethltemp(list, llvmretdef, llvmretdef.size, tt_normal, rettemp);
  1702. case def2regtyp(llvmretdef) of
  1703. R_INTREGISTER,
  1704. R_ADDRESSREGISTER:
  1705. a_load_reg_ref(list,llvmretdef,llvmretdef,resval,rettemp);
  1706. R_FPUREGISTER:
  1707. a_loadfpu_reg_ref(list,llvmretdef,llvmretdef,resval,rettemp);
  1708. R_MMREGISTER:
  1709. a_loadmm_reg_ref(list,llvmretdef,llvmretdef,resval,rettemp,mms_movescalar);
  1710. end;
  1711. { the return parameter now contains a value whose type matches the one
  1712. that the high level code generator expects instead of the llvm shim
  1713. }
  1714. retpara.def:=llvmretdef;
  1715. retpara.location^.def:=llvmretdef;
  1716. { for llvm-specific code: }
  1717. retpara.location^.llvmvalueloc:=false;
  1718. retpara.location^.llvmloc.loc:=LOC_REGISTER;
  1719. retpara.location^.llvmloc.reg:=rettemp.base;
  1720. { for the rest (normally not used, but cleaner to set it correclty) }
  1721. retpara.location^.loc:=LOC_REFERENCE;
  1722. retpara.location^.reference.index:=rettemp.base;
  1723. retpara.location^.reference.offset:=0;
  1724. end
  1725. else
  1726. begin
  1727. retpara.def:=llvmretdef;
  1728. retpara.Location^.def:=llvmretdef;
  1729. retpara.location^.llvmloc.reg:=resval;
  1730. retpara.Location^.llvmloc.loc:=retpara.location^.loc;
  1731. retpara.Location^.llvmvalueloc:=true;
  1732. end;
  1733. end
  1734. else
  1735. retpara.location^.llvmloc.loc:=LOC_VOID;
  1736. end;
  1737. procedure thlcgllvm.paraloctoloc(const paraloc: pcgparalocation; out hloc: tlocation);
  1738. begin
  1739. case paraloc^.llvmloc.loc of
  1740. LOC_REFERENCE:
  1741. begin
  1742. location_reset_ref(hloc,LOC_REFERENCE,def_cgsize(paraloc^.def),paraloc^.def.alignment);
  1743. hloc.reference.symbol:=paraloc^.llvmloc.sym;
  1744. if paraloc^.llvmvalueloc then
  1745. hloc.reference.refaddr:=addr_full;
  1746. end;
  1747. LOC_REGISTER:
  1748. begin
  1749. if paraloc^.llvmvalueloc then
  1750. begin
  1751. location_reset(hloc,LOC_REGISTER,def_cgsize(paraloc^.def));
  1752. hloc.register:=paraloc^.llvmloc.reg;
  1753. end
  1754. else
  1755. begin
  1756. if getregtype(paraloc^.llvmloc.reg)<>R_TEMPREGISTER then
  1757. internalerror(2014011903);
  1758. location_reset_ref(hloc,LOC_REFERENCE,def_cgsize(paraloc^.def),paraloc^.def.alignment);
  1759. hloc.reference.base:=paraloc^.llvmloc.reg;
  1760. end;
  1761. end;
  1762. LOC_FPUREGISTER,
  1763. LOC_MMREGISTER:
  1764. begin
  1765. if paraloc^.llvmvalueloc then
  1766. begin
  1767. location_reset(hloc,paraloc^.llvmloc.loc,def_cgsize(paraloc^.def));
  1768. hloc.register:=paraloc^.llvmloc.reg;
  1769. end
  1770. else
  1771. internalerror(2014012401);
  1772. end
  1773. else
  1774. internalerror(2014010706);
  1775. end;
  1776. end;
  1777. procedure thlcgllvm.varsym_set_localloc(list: TAsmList; vs: tabstractnormalvarsym);
  1778. begin
  1779. if cs_asm_source in current_settings.globalswitches then
  1780. begin
  1781. case vs.initialloc.loc of
  1782. LOC_REFERENCE :
  1783. begin
  1784. if assigned(vs.initialloc.reference.symbol) then
  1785. list.concat(Tai_comment.Create(strpnew('Var '+vs.realname+' located at '+
  1786. vs.initialloc.reference.symbol.name)))
  1787. else
  1788. list.concat(Tai_comment.Create(strpnew('Var '+vs.realname+' located at %tmp.'+
  1789. tostr(getsupreg(vs.initialloc.reference.base)))));
  1790. end;
  1791. end;
  1792. end;
  1793. vs.localloc:=vs.initialloc;
  1794. end;
  1795. procedure thlcgllvm.paravarsym_set_initialloc_to_paraloc(vs: tparavarsym);
  1796. var
  1797. parasym : tasmsymbol;
  1798. begin
  1799. if vs.paraloc[calleeside].location^.llvmloc.loc<>LOC_REFERENCE then
  1800. internalerror(2014010708);
  1801. parasym:=vs.paraloc[calleeside].location^.llvmloc.sym;
  1802. reference_reset_symbol(vs.initialloc.reference,parasym,0,vs.paraloc[calleeside].alignment);
  1803. if vs.paraloc[calleeside].location^.llvmvalueloc then
  1804. vs.initialloc.reference.refaddr:=addr_full;
  1805. end;
  1806. procedure thlcgllvm.g_external_wrapper(list: TAsmList; procdef: tprocdef; const externalname: string);
  1807. var
  1808. asmsym: TAsmSymbol;
  1809. begin
  1810. if po_external in procdef.procoptions then
  1811. exit;
  1812. asmsym:=current_asmdata.RefAsmSymbol(externalname,AT_FUNCTION);
  1813. list.concat(taillvmalias.create(asmsym,procdef.mangledname,procdef,asmsym.bind));
  1814. end;
  1815. procedure create_hlcodegen;
  1816. begin
  1817. if not assigned(current_procinfo) or
  1818. not(po_assembler in current_procinfo.procdef.procoptions) then
  1819. begin
  1820. tgobjclass:=ttgllvm;
  1821. hlcg:=thlcgllvm.create;
  1822. cgllvm.create_codegen
  1823. end
  1824. else
  1825. begin
  1826. tgobjclass:=orgtgclass;
  1827. hlcgcpu.create_hlcodegen;
  1828. { todo: handle/remove chlcgobj }
  1829. end;
  1830. end;
  1831. begin
  1832. chlcgobj:=thlcgllvm;
  1833. end.