Browse Source

m68k/n68kadd.pas:
+ add support for 64-bit comparisons; the code is based on the code of mips/ncpuadd.pas, but heavily adjusted for m68k

git-svn-id: trunk@22913 -

svenbarth 12 years ago
parent
commit
9d4d7d748c
1 changed files with 299 additions and 6 deletions
  1. 299 6
      compiler/m68k/n68kadd.pas

+ 299 - 6
compiler/m68k/n68kadd.pas

@@ -26,13 +26,21 @@ unit n68kadd;
 interface
 
     uses
-       node,nadd,ncgadd,cpubase;
+       node,nadd,ncgadd,cpubase,cgbase;
 
 
     type
        t68kaddnode = class(tcgaddnode)
        private
+          function cmp64_lt(left_reg,right_reg:tregister64):tregister;
+          function cmp64_le(left_reg,right_reg:tregister64):tregister;
+          function cmp64_eq(left_reg,right_reg:tregister64):tregister;
+          function cmp64_ne(left_reg,right_reg:tregister64):tregister;
+          function cmp64_ltu(left_reg,right_reg:tregister64):tregister;
+          function cmp64_leu(left_reg,right_reg:tregister64):tregister;
+
           function getresflags(unsigned: boolean) : tresflags;
+          function getres64_register(unsigned:boolean;left_reg,right_reg:tregister64):tregister;
        protected
           procedure second_addfloat;override;
           procedure second_cmpfloat;override;
@@ -40,6 +48,8 @@ interface
           procedure second_cmpsmallset;override;
           procedure second_cmp64bit;override;
           procedure second_cmpboolean;override;
+       public
+          function pass_1:tnode;override;
        end;
 
 
@@ -48,9 +58,9 @@ implementation
     uses
       globtype,systems,
       cutils,verbose,globals,
-      symconst,symdef,paramgr,
+      symconst,symdef,paramgr,symtype,
       aasmbase,aasmtai,aasmdata,aasmcpu,defutil,htypechk,
-      cgbase,cpuinfo,pass_1,pass_2,regvars,
+      cpuinfo,pass_1,pass_2,regvars,
       cpupara,cgutils,procinfo,
       ncon,nset,
       ncgutil,tgobj,rgobj,rgcpu,cgobj,hlcgobj,cg64f32;
@@ -59,6 +69,193 @@ implementation
                                   Helpers
 *****************************************************************************}
 
