nx64mat.pas 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Generate x86-64 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 nx64mat;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. node,nmat,ncgmat,nx86mat;
  22. type
  23. tx8664moddivnode = class(tmoddivnode)
  24. procedure pass_generate_code;override;
  25. end;
  26. tx8664shlshrnode = class(tshlshrnode)
  27. procedure pass_generate_code;override;
  28. end;
  29. tx8664unaryminusnode = class(tx86unaryminusnode)
  30. end;
  31. tx8664notnode = class(tx86notnode)
  32. end;
  33. implementation
  34. uses
  35. globtype,systems,constexp,
  36. cutils,verbose,globals,
  37. symconst,symdef,aasmbase,aasmtai,aasmdata,defutil,
  38. pass_1,pass_2,
  39. ncon,
  40. cpubase,cpuinfo,
  41. cgbase,cgutils,cga,cgobj,hlcgobj,cgx86,
  42. ncgutil;
  43. {*****************************************************************************
  44. TX8664MODDIVNODE
  45. *****************************************************************************}
  46. procedure tx8664moddivnode.pass_generate_code;
  47. var
  48. hreg1,hreg2,rega,regd:Tregister;
  49. power:longint;
  50. op:Tasmop;
  51. cgsize:TCgSize;
  52. opsize:topsize;
  53. begin
  54. secondpass(left);
  55. if codegenerror then
  56. exit;
  57. secondpass(right);
  58. if codegenerror then
  59. exit;
  60. { put numerator in register }
  61. cgsize:=def_cgsize(resultdef);
  62. opsize:=TCGSize2OpSize[cgsize];
  63. case cgsize of
  64. OS_S64,OS_64:
  65. begin
  66. rega:=NR_RAX;
  67. regd:=NR_RDX;
  68. end;
  69. OS_S32,OS_32:
  70. begin
  71. rega:=NR_EAX;
  72. regd:=NR_EDX;
  73. end;
  74. else
  75. internalerror(2013102702);
  76. end;
  77. location_reset(location,LOC_REGISTER,cgsize);
  78. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef,false);
  79. hreg1:=left.location.register;
  80. if (nodetype=divn) and (right.nodetype=ordconstn) and
  81. ispowerof2(int64(tordconstnode(right).value),power) then
  82. begin
  83. { for signed numbers, the numerator must be adjusted before the
  84. shift instruction, but not wih unsigned numbers! Otherwise,
  85. "Cardinal($ffffffff) div 16" overflows! (JM) }
  86. if is_signed(left.resultdef) Then
  87. begin
  88. { use a sequence without jumps, saw this in
  89. comp.compilers (JM) }
  90. { no jumps, but more operations }
  91. hreg2:=cg.getintregister(current_asmdata.CurrAsmList,cgsize);
  92. emit_reg_reg(A_MOV,opsize,hreg1,hreg2);
  93. {If the left value is signed, hreg2=$ffffffff, otherwise 0.}
  94. emit_const_reg(A_SAR,opsize,63,hreg2);
  95. {If signed, hreg2=right value-1, otherwise 0.}
  96. { (don't use emit_const_reg, because if value>high(longint)
  97. then it must first be loaded into a register) }
  98. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_AND,cgsize,tordconstnode(right).value-1,hreg2);
  99. { add to the left value }
  100. emit_reg_reg(A_ADD,opsize,hreg2,hreg1);
  101. { do the shift }
  102. emit_const_reg(A_SAR,opsize,power,hreg1);
  103. end
  104. else
  105. emit_const_reg(A_SHR,opsize,power,hreg1);
  106. location.register:=hreg1;
  107. end
  108. else
  109. begin
  110. {Bring denominator to a register.}
  111. cg.getcpuregister(current_asmdata.CurrAsmList,rega);
  112. emit_reg_reg(A_MOV,opsize,hreg1,rega);
  113. cg.getcpuregister(current_asmdata.CurrAsmList,regd);
  114. {Sign extension depends on the left type.}
  115. if is_signed(left.resultdef) then
  116. case left.resultdef.size of
  117. 8:
  118. emit_none(A_CQO,S_NO);
  119. 4:
  120. emit_none(A_CDQ,S_NO);
  121. else
  122. internalerror(2013102701);
  123. end
  124. else
  125. emit_reg_reg(A_XOR,opsize,regd,regd);
  126. {Division depends on the right type.}
  127. if is_signed(right.resultdef) then
  128. op:=A_IDIV
  129. else
  130. op:=A_DIV;
  131. if right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
  132. emit_ref(op,opsize,right.location.reference)
  133. else if right.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  134. emit_reg(op,opsize,right.location.register)
  135. else
  136. begin
  137. hreg1:=cg.getintregister(current_asmdata.CurrAsmList,right.location.size);
  138. hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,right.resultdef,right.resultdef,right.location,hreg1);
  139. emit_reg(op,opsize,hreg1);
  140. end;
  141. { Copy the result into a new register. Release R/EAX & R/EDX.}
  142. cg.ungetcpuregister(current_asmdata.CurrAsmList,regd);
  143. cg.ungetcpuregister(current_asmdata.CurrAsmList,rega);
  144. location.register:=cg.getintregister(current_asmdata.CurrAsmList,cgsize);
  145. if nodetype=divn then
  146. cg.a_load_reg_reg(current_asmdata.CurrAsmList,cgsize,cgsize,rega,location.register)
  147. else
  148. cg.a_load_reg_reg(current_asmdata.CurrAsmList,cgsize,cgsize,regd,location.register);
  149. end;
  150. end;
  151. {*****************************************************************************
  152. TX8664SHLRSHRNODE
  153. *****************************************************************************}
  154. procedure tx8664shlshrnode.pass_generate_code;
  155. var
  156. op : Tasmop;
  157. opsize : tcgsize;
  158. mask : aint;
  159. begin
  160. secondpass(left);
  161. secondpass(right);
  162. { determine operator }
  163. if nodetype=shln then
  164. op:=A_SHL
  165. else
  166. op:=A_SHR;
  167. { special treatment of 32bit values for backwards compatibility }
  168. { mul optimizations require to keep the sign (FK) }
  169. if left.resultdef.size<=4 then
  170. begin
  171. if is_signed(left.resultdef) then
  172. opsize:=OS_S32
  173. else
  174. opsize:=OS_32;
  175. mask:=31;
  176. end
  177. else
  178. begin
  179. if is_signed(left.resultdef) then
  180. opsize:=OS_S64
  181. else
  182. opsize:=OS_64;
  183. mask:=63;
  184. end;
  185. { load left operators in a register }
  186. location_copy(location,left.location);
  187. hlcg.location_force_reg(current_asmdata.CurrAsmList,location,left.resultdef,cgsize_orddef(opsize),false);
  188. { shifting by a constant directly coded: }
  189. if (right.nodetype=ordconstn) then
  190. emit_const_reg(op,tcgsize2opsize[opsize],tordconstnode(right).value and mask,location.register)
  191. else
  192. begin
  193. { load right operators in a RCX }
  194. cg.getcpuregister(current_asmdata.CurrAsmList,NR_RCX);
  195. hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,right.resultdef,osuinttype,right.location,NR_RCX);
  196. { right operand is in ECX }
  197. cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_RCX);
  198. emit_reg_reg(op,tcgsize2opsize[opsize],NR_CL,location.register);
  199. end;
  200. end;
  201. begin
  202. cunaryminusnode:=tx8664unaryminusnode;
  203. cmoddivnode:=tx8664moddivnode;
  204. cshlshrnode:=tx8664shlshrnode;
  205. cnotnode:=tx8664notnode;
  206. end.