Explorar el Código

* Moved procedures calculating "magic" numbers for division by constants from powerpc64/cgcpu.pas to cgutils.pas, so they can be reused for all targets.
* "Shift" parameter for signed calculation changed from aint to byte, since it only holds values up to 63. It is consistent with unsigned routine.

git-svn-id: trunk@27883 -

sergei hace 11 años
padre
commit
90d2009a31
Se han modificado 2 ficheros con 103 adiciones y 103 borrados
  1. 99 0
      compiler/cgutils.pas
  2. 4 103
      compiler/powerpc64/cgcpu.pas

+ 99 - 0
compiler/cgutils.pas

@@ -176,6 +176,12 @@ unit cgutils;
     { returns r with the given alignment }
     function setalignment(const r : treference;b : byte) : treference;
 
+    { Helper function which calculate "magic" values for replacement of division
+      by constant operation by multiplication. See the "PowerPC compiler developer
+      manual" for more information.
+      N is number of bits to handle, functionality tested for values 32 and 64. }
+    procedure calc_divconst_magic_signed(N: byte; d: aInt; out magic_m: aInt; out magic_s: byte);
+    procedure calc_divconst_magic_unsigned(N: byte; d: aWord; out magic_m: aWord; out magic_add: boolean; out magic_shift: byte);
 
 implementation
 
@@ -328,5 +334,98 @@ uses
       end;
 
 
+{$push}
+{$r-,q-}
+    procedure calc_divconst_magic_signed(N: byte; d: aInt; out magic_m: aInt; out magic_s: byte);
+      var
+        p: aInt;
+        ad,anc,delta,q1,r1,q2,r2,t: aWord;
+        two_N_minus_1: aWord;
+      begin
+        assert((d<-1) or (d>1));
+        two_N_minus_1:=aWord(1) shl (N-1);
+
+        ad:=abs(d);
+        t:=two_N_minus_1+(aWord(d) shr (N-1));
+        anc:=t-1-t mod ad;               { absolute value of nc }
+        p:=(N-1);                        { initialize p }
+        q1:=two_N_minus_1 div anc;       { initialize q1 = 2**p/abs(nc) }
+        r1:=two_N_minus_1-q1*anc;        { initialize r1 = rem(2**p,abs(nc)) }
+        q2:=two_N_minus_1 div ad;        { initialize q2 = 2**p/abs(d) }
+        r2:=two_N_minus_1-q2*ad;         { initialize r2 = rem(2**p,abs(d)) }
+        repeat
+          inc(p);
+          q1:=2*q1;           { update q1 = 2**p/abs(nc) }
+          r1:=2*r1;           { update r1 = rem(2**p/abs(nc)) }
+          if (r1>=anc) then   { must be unsigned comparison }
+            begin
+              inc(q1);
+              dec(r1,anc);
+            end;
+          q2:=2*q2;           { update q2 = 2p/abs(d) }
+          r2:=2*r2;           { update r2 = rem(2p/abs(d)) }
+          if (r2>=ad) then    { must be unsigned comparison }
+            begin
+              inc(q2);
+              dec(r2,ad);
+            end;
+          delta:=ad-r2;
+        until not ((q1<delta) or ((q1=delta) and (r1=0)));
+        magic_m:=q2+1;
+        if (d<0) then
+          magic_m:=-magic_m;  { resulting magic number }
+        magic_s:=p-N;         { resulting shift }
+      end;
+
+
+    procedure calc_divconst_magic_unsigned(N: byte; d: aWord; out magic_m: aWord; out magic_add: boolean; out magic_shift: byte);
+      var
+        p: aInt;
+        nc,delta,q1,r1,q2,r2,two_N_minus_1 : aWord;
+      begin
+        two_N_minus_1:=aWord(1) shl (N-1);
+        magic_add:=false;
+{$push}
+{$warnings off }
+        nc:=aWord(-1)-(-d) mod d;
+{$pop}
+        p:=N-1;                       { initialize p }
+        q1:=two_N_minus_1 div nc;     { initialize q1 = 2**p/nc }
+        r1:=two_N_minus_1-q1*nc;      { initialize r1 = rem(2**p,nc) }
+        q2:=(two_N_minus_1-1) div d;  { initialize q2 = (2**p-1)/d }
+        r2:=(two_N_minus_1-1)-q2*d;   { initialize r2 = rem((2**p-1),d) }
+        repeat
+          inc(p);
+          if (r1>=(nc-r1)) then
+            begin
+              q1:=2*q1+1;    { update q1 }
+              r1:=2*r1-nc;   { update r1 }
+            end
+          else
+            begin
+              q1:=2*q1;      { update q1 }
+              r1:=2*r1;      { update r1 }
+            end;
+          if ((r2+1)>=(d-r2)) then
+            begin
+              if (q2>=(two_N_minus_1-1)) then
+                magic_add:=true;
+              q2:=2*q2+1;    { update q2 }
+              r2:=2*r2+1-d;  { update r2 }
+            end
+          else
+            begin
+              if (q2>=two_N_minus_1) then
+                magic_add:=true;
+              q2:=2*q2;      { update q2 }
+              r2:=2*r2+1;    { update r2 }
+            end;
+          delta:=d-1-r2;
+        until not ((p<(2*N)) and ((q1<delta) or ((q1=delta) and (r1=0))));
+        magic_m:=q2+1;        { resulting magic number }
+        magic_shift:=p-N;     { resulting shift }
+      end;
+{$pop}
+
 end.
 

