Browse Source

* use SarInt64 to optimize 64 bit divs on 32 bit platforms, resolves #20998

git-svn-id: trunk@19968 -
florian 13 years ago
parent
commit
4765728fc4
5 changed files with 63 additions and 25 deletions
  1. 1 0
      .gitattributes
  2. 40 24
      compiler/nmat.pas
  3. 3 1
      rtl/inc/generic.inc
  4. 1 0
      rtl/inc/systemh.inc
  5. 18 0
      tests/webtbs/tw20998.pp

+ 1 - 0
.gitattributes

@@ -12066,6 +12066,7 @@ tests/webtbs/tw20889.pp svneol=native#text/pascal
 tests/webtbs/tw20962.pp svneol=native#text/plain
 tests/webtbs/tw20995a.pp svneol=native#text/pascal
 tests/webtbs/tw20995b.pp svneol=native#text/pascal
+tests/webtbs/tw20998.pp svneol=native#text/pascal
 tests/webtbs/tw2109.pp svneol=native#text/plain
 tests/webtbs/tw2110.pp svneol=native#text/plain
 tests/webtbs/tw2128.pp svneol=native#text/plain

+ 40 - 24
compiler/nmat.pas

@@ -102,7 +102,7 @@ implementation
       defutil,
       htypechk,pass_1,
       cgbase,
-      ncon,ncnv,ncal,nadd,nld,nbas,nflw,
+      ncon,ncnv,ncal,nadd,nld,nbas,nflw,ninl,
       nutils;
 
 {****************************************************************************
@@ -419,47 +419,63 @@ implementation
 
     function tmoddivnode.firstoptimize: tnode;
       var
-        power{,shiftval} : longint;
+        power,shiftval : longint;
         newtype: tnodetype;
+        statements : tstatementnode;
+        temp : ttempcreatenode;
       begin
         result := nil;
         { divide/mod a number by a constant which is a power of 2? }
-        if (cs_opt_peephole in current_settings.optimizerswitches) and
-           (right.nodetype = ordconstn) and
-{           ((nodetype = divn) or
-            not is_signed(resultdef)) and}
-           (not is_signed(resultdef)) and
+        if (right.nodetype = ordconstn) and
+{$ifdef cpu64bitalu}
+          { for 64 bit, we leave the optimization to the cg }
+            (not is_signed(resultdef)) and
+{$else cpu64bitalu}
+           ((nodetype=divn) and (is_64bit(resultdef)) or
+            not is_signed(resultdef)) and
+{$endif cpu64bitalu}
            ispowerof2(tordconstnode(right).value,power) then
           begin
-            if nodetype = divn then
+            if nodetype=divn then
               begin
-(*
                 if is_signed(resultdef) then
                   begin
                     if is_64bitint(left.resultdef) then
                       if not (cs_opt_size in current_settings.optimizerswitches) then
-                        shiftval := 63
+                        shiftval:=63
                       else
                         { the shift code is a lot bigger than the call to }
                         { the divide helper                               }
                         exit
                     else
-                      shiftval := 31;
-                    { we reuse left twice, so create once a copy of it     }
-                    { !!! if left is a call is -> call gets executed twice }
-                    left := caddnode.create(addn,left,
-                      caddnode.create(andn,
-                        cshlshrnode.create(sarn,left.getcopy,
-                          cordconstnode.create(shiftval,sinttype,false)),
-                        cordconstnode.create(tordconstnode(right).value-1,
-                          right.resultdef,false)));
-                    newtype := sarn;
+                      shiftval:=31;
+
+                    result:=internalstatements(statements);
+                    temp:=ctempcreatenode.create(left.resultdef,left.resultdef.size,tt_persistent,true);
+                    addstatement(statements,temp);
+                    addstatement(statements,cassignmentnode.create(ctemprefnode.create(temp),
+                     left));
+                    left:=nil;
+
+                    addstatement(statements,ccallnode.createintern('fpc_sarint64',
+                      ccallparanode.create(cordconstnode.create(power,u8inttype,false),
+                      ccallparanode.create(caddnode.create(addn,ctemprefnode.create(temp),
+                        caddnode.create(andn,
+                          ccallnode.createintern('fpc_sarint64',
+                            ccallparanode.create(cordconstnode.create(shiftval,u8inttype,false),
+                            ccallparanode.create(ctemprefnode.create(temp),nil))
+                          ),
+                          cordconstnode.create(tordconstnode(right).value-1,
+                            right.resultdef,false)
+                        )),nil
+                      )))
+                    );
                   end
                 else
-*)
-                  newtype := shrn;
-                tordconstnode(right).value := power;
-                result := cshlshrnode.create(newtype,left,right)
+                  begin
+                    tordconstnode(right).value:=power;
+                    result:=cshlshrnode.create(shrn,left,right)
+                  end;
               end
             else
               begin

+ 3 - 1
rtl/inc/generic.inc

@@ -2296,10 +2296,12 @@ function SarLongint(Const AValue : Longint;const Shift : Byte): Longint;
 
 {$ifndef FPC_HAS_INTERNAL_SAR_QWORD}
 {$ifndef FPC_SYSTEM_HAS_SAR_QWORD}
-function SarInt64(Const AValue : Int64;const Shift : Byte): Int64;
+function fpc_SarInt64(Const AValue : Int64;const Shift : Byte): Int64; [Public,Alias:'FPC_SARINT64']; compilerproc;
   begin
     Result:=int64(qword(qword(qword(AValue) shr (Shift and 63)) or (qword(int64(qword(0-qword(qword(AValue) shr 63)) and qword(int64(0-(ord((Shift and 63)<>0){ and 1}))))) shl (64-(Shift and 63)))));
   end;
+
+function SarInt64(Const AValue : Int64;const Shift : Byte = 1): Int64; [external name 'FPC_SARINT64'];
 {$endif FPC_HAS_INTERNAL_SAR_QWORD}
 {$endif FPC_SYSTEM_HAS_SAR_QWORD}
 

+ 1 - 0
rtl/inc/systemh.inc

@@ -783,6 +783,7 @@ function SarLongint(Const AValue : Longint;const Shift : Byte = 1): Longint;
 function SarInt64(Const AValue : Int64): Int64;[internproc:fpc_in_sar_x];
 function SarInt64(Const AValue : Int64;Shift : Byte): Int64;[internproc:fpc_in_sar_x_y];
 {$else FPC_HAS_INTERNAL_SAR_QWORD}
+function fpc_SarInt64(Const AValue : Int64;const Shift : Byte): Int64;compilerproc;
 function SarInt64(Const AValue : Int64;const Shift : Byte = 1): Int64;
 {$endif FPC_HAS_INTERNAL_SAR_QWORD}
 

+ 18 - 0
tests/webtbs/tw20998.pp

@@ -0,0 +1,18 @@
+var
+  i : int64;
+
+begin
+  i:=6400;
+  i:=i div 64;
+  if i<>100 then
+    halt(1);
+  i:=6500;
+  i:=i div 65;
+  if i<>100 then
+    halt(1);
+  i:=-6400;
+  i:=i div 64;
+  if i<>-100 then
+    halt(1);
+  writeln('ok');
+end.