Browse Source

+ full JVM implementation for add-nodes and mat-nodes, except for
u64bit division/mod, and no overflow checking for divisions
(none yet for add nodes either, but that has to be implemented
in hlcgcpu rather than in the add-nodes themselves)

git-svn-id: branches/jvmbackend@18331 -

Jonas Maebe 14 years ago
parent
commit
f250d5d494
4 changed files with 451 additions and 1 deletions
  1. 2 0
      .gitattributes
  2. 1 1
      compiler/jvm/cpunode.pas
  3. 249 0
      compiler/jvm/njvmadd.pas
  4. 199 0
      compiler/jvm/njvmmat.pas

+ 2 - 0
.gitattributes

@@ -218,7 +218,9 @@ compiler/jvm/cputarg.pas svneol=native#text/plain
 compiler/jvm/hlcgcpu.pas svneol=native#text/plain
 compiler/jvm/itcpujas.pas svneol=native#text/plain
 compiler/jvm/jvmreg.dat svneol=native#text/plain
+compiler/jvm/njvmadd.pas svneol=native#text/plain
 compiler/jvm/njvmcal.pas svneol=native#text/plain
+compiler/jvm/njvmmat.pas svneol=native#text/plain
 compiler/jvm/rgcpu.pas svneol=native#text/plain
 compiler/jvm/rjvmcon.inc svneol=native#text/plain
 compiler/jvm/rjvmnor.inc svneol=native#text/plain

+ 1 - 1
compiler/jvm/cpunode.pas

@@ -32,7 +32,7 @@ implementation
   uses
     ncgbas,ncgflw,ncgcnv,ncgld,ncgmem,ncgcon,ncgset,
     ncgadd, ncgcal,ncgmat,ncginl,
-    njvmcal
+    njvmadd,njvmcal,njvmmat
 {    ncpuadd,ncpucall,ncpumat,ncpuinln,ncpucnv,ncpuset, }
     { this not really a node }
 {    rgcpu},tgcpu;

+ 249 - 0
compiler/jvm/njvmadd.pas

