Sfoglia il codice sorgente

* unified code to remove unnecessary type casts to support also removals of type conversions between smaller ints
* get rid of unnecessary 8->16 Bit type conversions on 8 Bit CPUs, resolves issue #27839

git-svn-id: trunk@30726 -

florian 10 anni fa
parent
commit
01cbf00455
2 ha cambiato i file con 53 aggiunte e 39 eliminazioni
  1. 51 39
      compiler/ncnv.pas
  2. 2 0
      compiler/symconst.pas

+ 51 - 39
compiler/ncnv.pas

@@ -2480,43 +2480,47 @@ implementation
   this applies is powerpc64
 }
 {$ifndef CPUNO32BITOPS}
-    { checks whether we can safely remove 64 bit typeconversions
+    { checks whether we can safely remove typeconversions to bigger types
       in case range and overflow checking are off, and in case
       the result of this node tree is downcasted again to a
-      8/16/32 bit value afterwards
+      smaller type value afterwards,
+
+      the smaller types being allowed are described by validints, ordinal constants must fit into l..h
 
       We do this on 64 bit CPUs as well, they benefit from it as well }
-    function checkremove64bittypeconvs(n: tnode; out gotsint: boolean): boolean;
+
+    function checkremovebiginttypeconvs(n: tnode; out gotsint: boolean;validints : tordtypeset;l,h : Tconstexprint): boolean;
       var
         gotdivmod: boolean;
 
-      { checks whether a node is either an u32bit, or originally }
-      { was one but was implicitly converted to s64bit           }
-      function wasoriginallyint32(n: tnode): boolean;
+      { checks whether a node has an accepted resultdef, or originally
+        had one but was implicitly converted to s64bit                 }
+      function wasoriginallysmallerint(n: tnode): boolean;
         begin
           if (n.resultdef.typ<>orddef) then
             exit(false);
-          if (torddef(n.resultdef).ordtype in [s8bit,u8bit,s16bit,u16bit,s32bit,u32bit]) then
+          if (torddef(n.resultdef).ordtype in validints) then
             begin
-              if (torddef(n.resultdef).ordtype in [s8bit,s16bit,s32bit]) then
+              if is_signed(n.resultdef) then
                 gotsint:=true;
               exit(true);
             end;
-          if (torddef(n.resultdef).ordtype in [u64bit,s64bit]) and
+          { type conv to a bigger int, we do not like to use? }
+          if (torddef(n.resultdef).ordtype in ([s8bit,u8bit,s16bit,u16bit,s32bit,u32bit,s64bit,u64bit]-validints)) and
              { nf_explicit is also set for explicitly typecasted }
              { ordconstn's                                       }
              ([nf_internal,nf_explicit]*n.flags=[]) and
-             { either a typeconversion node coming from u32bit }
+             { either a typeconversion node coming from a smaller type }
              (((n.nodetype=typeconvn) and
                (ttypeconvnode(n).left.resultdef.typ=orddef) and
-               (torddef(ttypeconvnode(n).left.resultdef).ordtype in [s8bit,u8bit,s16bit,u16bit,s32bit,u32bit])) or
-             { or an ordconstnode which was/is a valid cardinal }
+               (torddef(ttypeconvnode(n).left.resultdef).ordtype in validints)) or
+             { or an ordconstnode which has a smaller type}
               ((n.nodetype=ordconstn) and
-               (tordconstnode(n).value>=int64(low(longint))) and
-               (tordconstnode(n).value<=high(cardinal)))) then
+               (tordconstnode(n).value>=l) and
+               (tordconstnode(n).value<=h))) then
             begin
               if ((n.nodetype=typeconvn) and
-                  (torddef(ttypeconvnode(n).left.resultdef).ordtype in [s8bit,s16bit,s32bit])) or
+                  is_signed(ttypeconvnode(n).left.resultdef)) or
                  ((n.nodetype=ordconstn) and
                   (tordconstnode(n).value<0)) then
                 gotsint:=true;
@@ -2526,10 +2530,10 @@ implementation
         end;
 
 
-      function docheckremove64bittypeconvs(n: tnode): boolean;
+      function docheckremoveinttypeconvs(n: tnode): boolean;
         begin
           result:=false;
-          if wasoriginallyint32(n) then
+          if wasoriginallysmallerint(n) then
             exit(true);
           case n.nodetype of
             subn,orn,xorn:
@@ -2538,18 +2542,18 @@ implementation
                 if n.nodetype=subn then
                   gotsint:=true;
                 result:=
-                  docheckremove64bittypeconvs(tbinarynode(n).left) and
-                  docheckremove64bittypeconvs(tbinarynode(n).right);
+                  docheckremoveinttypeconvs(tbinarynode(n).left) and
+                  docheckremoveinttypeconvs(tbinarynode(n).right);
               end;
             addn,muln,divn,modn,andn:
               begin
                 if n.nodetype in [divn,modn] then
                   gotdivmod:=true;
                 result:=
