Browse Source

Redo overflow checking code.
Fix shift operators in case of unsigned subreg operations. There should be no sign extension here.
Add some unittest implementations that test stack execution and writing to readonly constants.

git-svn-id: branches/laksen/riscv_new@39762 -

Jeppe Johansen 7 years ago
parent
commit
74a7963d58
6 changed files with 147 additions and 116 deletions
  1. 1 1
      compiler/aggas.pas
  2. 6 6
      compiler/riscv/cgrv.pas
  3. 128 105
      compiler/riscv64/cgcpu.pas
  4. 2 2
      rtl/inc/systemh.inc
  5. 2 2
      tests/tbs/tb0627b.pp
  6. 8 0
      tests/webtbs/tw11563.pp

+ 1 - 1
compiler/aggas.pas

@@ -211,7 +211,7 @@ implementation
 { vtable for a class called Window:                                       }
 { vtable for a class called Window:                                       }
 { .section .data.rel.ro._ZTV6Window,"awG",@progbits,_ZTV6Window,comdat    }
 { .section .data.rel.ro._ZTV6Window,"awG",@progbits,_ZTV6Window,comdat    }
 { TODO: .data.ro not yet working}
 { TODO: .data.ro not yet working}
-{$if defined(arm) or defined(powerpc)}
+{$if defined(arm) or defined(riscv64) or defined(powerpc)}
           '.rodata',
           '.rodata',
 {$else arm}
 {$else arm}
           '.data',
           '.data',

+ 6 - 6
compiler/riscv/cgrv.pas

@@ -198,19 +198,19 @@ unit cgrv;
 
 
 {$ifdef RISCV64}
 {$ifdef RISCV64}
         if (op=OP_SHL) and
         if (op=OP_SHL) and
-           (size in [OS_32,OS_S32]) then
+               (size=OS_S32) then
           begin
           begin
             list.concat(taicpu.op_reg_reg_const(A_SLLIW,dst,src,a));
             list.concat(taicpu.op_reg_reg_const(A_SLLIW,dst,src,a));
             maybeadjustresult(list,op,size,dst);
             maybeadjustresult(list,op,size,dst);
           end
           end
         else if (op=OP_SHR) and
         else if (op=OP_SHR) and
-           (size in [OS_32,OS_S32]) then
+               (size=OS_S32) then
           begin
           begin
             list.concat(taicpu.op_reg_reg_const(A_SRLIW,dst,src,a));
             list.concat(taicpu.op_reg_reg_const(A_SRLIW,dst,src,a));
             maybeadjustresult(list,op,size,dst);
             maybeadjustresult(list,op,size,dst);
           end
           end
         else if (op=OP_SAR) and
         else if (op=OP_SAR) and
-           (size in [OS_32,OS_S32]) then
+               (size=OS_S32) then
           begin
           begin
             list.concat(taicpu.op_reg_reg_const(A_SRAIW,dst,src,a));
             list.concat(taicpu.op_reg_reg_const(A_SRAIW,dst,src,a));
             maybeadjustresult(list,op,size,dst);
             maybeadjustresult(list,op,size,dst);
@@ -251,19 +251,19 @@ unit cgrv;
           else
           else
 {$ifdef RISCV64}
 {$ifdef RISCV64}
             if (op=OP_SHL) and
             if (op=OP_SHL) and
-               (size in [OS_32,OS_S32]) then
+               (size=OS_S32) then
               begin
               begin
                 list.concat(taicpu.op_reg_reg_reg(A_SLLW,dst,src2,src1));
                 list.concat(taicpu.op_reg_reg_reg(A_SLLW,dst,src2,src1));
                 maybeadjustresult(list,op,size,dst);
                 maybeadjustresult(list,op,size,dst);
               end
               end
             else if (op=OP_SHR) and
             else if (op=OP_SHR) and