+    function t68kaddnode.cmp64_lt(left_reg,right_reg:tregister64):tregister;
+      var
+        labelcmp64_1,labelcmp64_2 : tasmlabel;
+        tmpreg : tregister;
+      begin
+        tmpreg:=cg.getintregister(current_asmdata.currasmlist,OS_INT);
+
+        { load the value for "false" }
+        current_asmdata.currasmlist.concat(taicpu.op_const_reg(A_MOVE,S_L,0,tmpreg));
+
+        current_asmdata.getjumplabel(labelcmp64_1);
+        current_asmdata.getjumplabel(labelcmp64_2);
+
+        { check whether left_reg.reghi is less than right_reg.reghi }
+        current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,right_reg.reghi,left_reg.reghi));
+        current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_LT,S_L,labelcmp64_2));
+
+        { are left_reg.reghi and right_reg.reghi equal? }
+        current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_NE,S_L,labelcmp64_1));
+
+        { is left_reg.reglo less than right_reg.reglo? }
+        current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,right_reg.reglo,left_reg.reglo));
+        current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_CS,S_L,labelcmp64_2));
+
+        current_asmdata.currasmlist.concat(Taicpu.op_sym(A_BRA,S_L,labelcmp64_1));
+
+        cg.a_label(current_asmdata.currasmlist,labelcmp64_2);
+
+        { load the value for "true" }
+        current_asmdata.currasmlist.concat(taicpu.op_const_reg(A_MOVE,S_L,1,tmpreg));
+
+        cg.a_label(current_asmdata.currasmlist,labelcmp64_1);
+        result:=tmpreg;
+      end;
+
+    function t68kaddnode.cmp64_le(left_reg,right_reg:tregister64):tregister;
+      var
+        labelcmp64_1,labelcmp64_2 : tasmlabel;
+        tmpreg : tregister;
+      begin
+        tmpreg:=cg.getintregister(current_asmdata.currasmlist,OS_INT);
+
+        { load the value for "false" }
+        current_asmdata.currasmlist.concat(taicpu.op_const_reg(A_MOVE,S_L,0,tmpreg));
+
+        current_asmdata.getjumplabel(labelcmp64_1);
+        current_asmdata.getjumplabel(labelcmp64_2);
+
+        { check whether right_reg.reghi is less than left_reg.reghi }
+        current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,left_reg.reghi,right_reg.reghi));
+        current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_LT,S_L,labelcmp64_1));
+
+        { are left_reg.reghi and right_reg.reghi equal? }
+        current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_NE,S_L,labelcmp64_2));
+
+        { is right_reg.reglo less than left_reg.reglo? }
+        current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,left_reg.reglo,right_reg.reglo));
+        current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_CS,S_L,labelcmp64_1));
+
+        cg.a_label(current_asmdata.currasmlist,labelcmp64_2);
+
+        { load the value for "true" }
+        current_asmdata.currasmlist.concat(taicpu.op_const_reg(A_MOVE,S_L,1,tmpreg));
+
+        cg.a_label(current_asmdata.currasmlist,labelcmp64_1);
+        result:=tmpreg;
+      end;
+
+    function t68kaddnode.cmp64_eq(left_reg,right_reg:tregister64):tregister;
+      var
+        labelcmp64 : tasmlabel;
+        tmpreg : tregister;
+      begin
+        tmpreg:=cg.getintregister(current_asmdata.currasmlist,OS_INT);
+        current_asmdata.getjumplabel(labelcmp64);
+
+        { load the value for "false" }
+        current_asmdata.currasmlist.concat(taicpu.op_const_reg(A_MOVE,S_L,0,tmpreg));
+
+        { is the high order longword equal? }
+        current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,left_reg.reghi,right_reg.reghi));
+        current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_NE,S_L,labelcmp64));
+
+        { is the low order longword equal? }
+        current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,left_reg.reglo,right_reg.reglo));
+        current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_NE,S_L,labelcmp64));
+
+        { load the value for "true" }
+        current_asmdata.currasmlist.concat(taicpu.op_const_reg(A_MOVE,S_L,1,tmpreg));
+
+        cg.a_label(current_asmdata.currasmlist,labelcmp64);
+        result:=tmpreg;
+      end;
+
+    function t68kaddnode.cmp64_ne(left_reg,right_reg:tregister64):tregister;
+      var
+        labelcmp64 : tasmlabel;
+        tmpreg : tregister;
+      begin
+        tmpreg:=cg.getintregister(current_asmdata.currasmlist,OS_INT);
+        current_asmdata.getjumplabel(labelcmp64);
+
+        { load the value for "true" }
+        current_asmdata.currasmlist.concat(taicpu.op_const_reg(A_MOVE,S_L,1,tmpreg));
+
+        { is the high order longword equal? }
+        current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,left_reg.reghi,right_reg.reghi));
+        current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_NE,S_L,labelcmp64));
+
+        { is the low order longword equal? }
+        current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,left_reg.reglo,right_reg.reglo));
+        current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_NE,S_L,labelcmp64));
+
+        { load the value for "false" }
+        current_asmdata.currasmlist.concat(taicpu.op_const_reg(A_MOVE,S_L,0,tmpreg));
+
+        cg.a_label(current_asmdata.currasmlist,labelcmp64);
+        result:=tmpreg;
+      end;
+
+    function t68kaddnode.cmp64_ltu(left_reg,right_reg:tregister64):tregister;
+      var
+        labelcmp64_1,labelcmp64_2 : tasmlabel;
+        tmpreg : tregister;
+      begin
+        tmpreg:=cg.getintregister(current_asmdata.currasmlist,OS_INT);
+
+        { load the value for "false" }
+        current_asmdata.currasmlist.concat(taicpu.op_const_reg(A_MOVE,S_L,0,tmpreg));
+
+        current_asmdata.getjumplabel(labelcmp64_1);
+        current_asmdata.getjumplabel(labelcmp64_2);
+
+        { check whether left_reg.reghi is less than right_reg.reghi }
+        current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,right_reg.reghi,left_reg.reghi));
+        current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_CS,S_L,labelcmp64_2));
+
+        { are left_reg.reghi and right_reg.reghi equal? }
+        current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_NE,S_L,labelcmp64_1));
+
+        { is left_reg.reglo less than right_reg.reglo? }
+        current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,right_reg.reglo,left_reg.reglo));
+        current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_CS,S_L,labelcmp64_2));
+
+        current_asmdata.currasmlist.concat(Taicpu.op_sym(A_BRA,S_L,labelcmp64_1));
+
+        cg.a_label(current_asmdata.currasmlist,labelcmp64_2);
+
+        { load the value for "true" }
+        current_asmdata.currasmlist.concat(taicpu.op_const_reg(A_MOVE,S_L,1,tmpreg));
+
+        cg.a_label(current_asmdata.currasmlist,labelcmp64_1);
+        result:=tmpreg;
+      end;
+
+    function t68kaddnode.cmp64_leu(left_reg,right_reg:tregister64):tregister;
+      var
+        labelcmp64_1,labelcmp64_2 : tasmlabel;
+        tmpreg : tregister;
+      begin
+        tmpreg:=cg.getintregister(current_asmdata.currasmlist,OS_INT);
+
+        { load the value for "false" }
+        current_asmdata.currasmlist.concat(taicpu.op_const_reg(A_MOVE,S_L,0,tmpreg));
+
+        current_asmdata.getjumplabel(labelcmp64_1);
+        current_asmdata.getjumplabel(labelcmp64_2);
+
+        { check whether right_reg.reghi is less than left_reg.reghi }
+        current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,left_reg.reghi,right_reg.reghi));
+        current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_CS,S_L,labelcmp64_1));
+
+        { are left_reg.reghi and right_reg.reghi equal? }
+        current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_NE,S_L,labelcmp64_2));
+
+        { is right_reg.reglo less than left_reg.reglo? }
+        current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,left_reg.reglo,right_reg.reglo));
+        current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_CS,S_L,labelcmp64_1));
+
+        cg.a_label(current_asmdata.currasmlist,labelcmp64_2);
+
+        { load the value for "true" }
+        current_asmdata.currasmlist.concat(taicpu.op_const_reg(A_MOVE,S_L,1,tmpreg));
+
+        cg.a_label(current_asmdata.currasmlist,labelcmp64_1);
+        result:=tmpreg;
+      end;
 
     function t68kaddnode.getresflags(unsigned : boolean) : tresflags;
       begin
