diff options
Diffstat (limited to 'compiler/x86/nx86add.pas')
-rw-r--r-- | compiler/x86/nx86add.pas | 1065 |
1 files changed, 1065 insertions, 0 deletions
diff --git a/compiler/x86/nx86add.pas b/compiler/x86/nx86add.pas new file mode 100644 index 0000000000..b678fe7c75 --- /dev/null +++ b/compiler/x86/nx86add.pas @@ -0,0 +1,1065 @@ +{ + Copyright (c) 2000-2002 by Florian Klaempfl + + Common code generation for add nodes on the i386 and x86 + + 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 nx86add; + +{$i fpcdefs.inc} + + interface + + uses + cgbase, + cpubase, + node,nadd,ncgadd; + + type + tx86addnode = class(tcgaddnode) + protected + function getresflags(unsigned : boolean) : tresflags; + procedure left_must_be_reg(opsize:TCGSize;noswap:boolean); + procedure left_and_right_must_be_fpureg; + procedure emit_op_right_left(op:TAsmOp;opsize:TCgSize); + procedure emit_generic_code(op:TAsmOp;opsize:TCgSize;unsigned,extra_not,mboverflow:boolean); + + procedure second_cmpfloatsse; + procedure second_addfloatsse; + procedure second_mul;virtual;abstract; + public + procedure second_addfloat;override; + procedure second_addsmallset;override; + procedure second_add64bit;override; + procedure second_addordinal;override; + procedure second_cmpfloat;override; + procedure second_cmpsmallset;override; + procedure second_cmp64bit;override; + procedure second_cmpordinal;override; +{$ifdef SUPPORT_MMX} + procedure second_opmmxset;override; + procedure second_opmmx;override; +{$endif SUPPORT_MMX} + end; + + + implementation + + uses + globtype,globals, + verbose,cutils, + cpuinfo, + aasmbase,aasmtai,aasmcpu, + symconst,symdef, + cgobj,cgx86,cga,cgutils, + paramgr,tgobj,ncgutil, + ncon,nset, + defutil; + + +{***************************************************************************** + Helpers +*****************************************************************************} + + procedure tx86addnode.emit_generic_code(op:TAsmOp;opsize:TCGSize;unsigned,extra_not,mboverflow:boolean); + var + power : longint; + hl4 : tasmlabel; + r : Tregister; + begin + { at this point, left.location.loc should be LOC_REGISTER } + if right.location.loc=LOC_REGISTER then + begin + { right.location is a LOC_REGISTER } + { when swapped another result register } + if (nodetype=subn) and (nf_swaped in flags) then + begin + if extra_not then + emit_reg(A_NOT,TCGSize2Opsize[opsize],left.location.register); + emit_reg_reg(op,TCGSize2Opsize[opsize],left.location.register,right.location.register); + { newly swapped also set swapped flag } + location_swap(left.location,right.location); + toggleflag(nf_swaped); + end + else + begin + if extra_not then + emit_reg(A_NOT,TCGSize2Opsize[opsize],right.location.register); + if (op=A_ADD) or (op=A_OR) or (op=A_AND) or (op=A_XOR) or (op=A_IMUL) then + location_swap(left.location,right.location); + emit_reg_reg(op,TCGSize2Opsize[opsize],right.location.register,left.location.register); + end; + end + else + begin + { right.location is not a LOC_REGISTER } + if (nodetype=subn) and (nf_swaped in flags) then + begin + if extra_not then + cg.a_op_reg_reg(exprasmlist,OP_NOT,opsize,left.location.register,left.location.register); + r:=cg.getintregister(exprasmlist,opsize); + cg.a_load_loc_reg(exprasmlist,opsize,right.location,r); + emit_reg_reg(op,TCGSize2Opsize[opsize],left.location.register,r); + cg.a_load_reg_reg(exprasmlist,opsize,opsize,r,left.location.register); + end + else + begin + { Optimizations when right.location is a constant value } + if (op=A_CMP) and + (nodetype in [equaln,unequaln]) and + (right.location.loc=LOC_CONSTANT) and + (right.location.value=0) then + begin + emit_reg_reg(A_TEST,TCGSize2Opsize[opsize],left.location.register,left.location.register); + end + else + if (op=A_ADD) and + (right.location.loc=LOC_CONSTANT) and + (right.location.value=1) and + not(cs_check_overflow in aktlocalswitches) then + begin + emit_reg(A_INC,TCGSize2Opsize[opsize],left.location.register); + end + else + if (op=A_SUB) and + (right.location.loc=LOC_CONSTANT) and + (right.location.value=1) and + not(cs_check_overflow in aktlocalswitches) then + begin + emit_reg(A_DEC,TCGSize2Opsize[opsize],left.location.register); + end + else + if (op=A_IMUL) and + (right.location.loc=LOC_CONSTANT) and + (ispowerof2(int64(right.location.value),power)) and + not(cs_check_overflow in aktlocalswitches) then + begin + emit_const_reg(A_SHL,TCGSize2Opsize[opsize],power,left.location.register); + end + else + begin + if extra_not then + begin + r:=cg.getintregister(exprasmlist,opsize); + cg.a_load_loc_reg(exprasmlist,opsize,right.location,r); + emit_reg(A_NOT,TCGSize2Opsize[opsize],r); + emit_reg_reg(A_AND,TCGSize2Opsize[opsize],r,left.location.register); + end + else + begin + emit_op_right_left(op,opsize); + end; + end; + end; + end; + + { only in case of overflow operations } + { produce overflow code } + { we must put it here directly, because sign of operation } + { is in unsigned VAR!! } + if mboverflow then + begin + if cs_check_overflow in aktlocalswitches then + begin + objectlibrary.getjumplabel(hl4); + if unsigned then + cg.a_jmp_flags(exprasmlist,F_AE,hl4) + else + cg.a_jmp_flags(exprasmlist,F_NO,hl4); + cg.a_call_name(exprasmlist,'FPC_OVERFLOW'); + cg.a_label(exprasmlist,hl4); + end; + end; + end; + + + procedure tx86addnode.left_must_be_reg(opsize:TCGSize;noswap:boolean); + begin + { left location is not a register? } + if (left.location.loc<>LOC_REGISTER) then + begin + { if right is register then we can swap the locations } + if (not noswap) and + (right.location.loc=LOC_REGISTER) then + begin + location_swap(left.location,right.location); + toggleflag(nf_swaped); + end + else + begin + { maybe we can reuse a constant register when the + operation is a comparison that doesn't change the + value of the register } + location_force_reg(exprasmlist,left.location,opsize,(nodetype in [ltn,lten,gtn,gten,equaln,unequaln])); + end; + end; + end; + + + procedure tx86addnode.left_and_right_must_be_fpureg; + begin + if (right.location.loc<>LOC_FPUREGISTER) then + begin + cg.a_loadfpu_loc_reg(exprasmlist,right.location,NR_ST); + if (right.location.loc <> LOC_CFPUREGISTER) then + location_freetemp(exprasmlist,left.location); + if (left.location.loc<>LOC_FPUREGISTER) then + begin + cg.a_loadfpu_loc_reg(exprasmlist,left.location,NR_ST); + if (left.location.loc <> LOC_CFPUREGISTER) then + location_freetemp(exprasmlist,left.location); + end + else + begin + { left was on the stack => swap } + toggleflag(nf_swaped); + end; + end + { the nominator in st0 } + else if (left.location.loc<>LOC_FPUREGISTER) then + begin + cg.a_loadfpu_loc_reg(exprasmlist,left.location,NR_ST); + if (left.location.loc <> LOC_CFPUREGISTER) then + location_freetemp(exprasmlist,left.location); + end + else + begin + { fpu operands are always in the wrong order on the stack } + toggleflag(nf_swaped); + end; + end; + + + procedure tx86addnode.emit_op_right_left(op:TAsmOp;opsize:TCgsize); +{$ifdef x86_64} + var + tmpreg : tregister; +{$endif x86_64} + begin + { left must be a register } + case right.location.loc of + LOC_REGISTER, + LOC_CREGISTER : + exprasmlist.concat(taicpu.op_reg_reg(op,TCGSize2Opsize[opsize],right.location.register,left.location.register)); + LOC_REFERENCE, + LOC_CREFERENCE : + begin + tcgx86(cg).make_simple_ref(exprasmlist,right.location.reference); + exprasmlist.concat(taicpu.op_ref_reg(op,TCGSize2Opsize[opsize],right.location.reference,left.location.register)); + end; + LOC_CONSTANT : + begin +{$ifdef x86_64} + { x86_64 only supports signed 32 bits constants directly } + if (opsize in [OS_S64,OS_64]) and + ((right.location.value<low(longint)) or (right.location.value>high(longint))) then + begin + tmpreg:=cg.getintregister(exprasmlist,opsize); + cg.a_load_const_reg(exprasmlist,opsize,right.location.value,tmpreg); + exprasmlist.concat(taicpu.op_reg_reg(op,TCGSize2Opsize[opsize],tmpreg,left.location.register)); + end + else +{$endif x86_64} + exprasmlist.concat(taicpu.op_const_reg(op,TCGSize2Opsize[opsize],right.location.value,left.location.register)); + end; + else + internalerror(200203232); + end; + end; + + + function tx86addnode.getresflags(unsigned : boolean) : tresflags; + begin + case nodetype of + equaln : getresflags:=F_E; + unequaln : getresflags:=F_NE; + else + if not(unsigned) then + begin + if nf_swaped in flags then + case nodetype of + ltn : getresflags:=F_G; + lten : getresflags:=F_GE; + gtn : getresflags:=F_L; + gten : getresflags:=F_LE; + end + else + case nodetype of + ltn : getresflags:=F_L; + lten : getresflags:=F_LE; + gtn : getresflags:=F_G; + gten : getresflags:=F_GE; + end; + end + else + begin + if nf_swaped in flags then + case nodetype of + ltn : getresflags:=F_A; + lten : getresflags:=F_AE; + gtn : getresflags:=F_B; + gten : getresflags:=F_BE; + end + else + case nodetype of + ltn : getresflags:=F_B; + lten : getresflags:=F_BE; + gtn : getresflags:=F_A; + gten : getresflags:=F_AE; + end; + end; + end; + end; + + +{***************************************************************************** + AddSmallSet +*****************************************************************************} + + procedure tx86addnode.second_addsmallset; + var + opsize : TCGSize; + op : TAsmOp; + extra_not, + noswap : boolean; + begin + pass_left_right; + + noswap:=false; + extra_not:=false; + opsize:=OS_32; + case nodetype of + addn : + begin + { this is a really ugly hack!!!!!!!!!! } + { this could be done later using EDI } + { as it is done for subn } + { instead of two registers!!!! } + { adding elements is not commutative } + if (nf_swaped in flags) and (left.nodetype=setelementn) then + swapleftright; + { are we adding set elements ? } + if right.nodetype=setelementn then + begin + { no range support for smallsets! } + if assigned(tsetelementnode(right).right) then + internalerror(43244); + { bts requires both elements to be registers } + location_force_reg(exprasmlist,left.location,opsize,false); + location_force_reg(exprasmlist,right.location,opsize,true); + op:=A_BTS; + noswap:=true; + end + else + op:=A_OR; + end; + symdifn : + op:=A_XOR; + muln : + op:=A_AND; + subn : + begin + op:=A_AND; + if (not(nf_swaped in flags)) and + (right.location.loc=LOC_CONSTANT) then + right.location.value := not(right.location.value) + else if (nf_swaped in flags) and + (left.location.loc=LOC_CONSTANT) then + left.location.value := not(left.location.value) + else + extra_not:=true; + end; + xorn : + op:=A_XOR; + orn : + op:=A_OR; + andn : + op:=A_AND; + else + internalerror(2003042215); + end; + { left must be a register } + left_must_be_reg(opsize,noswap); + emit_generic_code(op,opsize,true,extra_not,false); + location_freetemp(exprasmlist,right.location); + + set_result_location_reg; + end; + + + procedure tx86addnode.second_cmpsmallset; + var + opsize : TCGSize; + op : TAsmOp; + begin + pass_left_right; + opsize:=OS_32; + case nodetype of + equaln, + unequaln : + op:=A_CMP; + lten,gten: + begin + if (not(nf_swaped in flags) and (nodetype = lten)) or + ((nf_swaped in flags) and (nodetype = gten)) then + swapleftright; + location_force_reg(exprasmlist,left.location,opsize,true); + emit_op_right_left(A_AND,opsize); + op:=A_CMP; + { warning: ugly hack, we need a JE so change the node to equaln } + nodetype:=equaln; + end; + else + internalerror(2003042215); + end; + { left must be a register } + left_must_be_reg(opsize,false); + emit_generic_code(op,opsize,true,false,false); + location_freetemp(exprasmlist,right.location); + location_freetemp(exprasmlist,left.location); + + location_reset(location,LOC_FLAGS,OS_NO); + location.resflags:=getresflags(true); + end; + + +{***************************************************************************** + AddMMX +*****************************************************************************} + +{$ifdef SUPPORT_MMX} + procedure tx86addnode.second_opmmx; + var + op : TAsmOp; + cmpop : boolean; + mmxbase : tmmxtype; + hreg, + hregister : tregister; + begin + pass_left_right; + + cmpop:=false; + mmxbase:=mmx_type(left.resulttype.def); + location_reset(location,LOC_MMXREGISTER,def_cgsize(resulttype.def)); + case nodetype of + addn : + begin + if (cs_mmx_saturation in aktlocalswitches) then + begin + case mmxbase of + mmxs8bit: + op:=A_PADDSB; + mmxu8bit: + op:=A_PADDUSB; + mmxs16bit,mmxfixed16: + op:=A_PADDSB; + mmxu16bit: + op:=A_PADDUSW; + end; + end + else + begin + case mmxbase of + mmxs8bit,mmxu8bit: + op:=A_PADDB; + mmxs16bit,mmxu16bit,mmxfixed16: + op:=A_PADDW; + mmxs32bit,mmxu32bit: + op:=A_PADDD; + end; + end; + end; + muln : + begin + case mmxbase of + mmxs16bit,mmxu16bit: + op:=A_PMULLW; + mmxfixed16: + op:=A_PMULHW; + end; + end; + subn : + begin + if (cs_mmx_saturation in aktlocalswitches) then + begin + case mmxbase of + mmxs8bit: + op:=A_PSUBSB; + mmxu8bit: + op:=A_PSUBUSB; + mmxs16bit,mmxfixed16: + op:=A_PSUBSB; + mmxu16bit: + op:=A_PSUBUSW; + end; + end + else + begin + case mmxbase of + mmxs8bit,mmxu8bit: + op:=A_PSUBB; + mmxs16bit,mmxu16bit,mmxfixed16: + op:=A_PSUBW; + mmxs32bit,mmxu32bit: + op:=A_PSUBD; + end; + end; + end; + xorn: + op:=A_PXOR; + orn: + op:=A_POR; + andn: + op:=A_PAND; + else + internalerror(2003042214); + end; + + { left and right no register? } + { then one must be demanded } + if (left.location.loc<>LOC_MMXREGISTER) then + begin + if (right.location.loc=LOC_MMXREGISTER) then + begin + location_swap(left.location,right.location); + toggleflag(nf_swaped); + end + else + begin + { register variable ? } + if (left.location.loc=LOC_CMMXREGISTER) then + begin + hregister:=tcgx86(cg).getmmxregister(exprasmlist); + emit_reg_reg(A_MOVQ,S_NO,left.location.register,hregister); + end + else + begin + if not(left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then + internalerror(200203245); + + hregister:=tcgx86(cg).getmmxregister(exprasmlist); + emit_ref_reg(A_MOVQ,S_NO,left.location.reference,hregister); + end; + + location_reset(left.location,LOC_MMXREGISTER,OS_NO); + left.location.register:=hregister; + end; + end; + + { at this point, left.location.loc should be LOC_MMXREGISTER } + if right.location.loc<>LOC_MMXREGISTER then + begin + if (nodetype=subn) and (nf_swaped in flags) then + begin + hreg:=tcgx86(cg).getmmxregister(exprasmlist); + if right.location.loc=LOC_CMMXREGISTER then + begin + emit_reg_reg(A_MOVQ,S_NO,right.location.register,hreg); + emit_reg_reg(op,S_NO,left.location.register,hreg); + end + else + begin + if not(left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then + internalerror(200203247); + emit_ref_reg(A_MOVQ,S_NO,right.location.reference,hreg); + emit_reg_reg(op,S_NO,left.location.register,hreg); + end; + location.register:=hreg; + end + else + begin + if (right.location.loc=LOC_CMMXREGISTER) then + emit_reg_reg(op,S_NO,right.location.register,left.location.register) + else + begin + if not(right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then + internalerror(200203246); + emit_ref_reg(op,S_NO,right.location.reference,left.location.register); + end; + location.register:=left.location.register; + end; + end + else + begin + { right.location=LOC_MMXREGISTER } + if (nodetype=subn) and (nf_swaped in flags) then + begin + emit_reg_reg(op,S_NO,left.location.register,right.location.register); + location_swap(left.location,right.location); + toggleflag(nf_swaped); + end + else + begin + emit_reg_reg(op,S_NO,right.location.register,left.location.register); + end; + location.register:=left.location.register; + end; + + location_freetemp(exprasmlist,right.location); + if cmpop then + location_freetemp(exprasmlist,left.location); + end; +{$endif SUPPORT_MMX} + + +{***************************************************************************** + addmmxset +*****************************************************************************} + +{$ifdef SUPPORT_MMX} + procedure tx86addnode.second_opmmxset; + + var opsize : TCGSize; + op : TAsmOp; + cmpop, + noswap : boolean; + begin + pass_left_right; + + cmpop:=false; + noswap:=false; + opsize:=OS_32; + case nodetype of + addn: + begin + { are we adding set elements ? } + if right.nodetype=setelementn then + begin + { adding elements is not commutative } +{ if nf_swaped in flags then + swapleftright;} + { bts requires both elements to be registers } +{ location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],false); + location_force_reg(exprasmlist,right.location,opsize_2_cgsize[opsize],true); + op:=A_BTS; + noswap:=true;} + end + else + op:=A_POR; + end; + symdifn : + op:=A_PXOR; + muln: + op:=A_PAND; + subn: + op:=A_PANDN; + equaln, + unequaln : + begin + op:=A_PCMPEQD; + cmpop:=true; + end; + lten,gten: + begin + if (not(nf_swaped in flags) and (nodetype = lten)) or + ((nf_swaped in flags) and (nodetype = gten)) then + swapleftright; + location_force_reg(exprasmlist,left.location,opsize,true); + emit_op_right_left(A_AND,opsize); + op:=A_PCMPEQD; + cmpop:=true; + { warning: ugly hack, we need a JE so change the node to equaln } + nodetype:=equaln; + end; + xorn : + op:=A_PXOR; + orn : + op:=A_POR; + andn : + op:=A_PAND; + else + internalerror(2003042215); + end; + { left must be a register } + left_must_be_reg(opsize,noswap); +{ emit_generic_code(op,opsize,true,extra_not,false);} + location_freetemp(exprasmlist,right.location); + if cmpop then + location_freetemp(exprasmlist,left.location); + end; +{$endif SUPPORT_MMX} + + + +{***************************************************************************** + AddFloat +*****************************************************************************} + + procedure tx86addnode.second_addfloatsse; + var + op : topcg; + begin + pass_left_right; + if (nf_swaped in flags) then + swapleftright; + + case nodetype of + addn : + op:=OP_ADD; + muln : + op:=OP_MUL; + subn : + op:=OP_SUB; + slashn : + op:=OP_DIV; + else + internalerror(200312231); + end; + + location_reset(location,LOC_MMREGISTER,def_cgsize(resulttype.def)); + { we can use only right as left operand if the operation is commutative } + if (right.location.loc=LOC_MMREGISTER) and (op in [OP_ADD,OP_MUL]) then + begin + location.register:=right.location.register; + { force floating point reg. location to be written to memory, + we don't force it to mm register because writing to memory + allows probably shorter code because there is no direct fpu->mm register + copy instruction + } + if left.location.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER] then + location_force_mem(exprasmlist,left.location); + cg.a_opmm_loc_reg(exprasmlist,op,location.size,left.location,location.register,mms_movescalar); + end + else + begin + location_force_mmregscalar(exprasmlist,left.location,false); + location.register:=left.location.register; + { force floating point reg. location to be written to memory, + we don't force it to mm register because writing to memory + allows probably shorter code because there is no direct fpu->mm register + copy instruction + } + if right.location.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER] then + location_force_mem(exprasmlist,right.location); + cg.a_opmm_loc_reg(exprasmlist,op,location.size,right.location,location.register,mms_movescalar); + end; + end; + + + procedure tx86addnode.second_cmpfloatsse; + var + op : tasmop; + begin + if is_single(left.resulttype.def) then + op:=A_COMISS + else if is_double(left.resulttype.def) then + op:=A_COMISD + else + internalerror(200402222); + pass_left_right; + + location_reset(location,LOC_FLAGS,def_cgsize(resulttype.def)); + { we can use only right as left operand if the operation is commutative } + if (right.location.loc=LOC_MMREGISTER) then + begin + { force floating point reg. location to be written to memory, + we don't force it to mm register because writing to memory + allows probably shorter code because there is no direct fpu->mm register + copy instruction + } + if left.location.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER] then + location_force_mem(exprasmlist,left.location); + case left.location.loc of + LOC_REFERENCE,LOC_CREFERENCE: + begin + tcgx86(cg).make_simple_ref(exprasmlist,left.location.reference); + exprasmlist.concat(taicpu.op_ref_reg(op,S_NO,left.location.reference,right.location.register)); + end; + LOC_MMREGISTER,LOC_CMMREGISTER: + exprasmlist.concat(taicpu.op_reg_reg(op,S_NO,left.location.register,right.location.register)); + else + internalerror(200402221); + end; + if nf_swaped in flags then + exclude(flags,nf_swaped) + else + include(flags,nf_swaped) + end + else + begin + location_force_mmregscalar(exprasmlist,left.location,false); + { force floating point reg. location to be written to memory, + we don't force it to mm register because writing to memory + allows probably shorter code because there is no direct fpu->mm register + copy instruction + } + if right.location.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER] then + location_force_mem(exprasmlist,right.location); + case right.location.loc of + LOC_REFERENCE,LOC_CREFERENCE: + begin + tcgx86(cg).make_simple_ref(exprasmlist,right.location.reference); + exprasmlist.concat(taicpu.op_ref_reg(op,S_NO,right.location.reference,left.location.register)); + end; + LOC_MMREGISTER,LOC_CMMREGISTER: + exprasmlist.concat(taicpu.op_reg_reg(op,S_NO,right.location.register,left.location.register)); + else + internalerror(200402223); + end; + end; + location.resflags:=getresflags(true); + end; + + + procedure tx86addnode.second_addfloat; + var + op : TAsmOp; + begin + if use_sse(resulttype.def) then + begin + second_addfloatsse; + exit; + end; + + pass_left_right; + + case nodetype of + addn : + op:=A_FADDP; + muln : + op:=A_FMULP; + subn : + op:=A_FSUBP; + slashn : + op:=A_FDIVP; + else + internalerror(2003042214); + end; + + left_and_right_must_be_fpureg; + + { if we swaped the tree nodes, then use the reverse operator } + if nf_swaped in flags then + begin + if (nodetype=slashn) then + op:=A_FDIVRP + else if (nodetype=subn) then + op:=A_FSUBRP; + end; + + emit_reg_reg(op,S_NO,NR_ST,NR_ST1); + tcgx86(cg).dec_fpu_stack; + + location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def)); + location.register:=NR_ST; + end; + + + procedure tx86addnode.second_cmpfloat; + var + resflags : tresflags; + begin + if use_sse(left.resulttype.def) or use_sse(right.resulttype.def) then + begin + second_cmpfloatsse; + exit; + end; + + pass_left_right; + left_and_right_must_be_fpureg; + +{$ifndef x86_64} + if aktspecificoptprocessor<ClassPentium2 then + begin + emit_none(A_FCOMPP,S_NO); + tcgx86(cg).dec_fpu_stack; + tcgx86(cg).dec_fpu_stack; + + { load fpu flags } + cg.getcpuregister(exprasmlist,NR_AX); + emit_reg(A_FNSTSW,S_NO,NR_AX); + emit_none(A_SAHF,S_NO); + cg.ungetcpuregister(exprasmlist,NR_AX); + if nf_swaped in flags then + begin + case nodetype of + equaln : resflags:=F_E; + unequaln : resflags:=F_NE; + ltn : resflags:=F_A; + lten : resflags:=F_AE; + gtn : resflags:=F_B; + gten : resflags:=F_BE; + end; + end + else + begin + case nodetype of + equaln : resflags:=F_E; + unequaln : resflags:=F_NE; + ltn : resflags:=F_B; + lten : resflags:=F_BE; + gtn : resflags:=F_A; + gten : resflags:=F_AE; + end; + end; + end + else +{$endif x86_64} + begin + exprasmlist.concat(taicpu.op_reg_reg(A_FCOMIP,S_NO,NR_ST1,NR_ST0)); + { fcomip pops only one fpu register } + exprasmlist.concat(taicpu.op_reg(A_FSTP,S_NO,NR_ST0)); + tcgx86(cg).dec_fpu_stack; + tcgx86(cg).dec_fpu_stack; + + { load fpu flags } + if nf_swaped in flags then + begin + case nodetype of + equaln : resflags:=F_E; + unequaln : resflags:=F_NE; + ltn : resflags:=F_A; + lten : resflags:=F_AE; + gtn : resflags:=F_B; + gten : resflags:=F_BE; + end; + end + else + begin + case nodetype of + equaln : resflags:=F_E; + unequaln : resflags:=F_NE; + ltn : resflags:=F_B; + lten : resflags:=F_BE; + gtn : resflags:=F_A; + gten : resflags:=F_AE; + end; + end; + end; + + location_reset(location,LOC_FLAGS,OS_NO); + location.resflags:=resflags; + end; + + +{***************************************************************************** + Add64bit +*****************************************************************************} + + procedure tx86addnode.second_add64bit; + begin +{$ifdef cpu64bit} + second_addordinal; +{$else cpu64bit} + { must be implemented separate } + internalerror(200402042); +{$endif cpu64bit} + end; + + + procedure tx86addnode.second_cmp64bit; + begin +{$ifdef cpu64bit} + second_cmpordinal; +{$else cpu64bit} + { must be implemented separate } + internalerror(200402043); +{$endif cpu64bit} + end; + + +{***************************************************************************** + AddOrdinal +*****************************************************************************} + + procedure tx86addnode.second_addordinal; + var + mboverflow : boolean; + op : tasmop; + opsize : tcgsize; + { true, if unsigned types are compared } + unsigned : boolean; + { true, if for sets subtractions the extra not should generated } + extra_not : boolean; + begin + { defaults } + extra_not:=false; + mboverflow:=false; + unsigned:=not(is_signed(left.resulttype.def)) or + not(is_signed(right.resulttype.def)); + opsize:=def_cgsize(left.resulttype.def); + + pass_left_right; + + case nodetype of + addn : + begin + op:=A_ADD; + mboverflow:=true; + end; + muln : + begin + if unsigned then + op:=A_MUL + else + op:=A_IMUL; + mboverflow:=true; + end; + subn : + begin + op:=A_SUB; + mboverflow:=true; + end; + xorn : + op:=A_XOR; + orn : + op:=A_OR; + andn : + op:=A_AND; + else + internalerror(200304229); + end; + + { filter MUL, which requires special handling } + if op=A_MUL then + begin + second_mul; + exit; + end; + + left_must_be_reg(opsize,false); + emit_generic_code(op,opsize,unsigned,extra_not,mboverflow); + location_freetemp(exprasmlist,right.location); + + set_result_location_reg; + end; + + + procedure tx86addnode.second_cmpordinal; + var + opsize : tcgsize; + unsigned : boolean; + begin + unsigned:=not(is_signed(left.resulttype.def)) or + not(is_signed(right.resulttype.def)); + opsize:=def_cgsize(left.resulttype.def); + + pass_left_right; + + left_must_be_reg(opsize,false); + emit_generic_code(A_CMP,opsize,unsigned,false,false); + location_freetemp(exprasmlist,right.location); + location_freetemp(exprasmlist,left.location); + + location_reset(location,LOC_FLAGS,OS_NO); + location.resflags:=getresflags(unsigned); + end; + +begin + caddnode:=tx86addnode; +end. |