-               (size in [OS_32,OS_S32]) then
+               (size=OS_S32) then
               begin
               begin
                 list.concat(taicpu.op_reg_reg_reg(A_SRLW,dst,src2,src1));
                 list.concat(taicpu.op_reg_reg_reg(A_SRLW,dst,src2,src1));
                 maybeadjustresult(list,op,size,dst);
                 maybeadjustresult(list,op,size,dst);
               end
               end
             else if (op=OP_SAR) and
             else if (op=OP_SAR) and
-               (size in [OS_32,OS_S32]) then
+               (size=OS_S32) then
               begin
               begin
                 list.concat(taicpu.op_reg_reg_reg(A_SRAW,dst,src2,src1));
                 list.concat(taicpu.op_reg_reg_reg(A_SRAW,dst,src2,src1));
                 maybeadjustresult(list,op,size,dst);
                 maybeadjustresult(list,op,size,dst);

+ 128 - 105
compiler/riscv64/cgcpu.pas

@@ -95,8 +95,12 @@ implementation
       var
       var
         ai: taicpu;
         ai: taicpu;
       begin
       begin
+        list.concat(tai_comment.Create(strpnew('Move '+tcgsize2str(fromsize)+'->'+tcgsize2str(tosize))));
+
         if (tcgsize2unsigned[tosize]=OS_64) and (fromsize=OS_S32) then
         if (tcgsize2unsigned[tosize]=OS_64) and (fromsize=OS_S32) then
           list.Concat(taicpu.op_reg_reg_const(A_ADDIW,reg2,reg1,0))
           list.Concat(taicpu.op_reg_reg_const(A_ADDIW,reg2,reg1,0))
+        else if (tosize=OS_S32) and (tcgsize2unsigned[fromsize]=OS_64) then
+          list.Concat(taicpu.op_reg_reg_const(A_ADDIW,reg2,reg1,0))
         else if (tcgsize2unsigned[tosize]=OS_64) and (fromsize=OS_8) then
         else if (tcgsize2unsigned[tosize]=OS_64) and (fromsize=OS_8) then
           list.Concat(taicpu.op_reg_reg_const(A_ANDI,reg2,reg1,$FF))
           list.Concat(taicpu.op_reg_reg_const(A_ANDI,reg2,reg1,$FF))
         else if (tcgsize2size[fromsize] > tcgsize2size[tosize]) or
         else if (tcgsize2size[fromsize] > tcgsize2size[tosize]) or
@@ -187,69 +191,15 @@ implementation
         l: TAsmLabel;
         l: TAsmLabel;
         tmpreg: tregister;
         tmpreg: tregister;
         ai: taicpu;
         ai: taicpu;
-      begin           
-        signed:=tcgsize2unsigned[size]<>size;
-
-        if setflags and
-           (op=OP_ADD) and
-           (src=dst) and
-           (not signed) then
+      begin
+        if setflags then
           begin
           begin
             tmpreg:=getintregister(list,size);
             tmpreg:=getintregister(list,size);
-            a_load_reg_reg(list,size,size,src,tmpreg);
-            src:=tmpreg;
-          end;
-
-        a_op_const_reg_reg(list,op,size,a,src,dst);
-
-        if setflags and
-           (op=OP_ADD) then
-          begin
-            current_asmdata.getjumplabel(l);
-            if signed then
-              begin
-                {
-                  t0=a<0
-                  t1=result<a
-                  jump if t0=t1
-                }
-                tmpreg:=getintregister(list,OS_INT);
-                if is_imm12(a) then
-                  list.Concat(taicpu.op_reg_reg_const(A_SLTI,tmpreg,dst,a))
-                else
-                  begin
-                    a_load_const_reg(list,OS_INT,a,tmpreg);
-                    list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg,dst,tmpreg));
-                  end;
-
-                ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,tmpreg,NR_X0,l,0);
-                if a<0 then
-                  ai.condition:=C_NE
-                else
-                  ai.condition:=C_EQ;
-                list.concat(ai);
-              end
-            else
-              begin
-                {
-                  jump if not sum<x
-                }
-                tmpreg:=getintregister(list,OS_INT);
-                if size in [OS_S32,OS_32] then
-                  begin
-                    a_load_reg_reg(list,size,OS_64,dst,tmpreg);
-                    dst:=tmpreg;
-                  end;
-                list.Concat(taicpu.op_reg_reg_reg(A_SLTU,tmpreg,dst,src));
-                                                                        
-                ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,tmpreg,NR_X0,l,0);
-                ai.condition:=C_EQ;
-                list.concat(ai);
-              end;
-
-            a_call_name(list,'FPC_OVERFLOW',false);
-            a_label(list,l);
-          end;
+            a_load_const_reg(list,size,a,tmpreg);
+            a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,setflags,ovloc);
+          end
+        else
+          a_op_const_reg_reg(list,op,size,a,src,dst);
       end;
       end;
 
 
 
 
