From 322493c19561295b6c148670ab80d8f99087c0e9 Mon Sep 17 00:00:00 2001 From: Jonas Maebe Date: Tue, 29 Mar 2016 09:50:42 +0000 Subject: [PATCH] * fixed overflow checking on AArch64 for signed multiplications with zero (mantis #29912) git-svn-id: trunk@33380 - --- .gitattributes | 1 + compiler/aarch64/cgcpu.pas | 21 +++++++++++++-------- tests/webtbs/tw29912.pp | 21 +++++++++++++++++++++ 3 files changed, 35 insertions(+), 8 deletions(-) create mode 100644 tests/webtbs/tw29912.pp diff --git a/.gitattributes b/.gitattributes index 0244088af6..7538527401 100644 --- a/.gitattributes +++ b/.gitattributes @@ -14993,6 +14993,7 @@ tests/webtbs/tw29792.pp svneol=native#text/pascal tests/webtbs/tw2983.pp svneol=native#text/plain tests/webtbs/tw2984.pp svneol=native#text/plain tests/webtbs/tw29893.pp svneol=native#text/pascal +tests/webtbs/tw29912.pp svneol=native#text/plain tests/webtbs/tw2998.pp svneol=native#text/plain tests/webtbs/tw2999.pp svneol=native#text/plain tests/webtbs/tw3004.pp svneol=native#text/plain diff --git a/compiler/aarch64/cgcpu.pas b/compiler/aarch64/cgcpu.pas index b2cae937be..d8e41d6cbc 100644 --- a/compiler/aarch64/cgcpu.pas +++ b/compiler/aarch64/cgcpu.pas @@ -1340,7 +1340,7 @@ implementation procedure tcgaarch64.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: topcg; size: tcgsize; src1, src2, dst: tregister; setflags : boolean; var ovloc : tlocation); var - tmpreg1: tregister; + tmpreg1, tmpreg2: tregister; begin ovloc.loc:=LOC_VOID; { overflow can only occur with 64 bit calculations on 64 bit cpus } @@ -1375,17 +1375,22 @@ implementation end; OP_IMUL: begin - { check whether the sign bit of the (128 bit) result is the - same as "sign bit of src1" xor "signbit of src2" (if so, no - overflow and the xor-product of all sign bits is 0) } + { check whether the upper 64 bits of the 128 bit multiplication + result have the same value as the replicated sign bit of the + lower 64 bits } tmpreg1:=getintregister(list,OS_64); list.concat(taicpu.op_reg_reg_reg(A_SMULH,tmpreg1,src2,src1)); - list.concat(taicpu.op_reg_reg_reg(A_EOR,tmpreg1,tmpreg1,src1)); - list.concat(taicpu.op_reg_reg_reg(A_EOR,tmpreg1,tmpreg1,src2)); - list.concat(taicpu.op_reg_const(A_TST,tmpreg1,$80000000)); + { calculate lower 64 bits (afterwards, because dst may be + equal to src1 or src2) } + a_op_reg_reg_reg(list,op,size,src1,src2,dst); + { replicate sign bit } + tmpreg2:=getintregister(list,OS_64); + a_op_const_reg_reg(list,OP_SAR,OS_S64,63,dst,tmpreg2); + list.concat(taicpu.op_reg_reg(A_CMP,tmpreg1,tmpreg2)); ovloc.loc:=LOC_FLAGS; ovloc.resflags:=F_NE; - { still have to perform the actual multiplication } + { finished } + exit; end; OP_IDIV, OP_DIV: diff --git a/tests/webtbs/tw29912.pp b/tests/webtbs/tw29912.pp new file mode 100644 index 0000000000..af6b0fdcee --- /dev/null +++ b/tests/webtbs/tw29912.pp @@ -0,0 +1,21 @@ +program Project1; + +{$mode objfpc}{$H+} +{$R+,Q+,S+,T+} + +var + x,y,z:integer; +begin + x:=0; + z:=0; + // all ok + y:=Int64(x-1); + writeln(y); + // all ok + y:=Int64(z); + writeln(y); + // arithmetic overflow + y:=Int64(x-1)*Int64(z); + writeln(y); +end. +