ncpumat.pas 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. {
  2. Copyright (c) 1998-2002, 2014 by Florian Klaempfl and Jonas Maebe
  3. Generate AArch64 assembler 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 ncpumat;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. node,nmat,ncgmat;
  22. type
  23. taarch64moddivnode = class(tmoddivnode)
  24. procedure pass_generate_code;override;
  25. end;
  26. taarch64notnode = class(tcgnotnode)
  27. procedure second_boolean;override;
  28. end;
  29. taarch64unaryminusnode = class(tcgunaryminusnode)
  30. procedure second_float; override;
  31. end;
  32. implementation
  33. uses
  34. globtype,systems,constexp,
  35. cutils,verbose,globals,
  36. symconst,symdef,
  37. aasmbase,aasmcpu,aasmtai,aasmdata,
  38. defutil,
  39. cgbase,cgobj,hlcgobj,pass_2,procinfo,
  40. ncon,
  41. cpubase,
  42. ncgutil,cgcpu,cgutils;
  43. {*****************************************************************************
  44. taarch64moddivnode
  45. *****************************************************************************}
  46. procedure taarch64moddivnode.pass_generate_code;
  47. var
  48. op : tasmop;
  49. tmpreg,
  50. numerator,
  51. divider,
  52. resultreg : tregister;
  53. hl : tasmlabel;
  54. overflowloc: tlocation;
  55. begin
  56. secondpass(left);
  57. secondpass(right);
  58. { set result location }
  59. location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
  60. location.register:=cg.getintregister(current_asmdata.CurrAsmList,def_cgsize(resultdef));
  61. resultreg:=location.register;
  62. { put numerator in register }
  63. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
  64. numerator:=left.location.register;
  65. { load divider in a register }
  66. hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,true);
  67. divider:=right.location.register;
  68. { start division }
  69. if is_signed(left.resultdef) then
  70. op:=A_SDIV
  71. else
  72. op:=A_UDIV;
  73. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,numerator,divider));
  74. { no divide-by-zero detection available in hardware, emulate (if it's a
  75. constant, this will have been detected earlier already) }
  76. if (right.nodetype<>ordconstn) then
  77. begin
  78. current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_CMP,
  79. right.location.register,0));
  80. current_asmdata.getjumplabel(hl);
  81. current_asmdata.CurrAsmList.concat(taicpu.op_cond_sym(A_B,C_NE,hl));
  82. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_DIVBYZERO',false);
  83. cg.a_label(current_asmdata.CurrAsmList,hl);
  84. end;
  85. { in case of overflow checking, also check for low(int64) div (-1)
  86. (no hardware support for this either) }
  87. if (cs_check_overflow in current_settings.localswitches) and
  88. is_signed(left.resultdef) and
  89. ((right.nodetype<>ordconstn) or
  90. (tordconstnode(right).value=-1)) then
  91. begin
  92. { num=ffff... and div=8000... <=>
  93. num xor not(div xor 8000...) = 0
  94. (and we have the "eon" operation, which performs "xor not(...)" }
  95. tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,left.resultdef);
  96. hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_XOR,left.resultdef,low(int64),left.location.register,tmpreg);
  97. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_EON,
  98. tmpreg,left.location.register,tmpreg));
  99. current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_CMP,tmpreg,0));
  100. { now the zero/equal flag is set in case we divided low(int64) by
  101. (-1) }
  102. location_reset(overflowloc,LOC_FLAGS,OS_NO);
  103. overflowloc.resflags:=F_EQ;
  104. cg.g_overflowcheck_loc(current_asmdata.CurrAsmList,location,resultdef,overflowloc);
  105. end;
  106. { in case of modulo, multiply result again by the divider and subtract
  107. from the numerator }
  108. if nodetype=modn then
  109. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_reg(A_MSUB,resultreg,
  110. resultreg,divider,numerator));
  111. end;
  112. {*****************************************************************************
  113. taarch64notnode
  114. *****************************************************************************}
  115. procedure taarch64notnode.second_boolean;
  116. begin
  117. if not handle_locjump then
  118. begin
  119. secondpass(left);
  120. case left.location.loc of
  121. LOC_FLAGS :
  122. begin
  123. location_copy(location,left.location);
  124. inverse_flags(location.resflags);
  125. end;
  126. LOC_REGISTER, LOC_CREGISTER,
  127. LOC_REFERENCE, LOC_CREFERENCE,
  128. LOC_SUBSETREG, LOC_CSUBSETREG,
  129. LOC_SUBSETREF, LOC_CSUBSETREF:
  130. begin
  131. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
  132. current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_CMP,
  133. left.location.register,0));
  134. location_reset(location,LOC_FLAGS,OS_NO);
  135. location.resflags:=F_EQ;
  136. end;
  137. else
  138. internalerror(2003042401);
  139. end;
  140. end;
  141. end;
  142. {*****************************************************************************
  143. taarch64unaryminusnode
  144. *****************************************************************************}
  145. procedure taarch64unaryminusnode.second_float;
  146. begin
  147. secondpass(left);
  148. hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
  149. location_reset(location,LOC_MMREGISTER,def_cgsize(resultdef));
  150. location.register:=cg.getmmregister(current_asmdata.CurrAsmList,location.size);
  151. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FNEG,location.register,left.location.register));
  152. end;
  153. begin
  154. cmoddivnode:=taarch64moddivnode;
  155. cnotnode:=taarch64notnode;
  156. cunaryminusnode:=taarch64unaryminusnode;
  157. end.