@@ -262,60 +212,133 @@ implementation
       begin
       begin
         signed:=tcgsize2unsigned[size]<>size;
         signed:=tcgsize2unsigned[size]<>size;
 
 
-        if setflags and
-           (op=OP_ADD) and
-           (src2=dst) and
-           (not signed) then
-          begin
-            tmpreg:=getintregister(list,size);
-            a_load_reg_reg(list,size,size,src2,tmpreg);
-            src2:=tmpreg;
-          end;
+        if setflags then
+          case op of
+            OP_ADD:
+              begin
+                current_asmdata.getjumplabel(l);
 
 
-        a_op_reg_reg_reg(list,op,size,src1,src2,dst);
+                list.Concat(taicpu.op_reg_reg_reg(A_ADD,dst,src2,src1));
 
 
-        if setflags and
-           (op=OP_ADD) then
-          begin
-            current_asmdata.getjumplabel(l);
-            if signed then
-              begin
-                {
-                  t0=src1<0
-                  t1=result<src1
-                  jump if t0=t1
-                }
-                tmpreg0:=getintregister(list,OS_INT);
-                tmpreg:=getintregister(list,OS_INT);
-                list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg0,src1,NR_X0));
-                list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg,dst,src1));
+                if signed then
+                  begin
+                    {
+                      t0=src1<0
+                      t1=result<src2
+                      overflow if t0<>t1
+                    }
+                    tmpreg0:=getintregister(list,OS_INT);
+                    tmpreg:=getintregister(list,OS_INT);
+                    list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg0,src1,NR_X0));
+                    list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg,dst,src2));
+
+                    ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,tmpreg,tmpreg0,l,0);
+                    ai.condition:=C_EQ;
+                    list.concat(ai);
+                  end
+                else
+                  begin
+                    {
+                      jump if sum>=x
+                    }
+                    if size in [OS_S32,OS_32] then
+                      begin
+                        tmpreg:=getintregister(list,OS_INT);
+                        a_load_reg_reg(list,size,OS_64,dst,tmpreg);
+                        dst:=tmpreg;
+                      end;
 
 
-                ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,tmpreg,tmpreg0,l,0);
-                ai.condition:=C_EQ;
-                list.concat(ai);
-              end
-            else
+                    ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,dst,src2,l,0);
+                    ai.condition:=C_GEU;
+                    list.concat(ai);
+                  end;
+
+                a_call_name(list,'FPC_OVERFLOW',false);
+                a_label(list,l);
+              end;
+            OP_SUB:
               begin
               begin
-                {
-                  jump if not sum<x
-                }
-                tmpreg:=getintregister(list,OS_INT);
-                if size in [OS_S32,OS_32] then
+                current_asmdata.getjumplabel(l);
+
+                list.Concat(taicpu.op_reg_reg_reg(A_SUB,dst,src2,src1));
+
+                if signed then
+                  begin
+                    tmpreg0:=getintregister(list,OS_INT);
+                    tmpreg:=getintregister(list,OS_INT);
+                    list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg0,NR_X0,src1));
+                    list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg,dst,src2));
+
+                    ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,tmpreg,tmpreg0,l,0);
+                    ai.condition:=C_EQ;
+                    list.concat(ai);
+                  end
+                else
                   begin
                   begin
