{ Copyright (c) 1998-2002 by Florian Klaempfl Generate x86-64 assembler for math nodes This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. **************************************************************************** } unit nx64mat; {$i fpcdefs.inc} interface uses node,nmat,ncgmat,nx86mat; type tx8664moddivnode = class(tmoddivnode) procedure pass_2;override; end; tx8664shlshrnode = class(tshlshrnode) procedure pass_2;override; end; tx8664unaryminusnode = class(tx86unaryminusnode) end; tx8664notnode = class(tx86notnode) end; implementation uses globtype,systems, cutils,verbose,globals, symconst,symdef,aasmbase,aasmtai,defutil, pass_1,pass_2, ncon, cpubase,cpuinfo, cgbase,cgutils,cga,cgobj,cgx86, ncgutil; {***************************************************************************** TX8664MODDIVNODE *****************************************************************************} procedure tx8664moddivnode.pass_2; var hreg1,hreg2:Tregister; power:longint; op:Tasmop; begin secondpass(left); if codegenerror then exit; secondpass(right); if codegenerror then exit; { put numerator in register } location_reset(location,LOC_REGISTER,OS_INT); location_force_reg(exprasmlist,left.location,OS_INT,false); hreg1:=left.location.register; if (nodetype=divn) and (right.nodetype=ordconstn) and ispowerof2(int64(tordconstnode(right).value),power) then begin { for signed numbers, the numerator must be adjusted before the shift instruction, but not wih unsigned numbers! Otherwise, "Cardinal($ffffffff) div 16" overflows! (JM) } if is_signed(left.resulttype.def) Then begin { use a sequence without jumps, saw this in comp.compilers (JM) } { no jumps, but more operations } hreg2:=cg.getintregister(exprasmlist,OS_INT); emit_reg_reg(A_MOV,S_Q,hreg1,hreg2); {If the left value is signed, hreg2=$ffffffff, otherwise 0.} emit_const_reg(A_SAR,S_Q,63,hreg2); {If signed, hreg2=right value-1, otherwise 0.} emit_const_reg(A_AND,S_Q,tordconstnode(right).value-1,hreg2); { add to the left value } emit_reg_reg(A_ADD,S_Q,hreg2,hreg1); { do the shift } emit_const_reg(A_SAR,S_Q,power,hreg1); end else emit_const_reg(A_SHR,S_Q,power,hreg1); location.register:=hreg1; end else begin {Bring denominator to a register.} cg.getcpuregister(exprasmlist,NR_RAX); emit_reg_reg(A_MOV,S_Q,hreg1,NR_RAX); cg.getcpuregister(exprasmlist,NR_RDX); {Sign extension depends on the left type.} if torddef(left.resulttype.def).typ=u64bit then emit_reg_reg(A_XOR,S_Q,NR_RDX,NR_RDX) else emit_none(A_CQO,S_NO); {Division depends on the right type.} if Torddef(right.resulttype.def).typ=u64bit then op:=A_DIV else op:=A_IDIV; if right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then emit_ref(op,S_Q,right.location.reference) else if right.location.loc in [LOC_REGISTER,LOC_CREGISTER] then emit_reg(op,S_Q,right.location.register) else begin hreg1:=cg.getintregister(exprasmlist,right.location.size); cg.a_load_loc_reg(exprasmlist,OS_64,right.location,hreg1); emit_reg(op,S_Q,hreg1); end; { Copy the result into a new register. Release RAX & RDX.} cg.ungetcpuregister(exprasmlist,NR_RDX); cg.ungetcpuregister(exprasmlist,NR_RAX); location.register:=cg.getintregister(exprasmlist,OS_INT); if nodetype=divn then cg.a_load_reg_reg(exprasmlist,OS_INT,OS_INT,NR_RAX,location.register) else cg.a_load_reg_reg(exprasmlist,OS_INT,OS_INT,NR_RDX,location.register); end; end; {***************************************************************************** TX8664SHLRSHRNODE *****************************************************************************} procedure tx8664shlshrnode.pass_2; var op : Tasmop; opsize : tcgsize; mask : aint; begin secondpass(left); secondpass(right); { determine operator } if nodetype=shln then op:=A_SHL else op:=A_SHR; { special treatment of 32bit values for backwards compatibility } if left.resulttype.def.size<=4 then begin opsize:=OS_32; mask:=31; end else begin opsize:=OS_64; mask:=63; end; { load left operators in a register } location_copy(location,left.location); location_force_reg(exprasmlist,location,opsize,false); { shifting by a constant directly coded: } if (right.nodetype=ordconstn) then emit_const_reg(op,tcgsize2opsize[opsize],tordconstnode(right).value and mask,location.register) else begin { load right operators in a RCX } cg.getcpuregister(exprasmlist,NR_RCX); cg.a_load_loc_reg(exprasmlist,OS_INT,right.location,NR_RCX); { right operand is in ECX } cg.ungetcpuregister(exprasmlist,NR_RCX); emit_reg_reg(op,tcgsize2opsize[opsize],NR_CL,location.register); end; end; begin cunaryminusnode:=tx8664unaryminusnode; cmoddivnode:=tx8664moddivnode; cshlshrnode:=tx8664shlshrnode; cnotnode:=tx8664notnode; end.