2
0

nllvmmat.pas 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. {
  2. Copyright (c) 2014 Jonas Maebe
  3. Generate LLVM IR for math 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 nllvmmat;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. symtype,
  22. node, nmat, ncgmat, ncghlmat, cgbase;
  23. type
  24. tllvmmoddivnode = class(tcgmoddivnode)
  25. procedure pass_generate_code; override;
  26. end;
  27. tllvmshlshrnode = class(tcgshlshrnode)
  28. end;
  29. Tllvmunaryminusnode = class(tcgunaryminusnode)
  30. procedure emit_float_sign_change(r: tregister; _size : tdef);override;
  31. end;
  32. tllvmnotnode = class(tcghlnotnode)
  33. end;
  34. implementation
  35. uses
  36. globtype, systems, constexp,
  37. cutils, verbose, globals,
  38. symconst, symdef,
  39. aasmbase, aasmllvm, aasmtai, aasmdata,
  40. defutil,
  41. procinfo,
  42. hlcgobj, pass_2,
  43. ncon,
  44. llvmbase,
  45. ncgutil, cgutils;
  46. {*****************************************************************************
  47. tllvmmoddivnode
  48. *****************************************************************************}
  49. procedure tllvmmoddivnode.pass_generate_code;
  50. var
  51. op: tllvmop;
  52. hl: tasmlabel;
  53. tmpovreg1,
  54. tmpovreg2: tregister;
  55. ovloc: tlocation;
  56. begin
  57. secondpass(left);
  58. secondpass(right);
  59. if is_signed(left.resultdef) then
  60. if nodetype=divn then
  61. op:=la_sdiv
  62. else
  63. op:=la_srem
  64. else if nodetype=divn then
  65. op:=la_udiv
  66. else
  67. op:=la_urem;
  68. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef,true);
  69. if right.location.loc<>LOC_CONSTANT then
  70. begin
  71. hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,resultdef,true);
  72. { in llvm, div-by-zero is undefined on all platforms -> need explicit
  73. check }
  74. current_asmdata.getjumplabel(hl);
  75. hlcg.a_cmp_const_loc_label(current_asmdata.CurrAsmList,resultdef,OC_NE,0,right.location,hl);
  76. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_divbyzero',[],nil).resetiftemp;
  77. hlcg.a_label(current_asmdata.CurrAsmList,hl);
  78. end;
  79. if (cs_check_overflow in current_settings.localswitches) and
  80. is_signed(left.resultdef) and
  81. ((right.nodetype<>ordconstn) or
  82. (tordconstnode(right).value=-1)) then
  83. begin
  84. current_asmdata.getjumplabel(hl);
  85. location_reset(ovloc,LOC_REGISTER,OS_8);
  86. ovloc.register:=hlcg.getintregister(current_asmdata.CurrAsmList,llvmbool1type);
  87. if right.nodetype=ordconstn then
  88. current_asmdata.CurrAsmList.concat(taillvm.op_reg_cond_size_reg_const(la_icmp,ovloc.register,OC_EQ,resultdef,left.location.register,low(int64)))
  89. else
  90. begin
  91. tmpovreg1:=hlcg.getintregister(current_asmdata.CurrAsmList,llvmbool1type);
  92. tmpovreg2:=hlcg.getintregister(current_asmdata.CurrAsmList,llvmbool1type);
  93. current_asmdata.CurrAsmList.concat(taillvm.op_reg_cond_size_reg_const(la_icmp,tmpovreg1,OC_EQ,resultdef,left.location.register,low(int64)));
  94. current_asmdata.CurrAsmList.concat(taillvm.op_reg_cond_size_reg_const(la_icmp,tmpovreg2,OC_EQ,resultdef,right.location.register,-1));
  95. hlcg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_AND,llvmbool1type,tmpovreg1,tmpovreg2,ovloc.register);
  96. end;
  97. hlcg.g_overflowCheck_loc(current_asmdata.CurrAsmList,location,resultdef,ovloc);
  98. end;
  99. location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
  100. location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
  101. if right.location.loc=LOC_CONSTANT then
  102. current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_reg_const(op,location.register,resultdef,left.location.register,right.location.value))
  103. else
  104. current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_reg_reg(op,location.register,resultdef,left.location.register,right.location.register))
  105. end;
  106. {*****************************************************************************
  107. Tllvmunaryminusnode
  108. *****************************************************************************}
  109. procedure Tllvmunaryminusnode.emit_float_sign_change(r: tregister; _size : tdef);
  110. var
  111. minusonereg: tregister;
  112. begin
  113. { multiply with -1 instead of subtracting from 0, because otherwise we -x
  114. won't turn into -0.0 if x was 0.0 (0.0 - 0.0 = 0.0, but -1.0 * 0.0 = -0.0 }
  115. if _size.typ<>floatdef then
  116. internalerror(2014012212);
  117. minusonereg:=hlcg.getfpuregister(current_asmdata.CurrAsmList,_size);
  118. case tfloatdef(_size).floattype of
  119. s32real,s64real:
  120. current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_fpconst_size(la_bitcast,minusonereg,_size,-1.0,_size));
  121. { comp and currency are handled as int64 at the llvm level }
  122. s64comp,
  123. s64currency:
  124. begin
  125. { sc80floattype instead of _size, see comment in thlcgllvm.a_loadfpu_ref_reg }
  126. _size:=sc80floattype;
  127. current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_const_size(la_sitofp,minusonereg,s64inttype,-1,_size));
  128. end;
  129. {$ifdef cpuextended}
  130. s80real,sc80real:
  131. current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_fpconst80_size(la_bitcast,minusonereg,_size,-1.0,_size));
  132. {$endif cpuextended}
  133. else
  134. internalerror(2016112701);
  135. end;
  136. current_asmdata.CurrAsmList.Concat(taillvm.op_reg_size_reg_reg(la_fmul,r,_size,minusonereg,r));
  137. end;
  138. begin
  139. cmoddivnode := tllvmmoddivnode;
  140. cshlshrnode := tllvmshlshrnode;
  141. cnotnode := tllvmnotnode;
  142. cunaryminusnode := Tllvmunaryminusnode;
  143. end.