-                    a_load_reg_reg(list,size,OS_64,dst,tmpreg);
-                    dst:=tmpreg;
+                    { no overflow if result<=src2 }
+                    if size in [OS_S32,OS_32] then
+                      begin
+                        tmpreg:=getintregister(list,OS_INT);
+                        a_load_reg_reg(list,size,OS_64,dst,tmpreg);
+                        dst:=tmpreg;
+                      end;
+
+                    ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,src2,dst,l,0);
+                    ai.condition:=C_GEU;
+                    list.concat(ai);
                   end;
                   end;
+
+                a_call_name(list,'FPC_OVERFLOW',false);
+                a_label(list,l);
+              end;
+            OP_IMUL:
+              begin
+                { No overflow if upper result is same as sign of result }
+                current_asmdata.getjumplabel(l);
+
+                tmpreg:=getintregister(list,OS_INT);
+                tmpreg0:=getintregister(list,OS_INT);
+                list.Concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2));
+                list.Concat(taicpu.op_reg_reg_reg(A_MULH,tmpreg,src1,src2));
+
+                list.concat(taicpu.op_reg_reg_const(A_SRAI,tmpreg0,dst,63));
+
+                a_cmp_reg_reg_label(list,OS_INT,OC_EQ,tmpreg,tmpreg0,l);
+
+                a_call_name(list,'FPC_OVERFLOW',false);
+                a_label(list,l);
+              end;
+            OP_MUL:
+              begin
+                { No overflow if upper result is 0 }
+                current_asmdata.getjumplabel(l);
+
                 tmpreg:=getintregister(list,OS_INT);
                 tmpreg:=getintregister(list,OS_INT);
-                list.Concat(taicpu.op_reg_reg_reg(A_SLTU,tmpreg,dst,src2));
+                list.Concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2));
+                list.Concat(taicpu.op_reg_reg_reg(A_MULHU,tmpreg,src1,src2));
 
 
-                ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,tmpreg,NR_X0,l,0);
-                ai.condition:=C_EQ;
-                list.concat(ai);
+                a_cmp_reg_reg_label(list,OS_INT,OC_EQ,tmpreg,NR_X0,l);
+
+                a_call_name(list,'FPC_OVERFLOW',false);
+                a_label(list,l);
               end;
               end;
