{ Copyright (c) 1998-2002 by Florian Klaempfl Generate x86 inline 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 nx86inl; {$i fpcdefs.inc} interface uses node,ninl,ncginl; type tx86inlinenode = class(tcginlinenode) { first pass override so that the code generator will actually generate these nodes. } function first_pi: tnode ; override; function first_arctan_real: tnode; override; function first_abs_real: tnode; override; function first_sqr_real: tnode; override; function first_sqrt_real: tnode; override; function first_ln_real: tnode; override; function first_cos_real: tnode; override; function first_sin_real: tnode; override; function first_round_real: tnode; override; function first_trunc_real: tnode; override; function first_popcnt: tnode; override; { second pass override to generate these nodes } procedure second_IncludeExclude;override; procedure second_pi; override; procedure second_arctan_real; override; procedure second_abs_real; override; procedure second_round_real; override; procedure second_sqr_real; override; procedure second_sqrt_real; override; procedure second_ln_real; override; procedure second_cos_real; override; procedure second_sin_real; override; procedure second_trunc_real; override; procedure second_prefetch;override; {$ifndef i8086} procedure second_abs_long;override; {$endif not i8086} procedure second_popcnt;override; private procedure load_fpu_location(lnode: tnode); end; implementation uses systems, globtype,globals, cutils,verbose, symconst, defutil, aasmbase,aasmtai,aasmdata,aasmcpu, symtype,symdef, cgbase,pass_2, cpuinfo,cpubase,paramgr, nbas,ncon,ncal,ncnv,nld,ncgutil, tgobj, cga,cgutils,cgx86,cgobj,hlcgobj; {***************************************************************************** TX86INLINENODE *****************************************************************************} function tx86inlinenode.first_pi : tnode; begin expectloc:=LOC_FPUREGISTER; first_pi := nil; end; function tx86inlinenode.first_arctan_real : tnode; begin expectloc:=LOC_FPUREGISTER; first_arctan_real := nil; end; function tx86inlinenode.first_abs_real : tnode; begin if use_vectorfpu(resultdef) then expectloc:=LOC_MMREGISTER else expectloc:=LOC_FPUREGISTER; first_abs_real := nil; end; function tx86inlinenode.first_sqr_real : tnode; begin expectloc:=LOC_FPUREGISTER; first_sqr_real := nil; end; function tx86inlinenode.first_sqrt_real : tnode; begin expectloc:=LOC_FPUREGISTER; first_sqrt_real := nil; end; function tx86inlinenode.first_ln_real : tnode; begin expectloc:=LOC_FPUREGISTER; first_ln_real := nil; end; function tx86inlinenode.first_cos_real : tnode; begin {$ifdef i8086} { FCOS is 387+ } if current_settings.cputype < cpu_386 then begin result := inherited; exit; end; {$endif i8086} expectloc:=LOC_FPUREGISTER; first_cos_real := nil; end; function tx86inlinenode.first_sin_real : tnode; begin {$ifdef i8086} { FSIN is 387+ } if current_settings.cputype < cpu_386 then begin result := inherited; exit; end; {$endif i8086} expectloc:=LOC_FPUREGISTER; first_sin_real := nil; end; function tx86inlinenode.first_round_real : tnode; begin {$ifdef x86_64} if use_vectorfpu(left.resultdef) then expectloc:=LOC_REGISTER else {$endif x86_64} expectloc:=LOC_REFERENCE; result:=nil; end; function tx86inlinenode.first_trunc_real: tnode; begin if (cs_opt_size in current_settings.optimizerswitches) {$ifdef x86_64} and not(use_vectorfpu(left.resultdef)) {$endif x86_64} then result:=inherited else begin {$ifdef x86_64} if use_vectorfpu(left.resultdef) then expectloc:=LOC_REGISTER else {$endif x86_64} expectloc:=LOC_REFERENCE; result:=nil; end; end; function tx86inlinenode.first_popcnt: tnode; begin Result:=nil; if (current_settings.fputype=fpu_sse3)) then begin secondpass(left); hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,false); location_reset(location,LOC_REGISTER,OS_S64); location.register:=cg.getintregister(current_asmdata.CurrAsmList,OS_S64); case left.location.size of OS_F32: current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CVTTSS2SI,S_Q,left.location.register,location.register)); OS_F64: current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CVTTSD2SI,S_Q,left.location.register,location.register)); else internalerror(2007031401); end; end else {$endif x86_64} begin if (current_settings.fputype>=fpu_sse3) then begin load_fpu_location(left); location_reset_ref(location,LOC_REFERENCE,OS_S64,0); tg.GetTemp(current_asmdata.CurrAsmList,resultdef.size,resultdef.alignment,tt_normal,location.reference); emit_ref(A_FISTTP,S_IQ,location.reference); tcgx86(cg).dec_fpu_stack; end else begin tg.GetTemp(current_asmdata.CurrAsmList,2,2,tt_normal,oldcw); tg.GetTemp(current_asmdata.CurrAsmList,2,2,tt_normal,newcw); emit_ref(A_FNSTCW,S_NO,newcw); emit_ref(A_FNSTCW,S_NO,oldcw); emit_const_ref(A_OR,S_W,$0f00,newcw); load_fpu_location(left); emit_ref(A_FLDCW,S_NO,newcw); location_reset_ref(location,LOC_REFERENCE,OS_S64,0); tg.GetTemp(current_asmdata.CurrAsmList,resultdef.size,resultdef.alignment,tt_normal,location.reference); emit_ref(A_FISTP,S_IQ,location.reference); tcgx86(cg).dec_fpu_stack; emit_ref(A_FLDCW,S_NO,oldcw); emit_none(A_FWAIT,S_NO); tg.UnGetTemp(current_asmdata.CurrAsmList,oldcw); tg.UnGetTemp(current_asmdata.CurrAsmList,newcw); end; end; end; procedure tx86inlinenode.second_sqr_real; begin if use_vectorfpu(resultdef) then begin secondpass(left); hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,false); location:=left.location; cg.a_opmm_loc_reg(current_asmdata.CurrAsmList,OP_MUL,left.location.size,left.location,left.location.register,mms_movescalar); end else begin load_fpu_location(left); emit_reg_reg(A_FMUL,S_NO,NR_ST0,NR_ST0); end; end; procedure tx86inlinenode.second_sqrt_real; begin if use_vectorfpu(resultdef) then begin secondpass(left); hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,false); location:=left.location; case tfloatdef(resultdef).floattype of s32real: current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_SQRTSS,S_XMM,location.register,location.register)); s64real: current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_SQRTSD,S_XMM,location.register,location.register)); else internalerror(200510031); end; end else begin load_fpu_location(left); emit_none(A_FSQRT,S_NO); end; end; procedure tx86inlinenode.second_ln_real; begin load_fpu_location(left); emit_none(A_FLDLN2,S_NO); emit_none(A_FXCH,S_NO); emit_none(A_FYL2X,S_NO); end; procedure tx86inlinenode.second_cos_real; begin {$ifdef i8086} { FCOS is 387+ } if current_settings.cputype < cpu_386 then begin inherited; exit; end; {$endif i8086} load_fpu_location(left); emit_none(A_FCOS,S_NO); end; procedure tx86inlinenode.second_sin_real; begin {$ifdef i8086} { FSIN is 387+ } if current_settings.cputype < cpu_386 then begin inherited; exit; end; {$endif i8086} load_fpu_location(left); emit_none(A_FSIN,S_NO) end; procedure tx86inlinenode.second_prefetch; var ref : treference; r : tregister; begin {$if defined(i386) or defined(i8086)} if current_settings.cputype>=cpu_Pentium3 then {$endif i386 or i8086} begin secondpass(left); case left.location.loc of LOC_CREFERENCE, LOC_REFERENCE: begin r:=cg.getintregister(current_asmdata.CurrAsmList,OS_ADDR); cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.location.reference,r); reference_reset_base(ref,r,0,left.location.reference.alignment); current_asmdata.CurrAsmList.concat(taicpu.op_ref(A_PREFETCHNTA,S_NO,ref)); end; else internalerror(200402021); end; end; end; {$ifndef i8086} procedure tx86inlinenode.second_abs_long; var hregister : tregister; opsize : tcgsize; hp : taicpu; begin {$ifdef i386} if current_settings.cputypeopsize) then hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,cgsize_orddef(opsize),true); location_reset(location,LOC_REGISTER,opsize); location.register:=cg.getintregister(current_asmdata.CurrAsmList,opsize); if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_POPCNT,TCGSize2OpSize[opsize],left.location.register,location.register)) else current_asmdata.CurrAsmList.concat(taicpu.op_ref_reg(A_POPCNT,TCGSize2OpSize[opsize],left.location.reference,location.register)); end; end.