2
0

nllvmadd.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  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. procedure second_opvector; override;
  36. end;
  37. implementation
  38. uses
  39. verbose,globtype,globals,cutils,
  40. aasmdata,
  41. symconst,symtype,symdef,defutil,
  42. llvmbase,aasmllvm,aasmllvmmetadata,
  43. cgbase,cgutils,pass_1,
  44. hlcgobj,
  45. nadd,ncal,ncnv,ncon
  46. ;
  47. { tllvmaddnode }
  48. function tllvmaddnode.pass_1: tnode;
  49. var
  50. exceptmode: ansistring;
  51. intrname: string;
  52. iscompcurrency: boolean;
  53. begin
  54. result:=inherited pass_1;
  55. if not assigned(result) and
  56. is_fpu(left.resultdef) and
  57. not(cs_opt_fastmath in current_settings.optimizerswitches) then
  58. begin
  59. case nodetype of
  60. addn:
  61. begin
  62. intrname:='LLVM_EXPERIMENTAL_CONSTRAINED_FADD';
  63. end;
  64. subn:
  65. begin
  66. intrname:='LLVM_EXPERIMENTAL_CONSTRAINED_FSUB';
  67. end;
  68. muln:
  69. begin
  70. intrname:='LLVM_EXPERIMENTAL_CONSTRAINED_FMUL';
  71. end;
  72. slashn:
  73. begin
  74. intrname:='LLVM_EXPERIMENTAL_CONSTRAINED_FDIV';
  75. end;
  76. else
  77. begin
  78. intrname:='';
  79. end;
  80. end;
  81. if intrname<>'' then
  82. begin
  83. iscompcurrency:=tfloatdef(left.resultdef).floattype in [s64currency,s64comp];
  84. if iscompcurrency then
  85. begin
  86. inserttypeconv_internal(left,s80floattype);
  87. inserttypeconv_internal(right,s80floattype);
  88. end;
  89. exceptmode:=llvm_constrainedexceptmodestring;
  90. result:=ccallnode.createintern(intrname,
  91. ccallparanode.create(cstringconstnode.createpchar(ansistring2pchar(exceptmode),length(exceptmode),llvm_metadatatype),
  92. ccallparanode.create(cstringconstnode.createpchar(ansistring2pchar('round.dynamic'),length('round.dynamic'),llvm_metadatatype),
  93. ccallparanode.create(right,
  94. ccallparanode.create(left,nil)
  95. )
  96. )
  97. )
  98. );
  99. if iscompcurrency then
  100. begin
  101. result:=ctypeconvnode.create_internal(result,resultdef);
  102. end;
  103. left:=nil;
  104. right:=nil;
  105. exit;
  106. end;
  107. end;
  108. { there are no flags in LLVM }
  109. if expectloc=LOC_FLAGS then
  110. expectloc:=LOC_REGISTER;
  111. end;
  112. procedure tllvmaddnode.force_reg_left_right(allow_swap, allow_constant: boolean);
  113. begin
  114. { comparison with pointer -> no immediate, as icmp can't handle pointer
  115. immediates (except for nil as "null", but we don't generate that) }
  116. if (nodetype in [equaln,unequaln,gtn,gten,ltn,lten]) and
  117. (is_address(left.resultdef) or
  118. is_address(right.resultdef)) then
  119. allow_constant:=false;
  120. inherited;
  121. { pointer - pointer = integer -> make all defs integer since we can't
  122. subtract pointers }
  123. if (nodetype=subn) and
  124. is_address(left.resultdef) and
  125. is_address(right.resultdef) then
  126. begin
  127. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef,true);
  128. hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,resultdef,true);
  129. end
  130. { pointer +/- integer -> make defs the same since a_op_* only gets a
  131. single type as argument }
  132. else if (nodetype in [addn,subn]) and
  133. (is_address(left.resultdef)<>is_address(right.resultdef)) then
  134. begin
  135. { the result is a pointerdef -> typecast both arguments to pointer;
  136. a_op_*_reg will convert them back to integer as needed }
  137. if not is_address(left.resultdef) then
  138. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef,true);
  139. if not is_address(right.resultdef) then
  140. hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,resultdef,true);
  141. end;
  142. end;
  143. procedure tllvmaddnode.second_cmpsmallset;
  144. var
  145. tmpreg,
  146. tmpreg2: tregister;
  147. cmpop : topcmp;
  148. begin
  149. pass_left_right;
  150. location_reset(location,LOC_REGISTER,OS_8);
  151. location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,llvmbool1type);
  152. force_reg_left_right(false,false);
  153. case nodetype of
  154. equaln,
  155. unequaln:
  156. begin
  157. if nodetype=equaln then
  158. cmpop:=OC_EQ
  159. else
  160. cmpop:=OC_NE;
  161. current_asmdata.CurrAsmList.concat(taillvm.op_reg_cond_size_reg_reg(la_icmp,
  162. location.register,cmpop,left.resultdef,left.location.register,right.location.register));
  163. end;
  164. lten,
  165. gten:
  166. begin
  167. if (not(nf_swapped in flags) and
  168. (nodetype = lten)) or
  169. ((nf_swapped in flags) and
  170. (nodetype = gten)) then
  171. swapleftright;
  172. { set1<=set2 <-> set2 and not(set1) = 0 }
  173. tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,left.resultdef);
  174. hlcg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_NOT,left.resultdef,left.location.register,tmpreg);
  175. tmpreg2:=hlcg.getintregister(current_asmdata.CurrAsmList,left.resultdef);
  176. hlcg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_AND,left.resultdef,right.location.register,tmpreg,tmpreg2);
  177. current_asmdata.CurrAsmList.concat(taillvm.op_reg_cond_size_reg_const(la_icmp,
  178. location.register,OC_EQ,left.resultdef,tmpreg2,0));
  179. end;
  180. else
  181. internalerror(2012042701);
  182. end;
  183. tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
  184. hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,llvmbool1type,resultdef,location.register,tmpreg);
  185. location.register:=tmpreg;
  186. end;
  187. procedure tllvmaddnode.second_cmpordinal;
  188. var
  189. tmpreg: tregister;
  190. cmpop: topcmp;
  191. unsigned : boolean;
  192. begin
  193. pass_left_right;
  194. force_reg_left_right(true,true);
  195. unsigned:=not(is_signed(left.resultdef)) or
  196. not(is_signed(right.resultdef));
  197. case nodetype of
  198. ltn:
  199. if unsigned then
  200. cmpop:=OC_B
  201. else
  202. cmpop:=OC_LT;
  203. lten:
  204. if unsigned then
  205. cmpop:=OC_BE
  206. else
  207. cmpop:=OC_LTE;
  208. gtn:
  209. if unsigned then
  210. cmpop:=OC_A
  211. else
  212. cmpop:=OC_GT;
  213. gten:
  214. if unsigned then
  215. cmpop:=OC_AE
  216. else
  217. cmpop:=OC_GTE;
  218. equaln:
  219. cmpop:=OC_EQ;
  220. unequaln:
  221. cmpop:=OC_NE;
  222. else
  223. internalerror(2015031505);
  224. end;
  225. if nf_swapped in flags then
  226. cmpop:=swap_opcmp(cmpop);
  227. location_reset(location,LOC_REGISTER,OS_8);
  228. location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,llvmbool1type);
  229. if right.location.loc=LOC_CONSTANT then
  230. current_asmdata.CurrAsmList.concat(taillvm.op_reg_cond_size_reg_const(la_icmp,
  231. location.register,cmpop,left.resultdef,left.location.register,right.location.value64))
  232. else
  233. current_asmdata.CurrAsmList.concat(taillvm.op_reg_cond_size_reg_reg(la_icmp,
  234. location.register,cmpop,left.resultdef,left.location.register,right.location.register));
  235. tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
  236. hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,llvmbool1type,resultdef,location.register,tmpreg);
  237. location.register:=tmpreg;
  238. end;
  239. procedure tllvmaddnode.second_add64bit;
  240. begin
  241. second_addordinal;
  242. end;
  243. procedure tllvmaddnode.second_cmp64bit;
  244. begin
  245. second_cmpordinal;
  246. end;
  247. procedure tllvmaddnode.second_addfloat;
  248. var
  249. tmpreg: tregister;
  250. op : tllvmop;
  251. llvmfpcmp : tllvmfpcmp;
  252. size : tdef;
  253. begin
  254. pass_left_right;
  255. { get the operands in the correct order; there are no special cases here,
  256. everything is register-based }
  257. if nf_swapped in flags then
  258. swapleftright;
  259. { put both operands in a register }
  260. hlcg.location_force_fpureg(current_asmdata.CurrAsmList,right.location,right.resultdef,true);
  261. hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
  262. { see comment in thlcgllvm.a_loadfpu_ref_reg }
  263. if tfloatdef(left.resultdef).floattype in [s64comp,s64currency] then
  264. size:=sc80floattype
  265. else
  266. size:=left.resultdef;
  267. if nodetype in [ltn,lten,gtn,gten,equaln,unequaln] then
  268. begin
  269. case nodetype of
  270. ltn:
  271. llvmfpcmp:=lfc_olt;
  272. lten:
  273. llvmfpcmp:=lfc_ole;
  274. gtn:
  275. llvmfpcmp:=lfc_ogt;
  276. gten:
  277. llvmfpcmp:=lfc_oge;
  278. equaln:
  279. llvmfpcmp:=lfc_oeq;
  280. unequaln:
  281. llvmfpcmp:=lfc_une;
  282. else
  283. internalerror(2015031506);
  284. end;
  285. location_reset(location,LOC_REGISTER,OS_8);
  286. location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,llvmbool1type);
  287. current_asmdata.CurrAsmList.concat(taillvm.op_reg_fpcond_size_reg_reg(la_fcmp ,
  288. location.register,llvmfpcmp,size,left.location.register,right.location.register));
  289. tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
  290. hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,llvmbool1type,resultdef,location.register,tmpreg);
  291. location.register:=tmpreg;
  292. end
  293. else
  294. begin
  295. case nodetype of
  296. addn :
  297. op:=la_fadd;
  298. muln :
  299. op:=la_fmul;
  300. subn :
  301. op:=la_fsub;
  302. slashn :
  303. op:=la_fdiv;
  304. else
  305. internalerror(2013102401);
  306. end;
  307. location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
  308. location.register:=hlcg.getfpuregister(current_asmdata.CurrAsmList,resultdef);
  309. current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_reg_reg(op,location.register,size,
  310. left.location.register,right.location.register))
  311. end;
  312. end;
  313. procedure tllvmaddnode.second_cmpfloat;
  314. begin
  315. second_addfloat;
  316. end;
  317. procedure tllvmaddnode.second_opvector;
  318. var
  319. lv, rv: tdef;
  320. hreg: tregister;
  321. tempref: treference;
  322. op: tllvmop;
  323. isfloat: boolean;
  324. begin
  325. if not is_vector(left.resultdef) or
  326. not is_vector(right.resultdef) or
  327. not is_vector(resultdef) or
  328. not tarraydef(resultdef).is_hwvector then
  329. internalerror(2022090710);
  330. pass_left_right;
  331. if (nf_swapped in flags) then
  332. swapleftright;
  333. isfloat:=tarraydef(left.resultdef).elementdef.typ=floatdef;
  334. case nodetype of
  335. addn :
  336. if isfloat then
  337. op:=la_fadd
  338. else
  339. op:=la_add;
  340. muln :
  341. if isfloat then
  342. op:=la_fmul
  343. else
  344. op:=la_mul;
  345. subn :
  346. if isfloat then
  347. op:=la_fsub
  348. else
  349. op:=la_sub;
  350. slashn :
  351. if isfloat then
  352. op:=la_fdiv
  353. else if is_signed(tarraydef(left.resultdef).elementdef) then
  354. op:=la_sdiv
  355. else
  356. op:=la_udiv;
  357. xorn:
  358. if not isfloat then
  359. op:=la_xor
  360. else
  361. internalerror(2022090711);
  362. orn:
  363. if not isfloat then
  364. op:=la_or
  365. else
  366. internalerror(2022090712);
  367. andn:
  368. if not isfloat then
  369. op:=la_and
  370. else
  371. internalerror(2022090712);
  372. else
  373. internalerror(200610073);
  374. end;
  375. location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
  376. lv:=to_hwvectordef(tarraydef(left.resultdef),false);
  377. rv:=to_hwvectordef(tarraydef(right.resultdef),false);
  378. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,lv,false);
  379. hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,rv,false);
  380. location.register:=hlcg.getregisterfordef(current_asmdata.CurrAsmList,resultdef);
  381. current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_reg_reg(op,location.register,lv,left.location.register,right.location.register));
  382. end;
  383. begin
  384. caddnode:=tllvmaddnode;
  385. end.