@@ -103,6 +300,67 @@ implementation
          end;
       end;
 
+    function t68kaddnode.getres64_register(unsigned:boolean;left_reg,right_reg:tregister64):tregister;
+      begin
+        case nodetype of
+          equaln:
+            result:=cmp64_eq(left_reg,right_reg);
+          unequaln:
+            result:=cmp64_ne(left_reg,right_reg);
+          else
+            if not unsigned then
+            begin
+              if nf_swapped in flags then
+                case nodetype of
+                  ltn:
+                    result:=cmp64_lt(right_reg,left_reg);
+                  lten:
+                    result:=cmp64_le(right_reg,left_reg);
+                  gtn:
+                    result:=cmp64_lt(left_reg,right_reg);
+                  gten:
+                    result:=cmp64_le(left_reg,right_reg);
+                end
+              else
+                case nodetype of
+                  ltn:
+                    result:=cmp64_lt(left_reg,right_reg);
+                  lten:
+                    result:=cmp64_le(left_reg,right_reg);
+                  gtn:
+                    result:=cmp64_lt(right_reg,left_reg);
+                  gten:
+                    result:=cmp64_le(right_reg,left_reg);
+                end;
+            end
+            else
+            begin
+              if nf_swapped in Flags then
+                case nodetype of
+                  ltn:
+                    result:=cmp64_ltu(right_reg,left_reg);
+                  lten:
+                    result:=cmp64_leu(right_reg,left_reg);
+                  gtn:
+                    result:=cmp64_ltu(left_reg,right_reg);
+                  gten:
+                    result:=cmp64_leu(left_reg,right_reg);
+                end
+              else
+                case nodetype of
+                  ltn:
+                    result:=cmp64_ltu(left_reg,right_reg);
+                  lten:
+                    result:=cmp64_leu(left_reg,right_reg);
+                  gtn:
+                    result:=cmp64_ltu(right_reg,left_reg);
+                  gten:
+                    result:=cmp64_leu(right_reg,left_reg);
+                end;
+            end;
+        end;
+      end;
+
 {*****************************************************************************
                                 AddFloat
 *****************************************************************************}
@@ -459,15 +717,50 @@ implementation
         //release_reg_left_right;
       end;
 
+    function t68kaddnode.pass_1:tnode;
+      var
+        ld,rd : tdef;
+      begin
+        result:=inherited pass_1;
+
+        { for 64 bit operations we return the resulting value in a register }
+        if not assigned(result) then
+          begin
+            rd:=right.resultdef;
+            ld:=left.resultdef;
+            if (nodetype in [ltn,lten,gtn,gten,equaln,unequaln]) and
+                (
+                  ((ld.typ=orddef) and (torddef(ld).ordtype in [u64bit,s64bit,scurrency])) or
+                  ((rd.typ=orddef) and (torddef(rd).ordtype in [u64bit,s64bit,scurrency]))
+                ) then
+              expectloc:=LOC_REGISTER;
+          end;
+      end;
+
 
 {*****************************************************************************
                                 64-bit
 *****************************************************************************}
 
     procedure t68kaddnode.second_cmp64bit;
-     begin
+      var
+        unsigned : boolean;
+        tmp_left_reg : tregister;
+      begin
+        pass_left_right;
+        force_reg_left_right(false,false);
+
+        unsigned:=not(is_signed(left.resultdef)) or
+                  not(is_signed(right.resultdef));
+
+        location_reset(location,LOC_REGISTER,OS_INT);
+        location.register:=getres64_register(unsigned,left.location.register64,right.location.register64);
+
+        { keep the below code for now, as we could optimize the =/<> code later
+          on based on it }
+
       // writeln('second_cmp64bit');
-      pass_left_right;
+//      pass_left_right;
 
 
 //     load_left_right(true,false);
@@ -565,7 +858,7 @@ implementation
            not(nodetype in [equaln,unequaln]) then
           location_reset(location,LOC_JUMP,OS_NO);
 *)
-       location_reset(location,LOC_JUMP,OS_NO);
+  //     location_reset(location,LOC_JUMP,OS_NO);
        // writeln('second_cmp64_exit');
      end;