+ 4 - 103
compiler/powerpc64/cgcpu.pas

@@ -155,105 +155,6 @@ begin
   end;
 end;
 
-{$push}
-{$r-}
-{$q-}
-{ helper function which calculate "magic" values for replacement of unsigned
- division by constant operation by multiplication. See the PowerPC compiler
- developer manual for more information }
-procedure getmagic_unsignedN(const N : byte; const d : aWord;
-  out magic_m : aWord; out magic_add : boolean; out magic_shift : byte);
-var
-    p : aInt;
-    nc, delta, q1, r1, q2, r2, two_N_minus_1 : aWord;
-begin
-  assert(d > 0);
-
-  two_N_minus_1 := aWord(1) shl (N-1);
-
-  magic_add := false;
-{$push}
-{$warnings off }
-  nc := aWord(-1) - (-d) mod d;
-{$pop}
-  p := N-1; { initialize p }
-  q1 := two_N_minus_1 div nc; { initialize q1 = 2p/nc }
-  r1 := two_N_minus_1 - q1*nc; { initialize r1 = rem(2p,nc) }
-  q2 := (two_N_minus_1-1) div d; { initialize q2 = (2p-1)/d }
-  r2 := (two_N_minus_1-1) - q2*d; { initialize r2 = rem((2p-1),d) }
-  repeat
-    inc(p);
-    if (r1 >= (nc - r1)) then begin
-      q1 := 2 * q1 + 1; { update q1 }
-      r1 := 2*r1 - nc; { update r1 }
-    end else begin
-      q1 := 2*q1; { update q1 }
-      r1 := 2*r1; { update r1 }
-    end;
-    if ((r2 + 1) >= (d - r2)) then begin
-      if (q2 >= (two_N_minus_1-1)) then
-        magic_add := true;
-      q2 := 2*q2 + 1; { update q2 }
-      r2 := 2*r2 + 1 - d; { update r2 }
-    end else begin
-      if (q2 >= two_N_minus_1) then
-        magic_add := true;
-      q2 := 2*q2; { update q2 }
-      r2 := 2*r2 + 1; { update r2 }
-    end;
-    delta := d - 1 - r2;
-  until not ((p < (2*N)) and ((q1 < delta) or ((q1 = delta) and (r1 = 0))));
-  magic_m := q2 + 1; { resulting magic number }
-  magic_shift := p - N; { resulting shift }
-end;
-
-{ helper function which calculate "magic" values for replacement of signed
- division by constant operation by multiplication. See the PowerPC compiler
- developer manual for more information }
-procedure getmagic_signedN(const N : byte; const d : aInt;
-  out magic_m : aInt; out magic_s : aInt);
-var
-  p : aInt;
-  ad, anc, delta, q1, r1, q2, r2, t : aWord;
-  two_N_minus_1 : aWord;
-
-begin
-  assert((d < -1) or (d > 1));
-
-  two_N_minus_1 := aWord(1) shl (N-1);
-
-  ad := abs(d);
-  t := two_N_minus_1 + (aWord(d) shr (N-1));
-  anc := t - 1 - t mod ad; { absolute value of nc }
-  p := (N-1); { initialize p }
-  q1 := two_N_minus_1 div anc; { initialize q1 = 2p/abs(nc) }
-  r1 := two_N_minus_1 - q1*anc; { initialize r1 = rem(2p,abs(nc)) }
-  q2 := two_N_minus_1 div ad; { initialize q2 = 2p/abs(d) }
-  r2 := two_N_minus_1 - q2*ad; { initialize r2 = rem(2p,abs(d)) }
-  repeat
-    inc(p);
-    q1 := 2*q1; { update q1 = 2p/abs(nc) }
-    r1 := 2*r1; { update r1 = rem(2p/abs(nc)) }
-    if (r1 >= anc) then begin { must be unsigned comparison }
-      inc(q1);
-      dec(r1, anc);
-    end;
-    q2 := 2*q2; { update q2 = 2p/abs(d) }
-    r2 := 2*r2; { update r2 = rem(2p/abs(d)) }
-    if (r2 >= ad) then begin { must be unsigned comparison }
-      inc(q2);
-      dec(r2, ad);
-    end;
-    delta := ad - r2;
-  until not ((q1 < delta) or ((q1 = delta) and (r1 = 0)));
-  magic_m := q2 + 1;
-  if (d < 0) then begin
-    magic_m := -magic_m; { resulting magic number }
-  end;
-  magic_s := p - N; { resulting shift }
-end;
-{$pop}
-
 { finds positive and negative powers of two of the given value, returning the
  power and whether it's a negative power or not in addition to the actual result
  of the function }
