fpc/compiler/jvm/njvmadd.pas
Jonas Maebe 71b348757b * reversed expected operand order of tjvmhlcg.a_cmp_*(), because
that's how these operations also work on other architectures
  * fixed tjvmaddnode.second_generic_compare() for this new order

git-svn-id: branches/jvmbackend@18338 -
2011-08-20 07:48:27 +00:00

256 lines
8.4 KiB
ObjectPascal

{
Copyright (c) 2000-2011 by Florian Klaempfl and Jonas Maebe
Code generation for add nodes on the JVM
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 njvmadd;
{$i fpcdefs.inc}
interface
uses
cgbase,
node,ncgadd,cpubase;
type
{ njvmadd }
tjvmaddnode = class(tcgaddnode)
protected
function pass_1: tnode;override;
function cmpnode2signedtopcmp: TOpCmp;
procedure second_generic_compare;
procedure second_addfloat;override;
procedure second_cmpfloat;override;
procedure second_cmpboolean;override;
procedure second_cmpsmallset;override;
procedure second_cmp64bit;override;
procedure second_cmpordinal;override;
end;
implementation
uses
systems,
cutils,verbose,
paramgr,procinfo,
aasmtai,aasmdata,aasmcpu,defutil,
hlcgobj,hlcgcpu,cgutils,
cpupara,
ncon,nset,nadd,
cgobj;
{*****************************************************************************
tjvmaddnode
*****************************************************************************}
function tjvmaddnode.pass_1: tnode;
begin
result:=inherited pass_1;
if expectloc=LOC_FLAGS then
expectloc:=LOC_JUMP;
end;
function tjvmaddnode.cmpnode2signedtopcmp: TOpCmp;
begin
case nodetype of
gtn: result:=OC_GT;
gten: result:=OC_GTE;
ltn: result:=OC_LT;
lten: result:=OC_LTE;
equaln: result:=OC_EQ;
unequaln: result:=OC_NE;
else
internalerror(2011010412);
end;
end;
procedure tjvmaddnode.second_generic_compare;
begin
pass_left_right;
if (nf_swapped in flags) then
swapleftright;
location_reset(location,LOC_JUMP,OS_NO);
if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
hlcg.a_cmp_loc_reg_label(current_asmdata.CurrAsmList,left.resultdef,cmpnode2signedtopcmp,right.location,left.location.register,current_procinfo.CurrTrueLabel)
else case right.location.loc of
LOC_REGISTER,LOC_CREGISTER:
hlcg.a_cmp_reg_loc_label(current_asmdata.CurrAsmList,left.resultdef,cmpnode2signedtopcmp,right.location.register,left.location,current_procinfo.CurrTrueLabel);
LOC_REFERENCE,LOC_CREFERENCE:
hlcg.a_cmp_ref_loc_label(current_asmdata.CurrAsmList,left.resultdef,cmpnode2signedtopcmp,right.location.reference,left.location,current_procinfo.CurrTrueLabel);
LOC_CONSTANT:
hlcg.a_cmp_const_loc_label(current_asmdata.CurrAsmList,left.resultdef,cmpnode2signedtopcmp,right.location.value,left.location,current_procinfo.CurrTrueLabel);
else
internalerror(2011010413);
end;
hlcg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
end;
procedure tjvmaddnode.second_addfloat;
var
op : TAsmOp;
begin
pass_left_right;
if (nf_swapped in flags) then
swapleftright;
thlcgjvm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
thlcgjvm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,right.resultdef,right.location);
location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
location.register:=hlcg.getfpuregister(current_asmdata.CurrAsmList,resultdef);
case nodetype of
addn :
begin
if location.size=OS_F64 then
op:=a_dadd
else
op:=a_fadd;
end;
muln :
begin
if location.size=OS_F64 then
op:=a_dmul
else
op:=a_fmul;
end;
subn :
begin
if location.size=OS_F64 then
op:=a_dsub
else
op:=a_fsub;
end;
slashn :
begin
if location.size=OS_F64 then
op:=a_ddiv
else
op:=a_fdiv;
end;
else
internalerror(2011010402);
end;
current_asmdata.CurrAsmList.concat(taicpu.op_none(op));
thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,1+ord(location.size=OS_F64));
{ could be optimized in the future by keeping the results on the stack,
if we add code to swap the operands when necessary (a_swap for
singles, store/load/load for doubles since there is no swap for
2-slot elements -- also adjust expectloc in that case! }
thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,resultdef,location.register);
end;
procedure tjvmaddnode.second_cmpfloat;
var
op : tasmop;
begin
pass_left_right;
if (nf_swapped in flags) then
swapleftright;
location_reset(location,LOC_JUMP,OS_NO);
thlcgjvm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
thlcgjvm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,right.resultdef,right.location);
{ compares two floating point values and puts 1/0/-1 on stack depending
on whether value1 >/=/< value2 }
if left.location.size=OS_F64 then
{ make sure that comparisons with NaNs always return false for </> }
if nodetype in [ltn,lten] then
op:=a_dcmpg
else
op:=a_dcmpl
else if nodetype in [ltn,lten] then
op:=a_fcmpg
else
op:=a_fcmpl;
current_asmdata.CurrAsmList.concat(taicpu.op_none(op));
thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,(1+ord(left.location.size=OS_F64))*2-1);
current_asmdata.CurrAsmList.concat(taicpu.op_sym(opcmp2if[cmpnode2signedtopcmp],current_procinfo.CurrTrueLabel));
thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,1);
hlcg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
end;
procedure tjvmaddnode.second_cmpboolean;
begin
second_generic_compare;
end;
procedure tjvmaddnode.second_cmpsmallset;
begin
if (nodetype in [equaln,unequaln]) then
begin
second_generic_compare;
exit;
end;
case nodetype of
lten,gten:
begin
pass_left_right;
If (not(nf_swapped in flags) and
(nodetype=lten)) or
((nf_swapped in flags) and
(nodetype=gten)) then
swapleftright;
location_reset(location,LOC_JUMP,OS_NO);
// now we have to check whether left >= right:
// (right and not(left)=0)
thlcgjvm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
thlcgjvm(hlcg).a_op_reg_stack(current_asmdata.CurrAsmList,OP_NOT,left.resultdef,NR_NO);
thlcgjvm(hlcg).a_op_loc_stack(current_asmdata.CurrAsmList,OP_AND,right.resultdef,right.location);
current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_ifeq,current_procinfo.CurrTrueLabel));
thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,1);
hlcg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
end;
else
internalerror(2011010414);
end;
end;
procedure tjvmaddnode.second_cmp64bit;
begin
second_generic_compare;
end;
procedure tjvmaddnode.second_cmpordinal;
begin
second_generic_compare;
end;
begin
caddnode:=tjvmaddnode;
end.