nllvmcnv.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. {
  2. Copyright (c) 2014 by Jonas Maebe
  3. Generate LLVM IR for type converting nodes
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit nllvmcnv;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. node,ncnv,ncgcnv,defcmp;
  22. type
  23. tllvmtypeconvnode = class(tcgtypeconvnode)
  24. protected
  25. function first_int_to_real: tnode; override;
  26. function first_int_to_bool: tnode; override;
  27. function first_nil_to_methodprocvar: tnode; override;
  28. procedure second_int_to_int;override;
  29. { procedure second_string_to_string;override; }
  30. { procedure second_cstring_to_pchar;override; }
  31. { procedure second_string_to_chararray;override; }
  32. { procedure second_array_to_pointer;override; }
  33. procedure second_pointer_to_array;override;
  34. { procedure second_chararray_to_string;override; }
  35. { procedure second_char_to_string;override; }
  36. procedure second_int_to_real;override;
  37. { procedure second_real_to_real;override; }
  38. { procedure second_cord_to_pointer;override; }
  39. procedure second_proc_to_procvar;override;
  40. procedure second_nil_to_methodprocvar; override;
  41. procedure second_bool_to_int;override;
  42. procedure second_int_to_bool;override;
  43. { procedure second_load_smallset;override; }
  44. { procedure second_ansistring_to_pchar;override; }
  45. { procedure second_pchar_to_string;override; }
  46. { procedure second_class_to_intf;override; }
  47. { procedure second_char_to_char;override; }
  48. procedure second_nothing; override;
  49. end;
  50. implementation
  51. uses
  52. globtype,globals,verbose,
  53. aasmbase,aasmdata,
  54. llvmbase,aasmllvm,
  55. procinfo,
  56. symconst,symtype,symdef,defutil,
  57. cgbase,cgutils,tgobj,hlcgobj,pass_2;
  58. { tllvmtypeconvnode }
  59. function tllvmtypeconvnode.first_int_to_real: tnode;
  60. begin
  61. expectloc:=LOC_FPUREGISTER;
  62. result:=nil;
  63. end;
  64. function tllvmtypeconvnode.first_int_to_bool: tnode;
  65. begin
  66. result:=inherited;
  67. if not assigned(result) then
  68. begin
  69. if not((nf_explicit in flags) and
  70. not(left.location.loc in [LOC_FLAGS,LOC_JUMP])) then
  71. expectloc:=LOC_JUMP;
  72. end;
  73. end;
  74. function tllvmtypeconvnode.first_nil_to_methodprocvar: tnode;
  75. begin
  76. result:=inherited;
  77. if assigned(result) then
  78. exit;
  79. expectloc:=LOC_REFERENCE;
  80. end;
  81. procedure tllvmtypeconvnode.second_int_to_int;
  82. var
  83. fromsize, tosize: tcgint;
  84. hreg: tregister;
  85. begin
  86. if not(nf_explicit in flags) then
  87. hlcg.g_rangecheck(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef);
  88. fromsize:=left.resultdef.size;
  89. tosize:=resultdef.size;
  90. location_copy(location,left.location);
  91. if not(left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) or
  92. ((fromsize<>tosize) and
  93. not is_void(left.resultdef)) then
  94. begin
  95. hlcg.location_force_reg(current_asmdata.CurrAsmList,location,left.resultdef,resultdef,left.location.loc=LOC_CREGISTER);
  96. end
  97. else if left.resultdef<>resultdef then
  98. begin
  99. { just typecast the pointer type }
  100. hreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,cpointerdef.getreusable(resultdef));
  101. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.resultdef,cpointerdef.getreusable(resultdef),left.location.reference,hreg);
  102. hlcg.reference_reset_base(location.reference,cpointerdef.getreusable(resultdef),hreg,0,location.reference.alignment);
  103. end;
  104. end;
  105. procedure tllvmtypeconvnode.second_pointer_to_array;
  106. var
  107. hreg: tregister;
  108. begin
  109. inherited;
  110. { insert type conversion }
  111. hreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,cpointerdef.getreusable(resultdef));
  112. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,tpointerdef(left.resultdef).pointeddef,cpointerdef.getreusable(resultdef),location.reference,hreg);
  113. reference_reset_base(location.reference,hreg,0,location.reference.alignment);
  114. end;
  115. procedure tllvmtypeconvnode.second_int_to_real;
  116. var
  117. op: tllvmop;
  118. llvmtodef: tdef;
  119. begin
  120. if is_signed(left.resultdef) then
  121. op:=la_sitofp
  122. else
  123. op:=la_uitofp;
  124. { see comment about currency in thlcgllvm.a_loadfpu_ref_reg }
  125. if not(tfloatdef(resultdef).floattype in [s64comp,s64currency]) then
  126. llvmtodef:=resultdef
  127. else
  128. llvmtodef:=s80floattype;
  129. location_reset(location,LOC_FPUREGISTER,def_cgsize(llvmtodef));
  130. location.register:=hlcg.getfpuregister(current_asmdata.CurrAsmList,llvmtodef);
  131. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
  132. current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_reg_size(op,location.register,left.resultdef,left.location.register,llvmtodef));
  133. end;
  134. procedure tllvmtypeconvnode.second_proc_to_procvar;
  135. begin
  136. inherited;
  137. if not tabstractprocdef(resultdef).is_addressonly and
  138. not tabstractprocdef(left.resultdef).is_addressonly then
  139. begin
  140. if location.loc<>LOC_REFERENCE then
  141. internalerror(2015111902);
  142. hlcg.g_ptrtypecast_ref(current_asmdata.CurrAsmList,
  143. cpointerdef.getreusable(tprocdef(left.resultdef).getcopyas(procvardef,pc_normal)),
  144. cpointerdef.getreusable(resultdef),
  145. location.reference);
  146. end;
  147. end;
  148. procedure tllvmtypeconvnode.second_nil_to_methodprocvar;
  149. var
  150. href: treference;
  151. begin
  152. tg.gethltemp(current_asmdata.CurrAsmList,resultdef,resultdef.size,tt_normal,href);
  153. location_reset_ref(location,LOC_REFERENCE,def_cgsize(resultdef),href.alignment);
  154. location.reference:=href;
  155. hlcg.g_ptrtypecast_ref(current_asmdata.CurrAsmList,cpointerdef.getreusable(resultdef),cpointerdef.getreusable(methodpointertype),href);
  156. hlcg.g_load_const_field_by_name(current_asmdata.CurrAsmList,trecorddef(methodpointertype),0,'proc',href);
  157. hlcg.g_load_const_field_by_name(current_asmdata.CurrAsmList,trecorddef(methodpointertype),0,'self',href);
  158. end;
  159. procedure tllvmtypeconvnode.second_bool_to_int;
  160. var
  161. pdef: tdef;
  162. hreg: tregister;
  163. begin
  164. inherited;
  165. { all boolean/integer of the same size are represented using the same type
  166. by FPC in LLVM, except for Pascal booleans, which are i1 -> convert
  167. the type if necessary. This never has to be done for registers on the
  168. assignment side, because we make everything that's explicitly typecasted
  169. on the assignment side non regable for llvm }
  170. if is_pasbool(left.resultdef) and
  171. (nf_explicit in flags) and
  172. not(left.location.loc in [LOC_FLAGS,LOC_JUMP]) and
  173. (resultdef.size=1) then
  174. case location.loc of
  175. LOC_REFERENCE,LOC_CREFERENCE:
  176. begin
  177. pdef:=cpointerdef.getreusable(resultdef);
  178. hreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,pdef);
  179. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.resultdef,pdef,location.reference,hreg);
  180. hlcg.reference_reset_base(location.reference,pdef,hreg,0,location.reference.alignment);
  181. end;
  182. LOC_REGISTER,LOC_CREGISTER:
  183. begin
  184. hreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
  185. hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,left.resultdef,resultdef,location.register,hreg);
  186. location.register:=hreg;
  187. end;
  188. end;
  189. end;
  190. procedure tllvmtypeconvnode.second_int_to_bool;
  191. var
  192. truelabel,
  193. falselabel: tasmlabel;
  194. newsize : tcgsize;
  195. begin
  196. secondpass(left);
  197. if codegenerror then
  198. exit;
  199. { Explicit typecasts from any ordinal type to a boolean type }
  200. { must not change the ordinal value }
  201. if (nf_explicit in flags) and
  202. not(left.location.loc in [LOC_FLAGS,LOC_JUMP]) then
  203. begin
  204. location_copy(location,left.location);
  205. newsize:=def_cgsize(resultdef);
  206. { change of size? change sign only if location is LOC_(C)REGISTER? Then we have to sign/zero-extend }
  207. if (tcgsize2size[newsize]<>tcgsize2size[left.location.size]) or
  208. ((newsize<>left.location.size) and (location.loc in [LOC_REGISTER,LOC_CREGISTER])) then
  209. hlcg.location_force_reg(current_asmdata.CurrAsmList,location,left.resultdef,resultdef,true)
  210. else
  211. location.size:=newsize;
  212. exit;
  213. end;
  214. case left.location.loc of
  215. LOC_SUBSETREG,LOC_CSUBSETREG,LOC_SUBSETREF,LOC_CSUBSETREF,
  216. LOC_CREFERENCE,LOC_REFERENCE,LOC_REGISTER,LOC_CREGISTER:
  217. begin
  218. current_asmdata.getjumplabel(truelabel);
  219. current_asmdata.getjumplabel(falselabel);
  220. location_reset_jump(location,truelabel,falselabel);
  221. hlcg.a_cmp_const_loc_label(current_asmdata.CurrAsmList,left.resultdef,OC_EQ,0,left.location,location.falselabel);
  222. hlcg.a_jmp_always(current_asmdata.CurrAsmList,location.truelabel);
  223. end;
  224. LOC_JUMP :
  225. begin
  226. location:=left.location;
  227. end;
  228. else
  229. internalerror(10062);
  230. end;
  231. end;
  232. procedure tllvmtypeconvnode.second_nothing;
  233. var
  234. hreg: tregister;
  235. begin
  236. if left.resultdef<>resultdef then
  237. begin
  238. { handle sometype(voidptr^) and "absolute" }
  239. if not is_void(left.resultdef) and
  240. not(nf_absolute in flags) and
  241. (left.resultdef.typ<>formaldef) and
  242. (left.resultdef.size<>resultdef.size) then
  243. internalerror(2014012216);
  244. hlcg.location_force_mem(current_asmdata.CurrAsmList,left.location,left.resultdef);
  245. hreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,cpointerdef.getreusable(resultdef));
  246. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.resultdef,cpointerdef.getreusable(resultdef),left.location.reference,hreg);
  247. location_reset_ref(location,left.location.loc,left.location.size,left.location.reference.alignment);
  248. reference_reset_base(location.reference,hreg,0,location.reference.alignment);
  249. end
  250. else
  251. location_copy(location,left.location);
  252. end;
  253. begin
  254. ctypeconvnode:=tllvmtypeconvnode;
  255. end.