nllvmadd.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. {
  2. Copyright (c) 2013 by Jonas Maebe
  3. Generate LLVM bytecode for add 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 nllvmadd;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. node,
  22. ncgadd;
  23. type
  24. tllvmaddnode = class(tcgaddnode)
  25. public
  26. function pass_1: tnode; override;
  27. procedure force_reg_left_right(allow_swap, allow_constant: boolean); override;
  28. protected
  29. procedure second_cmpsmallset; override;
  30. procedure second_cmpordinal; override;
  31. procedure second_add64bit; override;
  32. procedure second_cmp64bit; override;
  33. procedure second_addfloat; override;
  34. procedure second_cmpfloat; override;
  35. end;
  36. implementation
  37. uses
  38. verbose,globtype,globals,cutils,
  39. aasmdata,
  40. symconst,symtype,symdef,defutil,
  41. llvmbase,aasmllvm,
  42. cgbase,cgutils,pass_1,
  43. hlcgobj,
  44. nadd,ncal,ncnv,ncon
  45. ;
  46. { tllvmaddnode }
  47. function tllvmaddnode.pass_1: tnode;
  48. var
  49. intrname: string;
  50. iscompcurrency: boolean;
  51. begin
  52. result:=inherited pass_1;
  53. if not assigned(result) and
  54. is_fpu(left.resultdef) and
  55. not(cs_opt_fastmath in current_settings.optimizerswitches) then
  56. begin
  57. case nodetype of
  58. addn:
  59. begin
  60. intrname:='LLVM_EXPERIMENTAL_CONSTRAINED_FADD';
  61. end;
  62. subn:
  63. begin
  64. intrname:='LLVM_EXPERIMENTAL_CONSTRAINED_FSUB';
  65. end;
  66. muln:
  67. begin
  68. intrname:='LLVM_EXPERIMENTAL_CONSTRAINED_FMUL';
  69. end;
  70. slashn:
  71. begin
  72. intrname:='LLVM_EXPERIMENTAL_CONSTRAINED_FDIV';
  73. end;
  74. else
  75. begin
  76. intrname:='';
  77. end;
  78. end;
  79. if intrname<>'' then
  80. begin
  81. iscompcurrency:=tfloatdef(left.resultdef).floattype in [s64currency,s64comp];
  82. if iscompcurrency then
  83. begin
  84. inserttypeconv_internal(left,s80floattype);
  85. inserttypeconv_internal(right,s80floattype);
  86. end;
  87. result:=ccallnode.createintern(intrname,
  88. ccallparanode.create(cstringconstnode.createpchar(ansistring2pchar('fpexcept.strict'),length('fpexcept.strict'),llvm_metadatatype),
  89. ccallparanode.create(cstringconstnode.createpchar(ansistring2pchar('round.dynamic'),length('round.dynamic'),llvm_metadatatype),
  90. ccallparanode.create(right,
  91. ccallparanode.create(left,nil)
  92. )
  93. )
  94. )
  95. );
  96. if iscompcurrency then
  97. begin
  98. result:=ctypeconvnode.create_internal(result,resultdef);
  99. end;
  100. left:=nil;
  101. right:=nil;
  102. exit;
  103. end;
  104. end;
  105. { there are no flags in LLVM }
  106. if expectloc=LOC_FLAGS then
  107. expectloc:=LOC_REGISTER;
  108. end;
  109. procedure tllvmaddnode.force_reg_left_right(allow_swap, allow_constant: boolean);
  110. begin
  111. { comparison with pointer -> no immediate, as icmp can't handle pointer
  112. immediates (except for nil as "null", but we don't generate that) }
  113. if (nodetype in [equaln,unequaln,gtn,gten,ltn,lten]) and
  114. ((left.nodetype in [pointerconstn,niln]) or
  115. (right.nodetype in [pointerconstn,niln])) then
  116. allow_constant:=false;
  117. inherited;
  118. { pointer - pointer = integer -> make all defs pointer since we can't
  119. subtract pointers }
  120. if (nodetype=subn) and
  121. (left.resultdef.typ=pointerdef) and
  122. (right.resultdef.typ=pointerdef) then
  123. begin
  124. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef,true);
  125. hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,resultdef,true);
  126. end
  127. { pointer +/- integer -> make defs the same since a_op_* only gets a
  128. single type as argument }
  129. else if (nodetype in [addn,subn]) and
  130. ((left.resultdef.typ=pointerdef)<>(right.resultdef.typ=pointerdef)) then
  131. begin
  132. { the result is a pointerdef -> typecast both arguments to pointer;
  133. a_op_*_reg will convert them back to integer as needed }
  134. if left.resultdef.typ<>pointerdef then
  135. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef,true);
  136. if right.resultdef.typ<>pointerdef then
  137. hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,resultdef,true);
  138. end;
  139. end;
  140. procedure tllvmaddnode.second_cmpsmallset;
  141. var
  142. tmpreg,
  143. tmpreg2: tregister;
  144. cmpop : topcmp;
  145. begin
  146. pass_left_right;
  147. location_reset(location,LOC_REGISTER,OS_8);
  148. location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,llvmbool1type);
  149. force_reg_left_right(false,false);
  150. case nodetype of
  151. equaln,
  152. unequaln:
  153. begin
  154. if nodetype=equaln then
  155. cmpop:=OC_EQ
  156. else
  157. cmpop:=OC_NE;
  158. current_asmdata.CurrAsmList.concat(taillvm.op_reg_cond_size_reg_reg(la_icmp,
  159. location.register,cmpop,left.resultdef,left.location.register,right.location.register));
  160. end;
  161. lten,
  162. gten:
  163. begin
  164. if (not(nf_swapped in flags) and
  165. (nodetype = lten)) or
  166. ((nf_swapped in flags) and
  167. (nodetype = gten)) then
  168. swapleftright;
  169. { set1<=set2 <-> set2 and not(set1) = 0 }
  170. tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,left.resultdef);
  171. hlcg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_NOT,left.resultdef,left.location.register,tmpreg);
  172. tmpreg2:=hlcg.getintregister(current_asmdata.CurrAsmList,left.resultdef);
  173. hlcg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_AND,left.resultdef,right.location.register,tmpreg,tmpreg2);
  174. current_asmdata.CurrAsmList.concat(taillvm.op_reg_cond_size_reg_const(la_icmp,
  175. location.register,OC_EQ,left.resultdef,tmpreg2,0));
  176. end;
  177. else
  178. internalerror(2012042701);
  179. end;
  180. tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
  181. hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,llvmbool1type,resultdef,location.register,tmpreg);
  182. location.register:=tmpreg;
  183. end;
  184. procedure tllvmaddnode.second_cmpordinal;
  185. var
  186. tmpreg: tregister;
  187. cmpop: topcmp;
  188. unsigned : boolean;
  189. begin
  190. pass_left_right;
  191. force_reg_left_right(true,true);
  192. unsigned:=not(is_signed(left.resultdef)) or
  193. not(is_signed(right.resultdef));
  194. case nodetype of
  195. ltn:
  196. if unsigned then
  197. cmpop:=OC_B
  198. else
  199. cmpop:=OC_LT;
  200. lten:
  201. if unsigned then
  202. cmpop:=OC_BE
  203. else
  204. cmpop:=OC_LTE;
  205. gtn:
  206. if unsigned then
  207. cmpop:=OC_A
  208. else
  209. cmpop:=OC_GT;
  210. gten:
  211. if unsigned then
  212. cmpop:=OC_AE
  213. else
  214. cmpop:=OC_GTE;
  215. equaln:
  216. cmpop:=OC_EQ;
  217. unequaln:
  218. cmpop:=OC_NE;
  219. else
  220. internalerror(2015031505);
  221. end;
  222. if nf_swapped in flags then
  223. cmpop:=swap_opcmp(cmpop);
  224. location_reset(location,LOC_REGISTER,OS_8);
  225. location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,llvmbool1type);
  226. if right.location.loc=LOC_CONSTANT then
  227. current_asmdata.CurrAsmList.concat(taillvm.op_reg_cond_size_reg_const(la_icmp,
  228. location.register,cmpop,left.resultdef,left.location.register,right.location.value64))
  229. else
  230. current_asmdata.CurrAsmList.concat(taillvm.op_reg_cond_size_reg_reg(la_icmp,
  231. location.register,cmpop,left.resultdef,left.location.register,right.location.register));
  232. tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
  233. hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,llvmbool1type,resultdef,location.register,tmpreg);
  234. location.register:=tmpreg;
  235. end;
  236. procedure tllvmaddnode.second_add64bit;
  237. begin
  238. second_addordinal;
  239. end;
  240. procedure tllvmaddnode.second_cmp64bit;
  241. begin
  242. second_cmpordinal;
  243. end;
  244. procedure tllvmaddnode.second_addfloat;
  245. var
  246. tmpreg: tregister;
  247. op : tllvmop;
  248. llvmfpcmp : tllvmfpcmp;
  249. size : tdef;
  250. begin
  251. pass_left_right;
  252. { get the operands in the correct order; there are no special cases here,
  253. everything is register-based }
  254. if nf_swapped in flags then
  255. swapleftright;
  256. { put both operands in a register }
  257. hlcg.location_force_fpureg(current_asmdata.CurrAsmList,right.location,right.resultdef,true);
  258. hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
  259. { see comment in thlcgllvm.a_loadfpu_ref_reg }
  260. if tfloatdef(left.resultdef).floattype in [s64comp,s64currency] then
  261. size:=sc80floattype
  262. else
  263. size:=left.resultdef;
  264. if nodetype in [ltn,lten,gtn,gten,equaln,unequaln] then
  265. begin
  266. case nodetype of
  267. ltn:
  268. llvmfpcmp:=lfc_olt;
  269. lten:
  270. llvmfpcmp:=lfc_ole;
  271. gtn:
  272. llvmfpcmp:=lfc_ogt;
  273. gten:
  274. llvmfpcmp:=lfc_oge;
  275. equaln:
  276. llvmfpcmp:=lfc_oeq;
  277. unequaln:
  278. llvmfpcmp:=lfc_une;
  279. else
  280. internalerror(2015031506);
  281. end;
  282. location_reset(location,LOC_REGISTER,OS_8);
  283. location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,llvmbool1type);
  284. current_asmdata.CurrAsmList.concat(taillvm.op_reg_fpcond_size_reg_reg(la_fcmp ,
  285. location.register,llvmfpcmp,size,left.location.register,right.location.register));
  286. tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
  287. hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,llvmbool1type,resultdef,location.register,tmpreg);
  288. location.register:=tmpreg;
  289. end
  290. else
  291. begin
  292. case nodetype of
  293. addn :
  294. op:=la_fadd;
  295. muln :
  296. op:=la_fmul;
  297. subn :
  298. op:=la_fsub;
  299. slashn :
  300. op:=la_fdiv;
  301. else
  302. internalerror(2013102401);
  303. end;
  304. location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
  305. location.register:=hlcg.getfpuregister(current_asmdata.CurrAsmList,resultdef);
  306. current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_reg_reg(op,location.register,size,
  307. left.location.register,right.location.register))
  308. end;
  309. end;
  310. procedure tllvmaddnode.second_cmpfloat;
  311. begin
  312. second_addfloat;
  313. end;
  314. begin
  315. caddnode:=tllvmaddnode;
  316. end.