Explorar o código

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 %!s(int64=7) %!d(string=hai) anos
pai
achega
74a7963d58
Modificáronse 6 ficheiros con 147 adicións e 116 borrados
  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:                                       }
 { .section .data.rel.ro._ZTV6Window,"awG",@progbits,_ZTV6Window,comdat    }
 { TODO: .data.ro not yet working}
-{$if defined(arm) or defined(powerpc)}
+{$if defined(arm) or defined(riscv64) or defined(powerpc)}
           '.rodata',
 {$else arm}
           '.data',

+ 6 - 6
compiler/riscv/cgrv.pas

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

+ 128 - 105
compiler/riscv64/cgcpu.pas

@@ -95,8 +95,12 @@ implementation
       var
         ai: taicpu;
       begin
+        list.concat(tai_comment.Create(strpnew('Move '+tcgsize2str(fromsize)+'->'+tcgsize2str(tosize))));
+
         if (tcgsize2unsigned[tosize]=OS_64) and (fromsize=OS_S32) then
           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
           list.Concat(taicpu.op_reg_reg_const(A_ANDI,reg2,reg1,$FF))
         else if (tcgsize2size[fromsize] > tcgsize2size[tosize]) or
@@ -187,69 +191,15 @@ implementation
         l: TAsmLabel;
         tmpreg: tregister;
         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
             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;
 
 
@@ -262,60 +212,133 @@ implementation
       begin
         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
-                {
-                  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
-                    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;
+
+                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);
-                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;
+            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;
 
 

+ 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}
 { $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_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}
 

+ 2 - 2
tests/tbs/tb0627b.pp

@@ -47,10 +47,10 @@ program tb0627b;
 {$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)}
 
-{$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_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}
 

+ 8 - 0
tests/webtbs/tw11563.pp

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