nx64mat.pas 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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: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. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef,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. { (don't use emit_const_reg, because if value>high(longint)
  79. then it must first be loaded into a register) }
  80. cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_AND,OS_S64,tordconstnode(right).value-1,hreg2);
  81. { add to the left value }
  82. emit_reg_reg(A_ADD,S_Q,hreg2,hreg1);
  83. { do the shift }
  84. emit_const_reg(A_SAR,S_Q,power,hreg1);
  85. end
  86. else
  87. emit_const_reg(A_SHR,S_Q,power,hreg1);
  88. location.register:=hreg1;
  89. end
  90. else
  91. begin
  92. {Bring denominator to a register.}
  93. cg.getcpuregister(current_asmdata.CurrAsmList,NR_RAX);
  94. emit_reg_reg(A_MOV,S_Q,hreg1,NR_RAX);
  95. cg.getcpuregister(current_asmdata.CurrAsmList,NR_RDX);
  96. {Sign extension depends on the left type.}
  97. if torddef(left.resultdef).ordtype=u64bit then
  98. emit_reg_reg(A_XOR,S_Q,NR_RDX,NR_RDX)
  99. else
  100. emit_none(A_CQO,S_NO);
  101. {Division depends on the right type.}
  102. if Torddef(right.resultdef).ordtype=u64bit then
  103. op:=A_DIV
  104. else
  105. op:=A_IDIV;
  106. if right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
  107. emit_ref(op,S_Q,right.location.reference)
  108. else if right.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  109. emit_reg(op,S_Q,right.location.register)
  110. else
  111. begin
  112. hreg1:=cg.getintregister(current_asmdata.CurrAsmList,right.location.size);
  113. hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,right.resultdef,u64inttype,right.location,hreg1);
  114. emit_reg(op,S_Q,hreg1);
  115. end;
  116. { Copy the result into a new register. Release RAX & RDX.}
  117. cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_RDX);
  118. cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_RAX);
  119. location.register:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  120. if nodetype=divn then
  121. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_RAX,location.register)
  122. else
  123. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_RDX,location.register);
  124. end;
  125. end;
  126. {*****************************************************************************
  127. TX8664SHLRSHRNODE
  128. *****************************************************************************}
  129. procedure tx8664shlshrnode.pass_generate_code;
  130. var
  131. op : Tasmop;
  132. opsize : tcgsize;
  133. mask : aint;
  134. begin
  135. secondpass(left);
  136. secondpass(right);
  137. { determine operator }
  138. if nodetype=shln then
  139. op:=A_SHL
  140. else
  141. op:=A_SHR;
  142. { special treatment of 32bit values for backwards compatibility }
  143. { mul optimizations require to keep the sign (FK) }
  144. if left.resultdef.size<=4 then
  145. begin
  146. if is_signed(left.resultdef) then
  147. opsize:=OS_S32
  148. else
  149. opsize:=OS_32;
  150. mask:=31;
  151. end
  152. else
  153. begin
  154. if is_signed(left.resultdef) then
  155. opsize:=OS_S64
  156. else
  157. opsize:=OS_64;
  158. mask:=63;
  159. end;
  160. { load left operators in a register }
  161. location_copy(location,left.location);
  162. hlcg.location_force_reg(current_asmdata.CurrAsmList,location,left.resultdef,hlcg.tcgsize2orddef(opsize),false);
  163. { shifting by a constant directly coded: }
  164. if (right.nodetype=ordconstn) then
  165. emit_const_reg(op,tcgsize2opsize[opsize],tordconstnode(right).value and mask,location.register)
  166. else
  167. begin
  168. { load right operators in a RCX }
  169. cg.getcpuregister(current_asmdata.CurrAsmList,NR_RCX);
  170. hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,right.resultdef,osuinttype,right.location,NR_RCX);
  171. { right operand is in ECX }
  172. cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_RCX);
  173. emit_reg_reg(op,tcgsize2opsize[opsize],NR_CL,location.register);
  174. end;
  175. end;
  176. begin
  177. cunaryminusnode:=tx8664unaryminusnode;
  178. cmoddivnode:=tx8664moddivnode;
  179. cshlshrnode:=tx8664shlshrnode;
  180. cnotnode:=tx8664notnode;
  181. end.