nllvmcnv.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  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. symtype,
  22. node,ncnv,ncgcnv,defcmp;
  23. type
  24. tllvmtypeconvnode = class(tcgtypeconvnode)
  25. public
  26. class function target_specific_need_equal_typeconv(fromdef, todef: tdef): boolean; override;
  27. protected
  28. function first_int_to_real: tnode; override;
  29. function first_int_to_bool: tnode; override;
  30. function first_nil_to_methodprocvar: tnode; override;
  31. procedure second_int_to_int;override;
  32. { procedure second_string_to_string;override; }
  33. { procedure second_cstring_to_pchar;override; }
  34. { procedure second_string_to_chararray;override; }
  35. { procedure second_array_to_pointer;override; }
  36. procedure second_pointer_to_array;override;
  37. { procedure second_chararray_to_string;override; }
  38. { procedure second_char_to_string;override; }
  39. procedure second_int_to_real;override;
  40. { procedure second_real_to_real;override; }
  41. { procedure second_cord_to_pointer;override; }
  42. procedure second_proc_to_procvar;override;
  43. procedure second_nil_to_methodprocvar; override;
  44. procedure second_bool_to_int;override;
  45. procedure second_int_to_bool;override;
  46. { procedure second_load_smallset;override; }
  47. { procedure second_ansistring_to_pchar;override; }
  48. { procedure second_pchar_to_string;override; }
  49. { procedure second_class_to_intf;override; }
  50. { procedure second_char_to_char;override; }
  51. procedure second_nothing; override;
  52. end;
  53. implementation
  54. uses
  55. globtype,globals,verbose,
  56. aasmbase,aasmdata,
  57. llvmbase,aasmllvm,
  58. procinfo,
  59. symconst,symdef,defutil,
  60. cgbase,cgutils,tgobj,hlcgobj,pass_2;
  61. { tllvmtypeconvnode }
  62. class function tllvmtypeconvnode.target_specific_need_equal_typeconv(fromdef, todef: tdef): boolean;
  63. begin
  64. result:=
  65. (fromdef<>todef) and
  66. { two procdefs that are structurally the same but semantically different
  67. still need a convertion }
  68. (
  69. ((fromdef.typ=procvardef) and
  70. (todef.typ=procvardef))
  71. );
  72. end;
  73. function tllvmtypeconvnode.first_int_to_real: tnode;
  74. begin
  75. expectloc:=LOC_FPUREGISTER;
  76. result:=nil;
  77. end;
  78. function tllvmtypeconvnode.first_int_to_bool: tnode;
  79. begin
  80. result:=inherited;
  81. if not assigned(result) then
  82. begin
  83. if not((nf_explicit in flags) and
  84. not(left.location.loc in [LOC_FLAGS,LOC_JUMP])) then
  85. expectloc:=LOC_JUMP;
  86. end;
  87. end;
  88. function tllvmtypeconvnode.first_nil_to_methodprocvar: tnode;
  89. begin
  90. result:=inherited;
  91. if assigned(result) then
  92. exit;
  93. expectloc:=LOC_REFERENCE;
  94. end;
  95. procedure tllvmtypeconvnode.second_int_to_int;
  96. var
  97. fromsize, tosize: tcgint;
  98. hreg: tregister;
  99. begin
  100. if not(nf_explicit in flags) then
  101. hlcg.g_rangecheck(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef);
  102. fromsize:=left.resultdef.size;
  103. tosize:=resultdef.size;
  104. location_copy(location,left.location);
  105. if not(left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) or
  106. ((fromsize<>tosize) and
  107. not is_void(left.resultdef)) then
  108. begin
  109. hlcg.location_force_reg(current_asmdata.CurrAsmList,location,left.resultdef,resultdef,left.location.loc=LOC_CREGISTER);
  110. end
  111. else if left.resultdef<>resultdef then
  112. begin
  113. { just typecast the pointer type }
  114. hreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,cpointerdef.getreusable(resultdef));
  115. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.resultdef,cpointerdef.getreusable(resultdef),left.location.reference,hreg);
  116. hlcg.reference_reset_base(location.reference,cpointerdef.getreusable(resultdef),hreg,0,location.reference.alignment);
  117. end;
  118. end;
  119. procedure tllvmtypeconvnode.second_pointer_to_array;
  120. var
  121. hreg: tregister;
  122. begin
  123. inherited;
  124. { insert type conversion }
  125. hreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,cpointerdef.getreusable(resultdef));
  126. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,tpointerdef(left.resultdef).pointeddef,cpointerdef.getreusable(resultdef),location.reference,hreg);
  127. reference_reset_base(location.reference,hreg,0,location.reference.alignment);
  128. end;
  129. procedure tllvmtypeconvnode.second_int_to_real;
  130. var
  131. op: tllvmop;
  132. llvmtodef: tdef;
  133. begin
  134. if is_signed(left.resultdef) then
  135. op:=la_sitofp
  136. else
  137. op:=la_uitofp;
  138. { see comment about currency in thlcgllvm.a_loadfpu_ref_reg }
  139. if not(tfloatdef(resultdef).floattype in [s64comp,s64currency]) then
  140. llvmtodef:=resultdef
  141. else
  142. llvmtodef:=s80floattype;
  143. location_reset(location,LOC_FPUREGISTER,def_cgsize(llvmtodef));
  144. location.register:=hlcg.getfpuregister(current_asmdata.CurrAsmList,llvmtodef);
  145. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
  146. current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_reg_size(op,location.register,left.resultdef,left.location.register,llvmtodef));
  147. end;
  148. procedure tllvmtypeconvnode.second_proc_to_procvar;
  149. begin
  150. inherited;
  151. if not tabstractprocdef(resultdef).is_addressonly and
  152. not tabstractprocdef(left.resultdef).is_addressonly then
  153. begin
  154. if location.loc<>LOC_REFERENCE then
  155. internalerror(2015111902);
  156. hlcg.g_ptrtypecast_ref(current_asmdata.CurrAsmList,
  157. cpointerdef.getreusable(tprocdef(left.resultdef).getcopyas(procvardef,pc_normal)),
  158. cpointerdef.getreusable(resultdef),
  159. location.reference);
  160. end;
  161. end;
  162. procedure tllvmtypeconvnode.second_nil_to_methodprocvar;
  163. var
  164. href: treference;
  165. begin
  166. tg.gethltemp(current_asmdata.CurrAsmList,resultdef,resultdef.size,tt_normal,href);
  167. location_reset_ref(location,LOC_REFERENCE,def_cgsize(resultdef),href.alignment);
  168. location.reference:=href;
  169. hlcg.g_ptrtypecast_ref(current_asmdata.CurrAsmList,cpointerdef.getreusable(resultdef),cpointerdef.getreusable(methodpointertype),href);
  170. hlcg.g_load_const_field_by_name(current_asmdata.CurrAsmList,trecorddef(methodpointertype),0,'proc',href);
  171. hlcg.g_load_const_field_by_name(current_asmdata.CurrAsmList,trecorddef(methodpointertype),0,'self',href);
  172. end;
  173. procedure tllvmtypeconvnode.second_bool_to_int;
  174. var
  175. pdef: tdef;
  176. hreg: tregister;
  177. begin
  178. inherited;
  179. { all boolean/integer of the same size are represented using the same type
  180. by FPC in LLVM, except for Pascal booleans, which are i1 -> convert
  181. the type if necessary. This never has to be done for registers on the
  182. assignment side, because we make everything that's explicitly typecasted
  183. on the assignment side non regable for llvm }
  184. if is_pasbool(left.resultdef) and
  185. (nf_explicit in flags) and
  186. not(left.location.loc in [LOC_FLAGS,LOC_JUMP]) and
  187. (resultdef.size=1) then
  188. case location.loc of
  189. LOC_REFERENCE,LOC_CREFERENCE:
  190. begin
  191. pdef:=cpointerdef.getreusable(resultdef);
  192. hreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,pdef);
  193. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.resultdef,pdef,location.reference,hreg);
  194. hlcg.reference_reset_base(location.reference,pdef,hreg,0,location.reference.alignment);
  195. end;
  196. LOC_REGISTER,LOC_CREGISTER:
  197. begin
  198. hreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
  199. hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,left.resultdef,resultdef,location.register,hreg);
  200. location.register:=hreg;
  201. end;
  202. end;
  203. end;
  204. procedure tllvmtypeconvnode.second_int_to_bool;
  205. var
  206. truelabel,
  207. falselabel: tasmlabel;
  208. newsize : tcgsize;
  209. begin
  210. secondpass(left);
  211. if codegenerror then
  212. exit;
  213. { Explicit typecasts from any ordinal type to a boolean type }
  214. { must not change the ordinal value }
  215. if (nf_explicit in flags) and
  216. not(left.location.loc in [LOC_FLAGS,LOC_JUMP]) then
  217. begin
  218. location_copy(location,left.location);
  219. newsize:=def_cgsize(resultdef);
  220. { change of size? change sign only if location is LOC_(C)REGISTER? Then we have to sign/zero-extend }
  221. if (tcgsize2size[newsize]<>tcgsize2size[left.location.size]) or
  222. ((newsize<>left.location.size) and (location.loc in [LOC_REGISTER,LOC_CREGISTER])) then
  223. hlcg.location_force_reg(current_asmdata.CurrAsmList,location,left.resultdef,resultdef,true)
  224. else
  225. location.size:=newsize;
  226. exit;
  227. end;
  228. case left.location.loc of
  229. LOC_SUBSETREG,LOC_CSUBSETREG,LOC_SUBSETREF,LOC_CSUBSETREF,
  230. LOC_CREFERENCE,LOC_REFERENCE,LOC_REGISTER,LOC_CREGISTER:
  231. begin
  232. current_asmdata.getjumplabel(truelabel);
  233. current_asmdata.getjumplabel(falselabel);
  234. location_reset_jump(location,truelabel,falselabel);
  235. hlcg.a_cmp_const_loc_label(current_asmdata.CurrAsmList,left.resultdef,OC_EQ,0,left.location,location.falselabel);
  236. hlcg.a_jmp_always(current_asmdata.CurrAsmList,location.truelabel);
  237. end;
  238. LOC_JUMP :
  239. begin
  240. location:=left.location;
  241. end;
  242. else
  243. internalerror(10062);
  244. end;
  245. end;
  246. procedure tllvmtypeconvnode.second_nothing;
  247. var
  248. hreg: tregister;
  249. begin
  250. if left.resultdef<>resultdef then
  251. begin
  252. { handle sometype(voidptr^) and "absolute" }
  253. if not is_void(left.resultdef) and
  254. not(nf_absolute in flags) and
  255. (left.resultdef.typ<>formaldef) and
  256. (left.resultdef.size<>resultdef.size) then
  257. internalerror(2014012216);
  258. hlcg.location_force_mem(current_asmdata.CurrAsmList,left.location,left.resultdef);
  259. hreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,cpointerdef.getreusable(resultdef));
  260. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.resultdef,cpointerdef.getreusable(resultdef),left.location.reference,hreg);
  261. location_reset_ref(location,left.location.loc,left.location.size,left.location.reference.alignment);
  262. reference_reset_base(location.reference,hreg,0,location.reference.alignment);
  263. end
  264. else
  265. location_copy(location,left.location);
  266. end;
  267. begin
  268. ctypeconvnode:=tllvmtypeconvnode;
  269. end.