summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlaksen <laksen@3ad0048d-3df7-0310-abae-a5850022a9f2>2018-09-16 18:37:59 +0000
committerlaksen <laksen@3ad0048d-3df7-0310-abae-a5850022a9f2>2018-09-16 18:37:59 +0000
commit6a21f8eb4bcbbe5b2f1d61192484439916a93e89 (patch)
tree4b395a317e0d0df3e5f536f7c2f3de9cc2784cbd
parente20a765cf7422ac03bba787f947468132de12ae7 (diff)
downloadfpc-6a21f8eb4bcbbe5b2f1d61192484439916a93e89.tar.gz
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: https://svn.freepascal.org/svn/fpc/branches/laksen@39762 3ad0048d-3df7-0310-abae-a5850022a9f2
-rw-r--r--riscv_new/compiler/aggas.pas2
-rw-r--r--riscv_new/compiler/riscv/cgrv.pas12
-rw-r--r--riscv_new/compiler/riscv64/cgcpu.pas233
-rw-r--r--riscv_new/rtl/inc/systemh.inc4
-rw-r--r--riscv_new/tests/tbs/tb0627b.pp4
-rw-r--r--riscv_new/tests/webtbs/tw11563.pp8
6 files changed, 147 insertions, 116 deletions
diff --git a/riscv_new/compiler/aggas.pas b/riscv_new/compiler/aggas.pas
index b84f0d505d..4478bc3dc4 100644
--- a/riscv_new/compiler/aggas.pas
+++ b/riscv_new/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',
diff --git a/riscv_new/compiler/riscv/cgrv.pas b/riscv_new/compiler/riscv/cgrv.pas
index 0cbfd753c0..5a616925bf 100644
--- a/riscv_new/compiler/riscv/cgrv.pas
+++ b/riscv_new/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);
diff --git a/riscv_new/compiler/riscv64/cgcpu.pas b/riscv_new/compiler/riscv64/cgcpu.pas
index 6f028d5448..554107ab91 100644
--- a/riscv_new/compiler/riscv64/cgcpu.pas
+++ b/riscv_new/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;
diff --git a/riscv_new/rtl/inc/systemh.inc b/riscv_new/rtl/inc/systemh.inc
index 4d9f991023..1ff1432c82 100644
--- a/riscv_new/rtl/inc/systemh.inc
+++ b/riscv_new/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}
diff --git a/riscv_new/tests/tbs/tb0627b.pp b/riscv_new/tests/tbs/tb0627b.pp
index 5475cbf8fe..d1682ef1b2 100644
--- a/riscv_new/tests/tbs/tb0627b.pp
+++ b/riscv_new/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}
diff --git a/riscv_new/tests/webtbs/tw11563.pp b/riscv_new/tests/webtbs/tw11563.pp
index 1d03b348de..b122d1148b 100644
--- a/riscv_new/tests/webtbs/tw11563.pp
+++ b/riscv_new/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);