nx64mat.pas 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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,cgx86,
  42. ncgutil;
  43. {*****************************************************************************
  44. TX8664MODDIVNODE
  45. *****************************************************************************}
  46. procedure tx8664moddivnode.pass_generate_code;
  47. var
  48. hreg1,hreg2:Tregister;
  49. power:longint;
  50. op:Tasmop;
  51. begin
  52. secondpass(left);
  53. if codegenerror then
  54. exit;
  55. secondpass(right);
  56. if codegenerror then
  57. exit;
  58. { put numerator in register }
  59. location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
  60. location_force_reg(current_asmdata.CurrAsmList,left.location,location.size,false);
  61. hreg1:=left.location.register;
  62. if (nodetype=divn) and (right.nodetype=ordconstn) and
  63. ispowerof2(int64(tordconstnode(right).value),power) then
  64. begin
  65. { for signed numbers, the numerator must be adjusted before the
  66. shift instruction, but not wih unsigned numbers! Otherwise,
  67. "Cardinal($ffffffff) div 16" overflows! (JM) }
  68. if is_signed(left.resultdef) Then
  69. begin
  70. { use a sequence without jumps, saw this in
  71. comp.compilers (JM) }
  72. { no jumps, but more operations }
  73. hreg2:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  74. emit_reg_reg(A_MOV,S_Q,hreg1,hreg2);
  75. {If the left value is signed, hreg2=$ffffffff, otherwise 0.}
  76. emit_const_reg(A_SAR,S_Q,63,hreg2);
  77. {If signed, hreg2=right value-1, otherwise 0.}
  78. emit_const_reg(A_AND,S_Q,tordconstnode(right).value-1,hreg2);
  79. { add to the left value }
  80. emit_reg_reg(A_ADD,S_Q,hreg2,hreg1);
  81. { do the shift }
  82. emit_const_reg(A_SAR,S_Q,power,hreg1);
  83. end
  84. else
  85. emit_const_reg(A_SHR,S_Q,power,hreg1);
  86. location.register:=hreg1;
  87. end
  88. else
  89. begin
  90. {Bring denominator to a register.}
  91. cg.getcpuregister(current_asmdata.CurrAsmList,NR_RAX);
  92. emit_reg_reg(A_MOV,S_Q,hreg1,NR_RAX);
  93. cg.getcpuregister(current_asmdata.CurrAsmList,NR_RDX);
  94. {Sign extension depends on the left type.}
  95. if torddef(left.resultdef).ordtype=u64bit then
  96. emit_reg_reg(A_XOR,S_Q,NR_RDX,NR_RDX)
  97. else
  98. emit_none(A_CQO,S_NO);
  99. {Division depends on the right type.}
  100. if Torddef(right.resultdef).ordtype=u64bit then
  101. op:=A_DIV
  102. else
  103. op:=A_IDIV;
  104. if right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
  105. emit_ref(op,S_Q,right.location.reference)
  106. else if right.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  107. emit_reg(op,S_Q,right.location.register)
  108. else
  109. begin
  110. hreg1:=cg.getintregister(current_asmdata.CurrAsmList,right.location.size);
  111. cg.a_load_loc_reg(current_asmdata.CurrAsmList,OS_64,right.location,hreg1);
  112. emit_reg(op,S_Q,hreg1);
  113. end;
  114. { Copy the result into a new register. Release RAX & RDX.}
  115. cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_RDX);
  116. cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_RAX);
  117. location.register:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  118. if nodetype=divn then
  119. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_RAX,location.register)
  120. else
  121. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_RDX,location.register);
  122. end;
  123. end;
  124. {*****************************************************************************
  125. TX8664SHLRSHRNODE
  126. *****************************************************************************}
  127. procedure tx8664shlshrnode.pass_generate_code;
  128. var
  129. op : Tasmop;
  130. opsize : tcgsize;
  131. mask : aint;
  132. begin
  133. secondpass(left);
  134. secondpass(right);
  135. { determine operator }
  136. if nodetype=shln then
  137. op:=A_SHL
  138. else
  139. op:=A_SHR;
  140. { special treatment of 32bit values for backwards compatibility }
  141. { mul optimizations require to keep the sign (FK) }
  142. if left.resultdef.size<=4 then
  143. begin
  144. if is_signed(left.resultdef) then
  145. opsize:=OS_S32
  146. else
  147. opsize:=OS_32;
  148. mask:=31;
  149. end
  150. else
  151. begin
  152. if is_signed(left.resultdef) then
  153. opsize:=OS_S64
  154. else
  155. opsize:=OS_64;
  156. mask:=63;
  157. end;
  158. { load left operators in a register }
  159. location_copy(location,left.location);
  160. location_force_reg(current_asmdata.CurrAsmList,location,opsize,false);
  161. { shifting by a constant directly coded: }
  162. if (right.nodetype=ordconstn) then
  163. emit_const_reg(op,tcgsize2opsize[opsize],tordconstnode(right).value and mask,location.register)
  164. else
  165. begin
  166. { load right operators in a RCX }
  167. cg.getcpuregister(current_asmdata.CurrAsmList,NR_RCX);
  168. cg.a_load_loc_reg(current_asmdata.CurrAsmList,OS_INT,right.location,NR_RCX);
  169. { right operand is in ECX }
  170. cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_RCX);
  171. emit_reg_reg(op,tcgsize2opsize[opsize],NR_CL,location.register);
  172. end;
  173. end;
  174. begin
  175. cunaryminusnode:=tx8664unaryminusnode;
  176. cmoddivnode:=tx8664moddivnode;
  177. cshlshrnode:=tx8664shlshrnode;
  178. cnotnode:=tx8664notnode;
  179. end.