@@ -0,0 +1,249 @@
+{
+    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 right.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
+          hlcg.a_cmp_loc_reg_label(current_asmdata.CurrAsmList,left.resultdef,cmpnode2signedtopcmp,left.location,right.location.register,current_procinfo.CurrTrueLabel)
+        else case left.location.loc of
+          LOC_REGISTER,LOC_CREGISTER:
+            hlcg.a_cmp_reg_loc_label(current_asmdata.CurrAsmList,left.resultdef,cmpnode2signedtopcmp,left.location.register,right.location,current_procinfo.CurrTrueLabel);
+          LOC_REFERENCE,LOC_CREFERENCE:
+            hlcg.a_cmp_ref_loc_label(current_asmdata.CurrAsmList,left.resultdef,cmpnode2signedtopcmp,left.location.reference,right.location,current_procinfo.CurrTrueLabel);
+          LOC_CONSTANT:
+            hlcg.a_cmp_const_loc_label(current_asmdata.CurrAsmList,left.resultdef,cmpnode2signedtopcmp,left.location.value,right.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(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
+          op:=a_dcmpl
+        else
+          op:=a_fcmpl;
+        current_asmdata.CurrAsmList.concat(taicpu.op_none(op));
+        thlcgjvm(hlcg).decstack((1+ord(left.location.size=OS_F64))*2-1);
+
+        current_asmdata.CurrAsmList.concat(taicpu.op_sym(opcmp2if[cmpnode2signedtopcmp],current_procinfo.CurrTrueLabel));
+        thlcgjvm(hlcg).decstack(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(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.

+ 199 - 0
compiler/jvm/njvmmat.pas

@@ -0,0 +1,199 @@
+{
+    Copyright (c) 1998-2011 by Florian Klaempfl and Jonas Maebe
+
+    Generate JVM code 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 njvmmat;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      node,nmat,ncgmat;
+
+    type
+      tjvmmoddivnode = class(tmoddivnode)
+         procedure pass_generate_code;override;
+      end;
+
+      tjvmshlshrnode = class(tshlshrnode)
+         procedure pass_generate_code;override;
+      end;
+
+      tjvmnotnode = class(tcgnotnode)
+         procedure second_boolean;override;
+      end;
+
+implementation
+
+    uses
+      globtype,systems,constexp,
+      cutils,verbose,globals,
+      symconst,symdef,
+      aasmbase,aasmcpu,aasmtai,aasmdata,
+      defutil,
+      cgbase,cgobj,pass_2,procinfo,
+      ncon,
+      cpubase,
+      hlcgobj,hlcgcpu,cgutils;
+
+{*****************************************************************************
+                             tjvmmoddivnode
+*****************************************************************************}
+
+    procedure tjvmmoddivnode.pass_generate_code;
+      var
+        op: topcg;
+        isu32int: boolean;
+      begin
+         secondpass(left);
+         secondpass(right);
+         location_reset(location,LOC_REGISTER,left.location.size);
+         location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
+
+
+        if nodetype=divn then
+          begin
+            { TODO: overflow checking in case of high(longint) or high(int64) div -1 }
+            thlcgjvm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
+            if is_signed(resultdef) then
+              op:=OP_IDIV
+            else
+              op:=OP_DIV;
+            thlcgjvm(hlcg).a_op_loc_stack(current_asmdata.CurrAsmList,op,right.resultdef,right.location)
+          end
+        else
+          begin
+            { must be handled via a helper }
+            if torddef(resultdef).ordtype=u64bit then
+              internalerror(2011010416);
+            if (torddef(resultdef).ordtype<>u32bit) then
+              begin
+                isu32int:=false;
+                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);
+              end
+            else
+              begin
+                isu32int:=true;
+                if left.location.loc=LOC_CONSTANT then
+                  thlcgjvm(hlcg).a_load_const_stack(current_asmdata.CurrAsmList,s64inttype,left.location.value,R_INTREGISTER)
+                else
+                  begin
+                    thlcgjvm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
+                    thlcgjvm(hlcg).resize_stack_int_val(current_asmdata.CurrAsmList,OS_32,OS_S64,false);
+                  end;
+                if right.location.loc=LOC_CONSTANT then
+                  thlcgjvm(hlcg).a_load_const_stack(current_asmdata.CurrAsmList,s64inttype,right.location.value,R_INTREGISTER)
+                else
+                  begin
+                    thlcgjvm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,right.resultdef,right.location);
+                    thlcgjvm(hlcg).resize_stack_int_val(current_asmdata.CurrAsmList,OS_32,OS_S64,false);
+                  end;
+              end;
+            if isu32int or
+               (torddef(resultdef).ordtype=s64bit) then
+              begin
+                current_asmdata.CurrAsmList.concat(taicpu.op_none(a_lrem));
+                thlcgjvm(hlcg).decstack(2);
+              end
+            else
+              begin
+                current_asmdata.CurrAsmList.concat(taicpu.op_none(a_irem));
+                thlcgjvm(hlcg).decstack(1);
+              end;
+            if isu32int then
+              thlcgjvm(hlcg).resize_stack_int_val(current_asmdata.CurrAsmList,OS_S64,OS_32,false);
+          end;
+         thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,resultdef,location.register);
+      end;
+
+
+{*****************************************************************************
+                             tjvmshlshrnode
+*****************************************************************************}
+
+    procedure tjvmshlshrnode.pass_generate_code;
+      var
+        op : topcg;
+      begin
+        secondpass(left);
+        secondpass(right);
+        location_reset(location,LOC_REGISTER,left.location.size);
+        location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
+
+        thlcgjvm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
+        if nodetype=shln then
+          op:=OP_SHL
+        else
+          op:=OP_SHR;
+        thlcgjvm(hlcg).a_op_loc_stack(current_asmdata.CurrAsmList,op,right.resultdef,right.location);
+        thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,resultdef,location.register);
+      end;
+
+
+{*****************************************************************************
+                               tjvmnotnode
+*****************************************************************************}
+
+    procedure tjvmnotnode.second_boolean;
+      var
+        hl : tasmlabel;
+      begin
+        { if the location is LOC_JUMP, we do the secondpass after the
+          labels are allocated
+        }
+        if left.expectloc=LOC_JUMP then
+          begin
+            hl:=current_procinfo.CurrTrueLabel;
+            current_procinfo.CurrTrueLabel:=current_procinfo.CurrFalseLabel;
+            current_procinfo.CurrFalseLabel:=hl;
+            secondpass(left);
+            hlcg.maketojumpbool(current_asmdata.CurrAsmList,left);
+            hl:=current_procinfo.CurrTrueLabel;
+            current_procinfo.CurrTrueLabel:=current_procinfo.CurrFalseLabel;
+            current_procinfo.CurrFalseLabel:=hl;
+            location.loc:=LOC_JUMP;
+          end
+        else
+          begin
+            secondpass(left);
+            case left.location.loc of
+              LOC_REGISTER, LOC_CREGISTER,
+              LOC_REFERENCE, LOC_CREFERENCE:
+                begin
+                  location_reset(location,LOC_REGISTER,left.location.size);
+                  location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
+                  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_load_stack_reg(current_asmdata.CurrAsmList,resultdef,location.register);
+                end;
+              else
+                internalerror(2011010417);
+            end;
+          end;
+      end;
+
+
+begin
+   cmoddivnode:=tjvmmoddivnode;
+   cshlshrnode:=tjvmshlshrnode;
+   cnotnode:=tjvmnotnode;
+end.