@@ -710,7 +611,7 @@ var
   const
     negops : array[boolean] of tasmop = (A_NEG, A_NEGO);
   var
-    magic, shift : int64;
+    magic : int64;
     u_magic : qword;
     u_shift : byte;
     u_add : boolean;
@@ -742,7 +643,7 @@ var
       { from "The PowerPC Compiler Writer's Guide" pg. 53ff      }
       divreg := getintregister(list, OS_INT);
       if (signed) then begin
-        getmagic_signedN(sizeof(aInt)*8, a, magic, shift);
+        calc_divconst_magic_signed(sizeof(aInt)*8, a, magic, u_shift);
         { load magic value }
         a_load_const_reg(list, OS_INT, magic, divreg);
         { multiply }
@@ -754,7 +655,7 @@ var
           a_op_reg_reg_reg(list, OP_SUB, OS_INT, src, dst, dst);
         end;
         { shift shift places to the right (arithmetic) }
-        a_op_const_reg_reg(list, OP_SAR, OS_INT, shift, dst, dst);
+        a_op_const_reg_reg(list, OP_SAR, OS_INT, u_shift, dst, dst);
         { extract and add sign bit }
         if (a >= 0) then begin
           a_op_const_reg_reg(list, OP_SHR, OS_INT, 63, src, divreg);
@@ -763,7 +664,7 @@ var
         end;
         a_op_reg_reg_reg(list, OP_ADD, OS_INT, dst, divreg, dst);
       end else begin
-        getmagic_unsignedN(sizeof(aWord)*8, a, u_magic, u_add, u_shift);
+        calc_divconst_magic_unsigned(sizeof(aWord)*8, a, u_magic, u_add, u_shift);
         { load magic in divreg }
         a_load_const_reg(list, OS_INT, aint(u_magic), divreg);
         list.concat(taicpu.op_reg_reg_reg(A_MULHDU, dst, src, divreg));