-                  (docheckremove64bittypeconvs(tbinarynode(n).left) and
-                   docheckremove64bittypeconvs(tbinarynode(n).right)) or
-                  ((n.nodetype=andn) and wasoriginallyint32(tbinarynode(n).left)) or
-                  ((n.nodetype=andn) and wasoriginallyint32(tbinarynode(n).right));
+                  (docheckremoveinttypeconvs(tbinarynode(n).left) and
+                   docheckremoveinttypeconvs(tbinarynode(n).right)) or
+                  ((n.nodetype=andn) and wasoriginallysmallerint(tbinarynode(n).left)) or
+                  ((n.nodetype=andn) and wasoriginallysmallerint(tbinarynode(n).right));
               end;
           end;
         end;
@@ -2558,12 +2562,13 @@ implementation
         gotdivmod:=false;
         gotsint:=false;
         result:=
-          docheckremove64bittypeconvs(n) and
+          docheckremoveinttypeconvs(n) and
           not(gotdivmod and gotsint);
       end;
 
 
-    procedure doremove64bittypeconvs(var n: tnode; todef: tdef; forceunsigned: boolean);
+    { remove int type conversions and set the result to the given type }
+    procedure doremoveinttypeconvs(var n: tnode; todef: tdef; forceunsigned: boolean; signedtype,unsignedtype : tdef);
       begin
         case n.nodetype of
           subn,addn,muln,divn,modn,xorn,andn,orn:
@@ -2572,15 +2577,15 @@ implementation
               if not forceunsigned and
                  is_signed(n.resultdef) then
                 begin
-                  doremove64bittypeconvs(tbinarynode(n).left,s32inttype,false);
-                  doremove64bittypeconvs(tbinarynode(n).right,s32inttype,false);
-                  n.resultdef:=s32inttype
+                  doremoveinttypeconvs(tbinarynode(n).left,signedtype,false,signedtype,unsignedtype);
+                  doremoveinttypeconvs(tbinarynode(n).right,signedtype,false,signedtype,unsignedtype);
+                  n.resultdef:=signedtype;
                 end
               else
                 begin
-                  doremove64bittypeconvs(tbinarynode(n).left,u32inttype,forceunsigned);
-                  doremove64bittypeconvs(tbinarynode(n).right,u32inttype,forceunsigned);
-                  n.resultdef:=u32inttype
+                  doremoveinttypeconvs(tbinarynode(n).left,unsignedtype,forceunsigned,signedtype,unsignedtype);
+                  doremoveinttypeconvs(tbinarynode(n).right,unsignedtype,forceunsigned,signedtype,unsignedtype);
+                  n.resultdef:=unsignedtype;
                 end;
               //if ((n.nodetype=andn) and (tbinarynode(n).left.nodetype=ordconstn) and
               //    ((tordconstnode(tbinarynode(n).left).value and $7fffffff)=tordconstnode(tbinarynode(n).left).value)
@@ -2812,15 +2817,22 @@ implementation
           tc_int_2_int:
             begin
               if (localswitches * [cs_check_range,cs_check_overflow] = []) and
-                 (resultdef.typ in [pointerdef,orddef,enumdef]) and
-                 (resultdef.size <= 4) and
-                 is_64bitint(left.resultdef) and
-                 (left.nodetype in [subn,addn,muln,divn,modn,xorn,andn,orn]) and
-                 checkremove64bittypeconvs(left,foundsint) then
+                 (resultdef.typ in [pointerdef,orddef,enumdef]) then
                 begin
-                  { avoid unnecessary widening of intermediary calculations }
-                  { to 64 bit                                               }
-                  doremove64bittypeconvs(left,generrordef,not foundsint);
+                  { avoid unnecessary widening of intermediary calculations
+                    to 64 bit                                               }
+                  if (resultdef.size <= 4) and
+                    is_64bitint(left.resultdef) and
+                    (left.nodetype in [subn,addn,muln,divn,modn,xorn,andn,orn]) and
+                    checkremovebiginttypeconvs(left,foundsint,[s8bit,u8bit,s16bit,u16bit,s32bit,u32bit],int64(low(longint)),high(cardinal)) then
+                    doremoveinttypeconvs(left,generrordef,not foundsint,s32inttype,u32inttype);
+{$if defined(cpu8bitalu)}
+                 if (resultdef.size<left.resultdef.size) and
+                  is_integer(left.resultdef) and
+                  (left.nodetype in [subn,addn,muln,divn,modn,xorn,andn,orn]) and
+                  checkremovebiginttypeconvs(left,foundsint,[s8bit,u8bit],int64(low(shortint)),high(byte)) then
+                    doremoveinttypeconvs(left,generrordef,not foundsint,s8inttype,u8inttype);
+{$endif defined(cpu8bitalu)}
                 end;
             end;
         end;

+ 2 - 0
compiler/symconst.pas

@@ -235,6 +235,8 @@ type
     uchar,uwidechar,scurrency
   );
 
+  tordtypeset = set of tordtype;
+
   { string types }
   tstringtype = (
     st_shortstring,