+            OP_IDIV:
+              begin
+                { Only overflow if dst is all 1's }
+                current_asmdata.getjumplabel(l);
 
 
-            a_call_name(list,'FPC_OVERFLOW',false);
-            a_label(list,l);
-          end;
+                tmpreg:=getintregister(list,OS_INT);
+                list.Concat(taicpu.op_reg_reg_reg(A_DIV,dst,src1,src2));
+                list.Concat(taicpu.op_reg_reg_const(A_ADDI,tmpreg,dst,1));
+
+                a_cmp_reg_reg_label(list,OS_INT,OC_NE,tmpreg,NR_X0,l);
+
+                a_call_name(list,'FPC_OVERFLOW',false);
+                a_label(list,l);
+              end;
+          end
+        else
+          a_op_reg_reg_reg(list,op,size,src1,src2,dst);
       end;
       end;
 
 
 
 

+ 2 - 2
rtl/inc/systemh.inc

@@ -1092,10 +1092,10 @@ function RolQWord(Const AValue : QWord;const Dist : Byte): QWord;{$ifdef SYSTEMI
 {$define FPC_HAS_INTERNAL_SAR_DWORD}
 {$define FPC_HAS_INTERNAL_SAR_DWORD}
 { $endif defined(cpux86_64) or defined(cpui386) or defined(cpuarm) or defined(cpupowerpc) or defined(cpupowerpc64) or defined(cpumips) or defined(cpumipsel)}
 { $endif defined(cpux86_64) or defined(cpui386) or defined(cpuarm) or defined(cpupowerpc) or defined(cpupowerpc64) or defined(cpumips) or defined(cpumipsel)}
 
 
-{$if defined(cpux86_64) or defined(cpupowerpc64) or defined(cpuaarch64)}
+{$if defined(cpux86_64) or defined(cpupowerpc64) or defined(cpuaarch64) or defined(cpuriscv64)}
 {$define FPC_HAS_INTERNAL_SAR_QWORD}
 {$define FPC_HAS_INTERNAL_SAR_QWORD}
 {$define FPC_HAS_INTERNAL_SAR_ASSIGN_QWORD}
 {$define FPC_HAS_INTERNAL_SAR_ASSIGN_QWORD}
-{$endif defined(cpux86_64) or defined(cpupowerpc64) or defined(cpuaarch64)}
+{$endif defined(cpux86_64) or defined(cpupowerpc64) or defined(cpuaarch64) or defined(cpuriscv64)}
 
 
 {$endif FPC_HAS_INTERNAL_SAR}
 {$endif FPC_HAS_INTERNAL_SAR}
 
 

+ 2 - 2
tests/tbs/tb0627b.pp

@@ -47,10 +47,10 @@ program tb0627b;
 {$define FPC_HAS_INTERNAL_SAR_DWORD}
 {$define FPC_HAS_INTERNAL_SAR_DWORD}
 { $endif defined(cpux86_64) or defined(cpui386) or defined(cpuarm) or defined(cpupowerpc) or defined(cpupowerpc64) or defined(cpumips) or defined(cpumipsel)}
 { $endif defined(cpux86_64) or defined(cpui386) or defined(cpuarm) or defined(cpupowerpc) or defined(cpupowerpc64) or defined(cpumips) or defined(cpumipsel)}
 
 
-{$if defined(cpux86_64) or defined(cpupowerpc64) or defined(cpuaarch64)}
+{$if defined(cpux86_64) or defined(cpupowerpc64) or defined(cpuaarch64) or defined(cpuriscv64)}
 {$define FPC_HAS_INTERNAL_SAR_QWORD}
 {$define FPC_HAS_INTERNAL_SAR_QWORD}
 {$define FPC_HAS_INTERNAL_SAR_ASSIGN_QWORD}
 {$define FPC_HAS_INTERNAL_SAR_ASSIGN_QWORD}
-{$endif defined(cpux86_64) or defined(cpupowerpc64) or defined(cpuaarch64)}
+{$endif defined(cpux86_64) or defined(cpupowerpc64) or defined(cpuaarch64) or defined(cpuriscv64)}
 
 
 {$endif FPC_HAS_INTERNAL_SAR}
 {$endif FPC_HAS_INTERNAL_SAR}
 
 

+ 8 - 0
tests/webtbs/tw11563.pp

@@ -12,6 +12,9 @@ program ExecStack;
 {$if defined(cpuaarch64)}
 {$if defined(cpuaarch64)}
     ret: longint;
     ret: longint;
 {$endif}
 {$endif}
+{$if defined(cpuriscv64)}
+    ret: longint;
+{$endif}
 {$if defined(cpui386) or defined(cpux86_64)}
 {$if defined(cpui386) or defined(cpux86_64)}
     ret: Byte;
     ret: Byte;
 {$endif}
 {$endif}
@@ -48,6 +51,11 @@ program ExecStack;
     DoNothing := proc(@ret);
     DoNothing := proc(@ret);
     DoNothing;
     DoNothing;
 {$endif}
 {$endif}
+{$if defined(cpuriscv64)}
+    ret := $00008067;
+    DoNothing := proc(@ret);
+    DoNothing;
+{$endif}
 {$if defined(cpui386) or defined(cpux86_64)}
 {$if defined(cpui386) or defined(cpux86_64)}
     ret := $C3;
     ret := $C3;
     DoNothing := proc(@ret);
     DoNothing := proc(@ret);