Просмотр исходного кода

* fixed overflow checking on AArch64 for signed multiplications with zero
(mantis #29912)

git-svn-id: trunk@33380 -

Jonas Maebe 9 лет назад
Родитель
Сommit
322493c195
3 измененных файлов с 35 добавлено и 8 удалено
  1. 1 0
      .gitattributes
  2. 13 8
      compiler/aarch64/cgcpu.pas
  3. 21 0
      tests/webtbs/tw29912.pp

+ 1 - 0
.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

+ 13 - 8
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:

+ 21 - 0
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.
+