Browse Source

+ optimization type converted (modulo) divisions as well by removing up/down converting but,
insert a test and separate code path for -1 if needed

git-svn-id: trunk@47521 -

florian 4 years ago
parent
commit
ea11517d27
1 changed files with 55 additions and 4 deletions
  1. 55 4
      compiler/ncnv.pas

+ 55 - 4
compiler/ncnv.pas

@@ -322,7 +322,7 @@ implementation
       globtype,systems,constexp,compinnr,
       cutils,verbose,globals,widestr,ppu,
       symconst,symdef,symsym,symcpu,symtable,
-      ncon,ncal,nset,nadd,nmem,nmat,nbas,nutils,ninl,
+      ncon,ncal,nset,nadd,nmem,nmat,nbas,nutils,ninl,nflw,
       cgbase,procinfo,
       htypechk,blockutl,pass_1,cpuinfo;
 
@@ -2872,6 +2872,9 @@ implementation
 
     function checkremovebiginttypeconvs(n: tnode; out gotsint: boolean;validints : tordtypeset;const l,h : Tconstexprint): boolean;
       var
+        gotminus1,
+        gotsigned,
+        gotunsigned,
         gotdivmod: boolean;
 
       { checks whether a node has an accepted resultdef, or originally
@@ -2880,6 +2883,13 @@ implementation
         begin
           if (n.resultdef.typ<>orddef) then
             exit(false);
+          gotsigned:=gotsigned or is_signed(n.resultdef);
+          gotunsigned:=gotunsigned or not(is_signed(n.resultdef));
+          { actually, we should only check right (denominator) nodes here, but
+            setting it always is a safe approximation }
+          if ((n.nodetype=ordconstn) and
+            (tordconstnode(n).value=-1)) then
+            gotminus1:=true;
           if (torddef(n.resultdef).ordtype in validints) then
             begin
               if is_signed(n.resultdef) then
@@ -2904,7 +2914,12 @@ implementation
                   is_signed(ttypeconvnode(n).left.resultdef)) or
                  ((n.nodetype=ordconstn) and
                   (tordconstnode(n).value<0)) then
-                gotsint:=true;
+                begin
+                  gotsint:=true;
+                  gotsigned:=true;
+                end
+              else
+                gotunsigned:=true;
               exit(true);
             end;
           result:=false;
@@ -2938,7 +2953,10 @@ implementation
                   gotdivmod:=true;
                 result:=
                   (docheckremoveinttypeconvs(tbinarynode(n).left) and
-                   docheckremoveinttypeconvs(tbinarynode(n).right)) or
+                   docheckremoveinttypeconvs(tbinarynode(n).right) and
+
+                   (not(n.nodetype in [modn,divn]) or (not(gotminus1)))
+                  ) or
                   { in case of div/mod, the result of that division/modulo can
                     usually be different in 32 and 64 bit }
                   (not gotdivmod and
@@ -2953,14 +2971,22 @@ implementation
       begin { checkremove64bittypeconvs }
         gotdivmod:=false;
         gotsint:=false;
+        gotminus1:=false;
+        gotsigned:=false;
+        gotunsigned:=false;
         result:=
           docheckremoveinttypeconvs(n) and
-          not(gotdivmod and gotsint);
+          (not(gotdivmod) or (gotsigned xor gotunsigned));
       end;
 
 
     { remove int type conversions and set the result to the given type }
     procedure doremoveinttypeconvs(var n: tnode; todef: tdef; forceunsigned: boolean; signedtype,unsignedtype : tdef);
+      var
+        newblock: tblocknode;
+        newstatements: tstatementnode;
+        originaldivtree: tnode;
+        tempnode: ttempcreatenode;
       begin
         case n.nodetype of
           subn,addn,muln,divn,modn,xorn,andn,orn:
@@ -2969,9 +2995,34 @@ implementation
               if not forceunsigned and
                  is_signed(n.resultdef) then
                 begin
+                  originaldivtree:=nil;
+                  if n.nodetype in [divn,modn] then
+                    originaldivtree:=n.getcopy;
                   doremoveinttypeconvs(tbinarynode(n).left,signedtype,false,signedtype,unsignedtype);
                   doremoveinttypeconvs(tbinarynode(n).right,signedtype,false,signedtype,unsignedtype);
                   n.resultdef:=signedtype;
+                  if n.nodetype in [divn,modn] then
+                    begin
+                      newblock:=internalstatements(newstatements);
+                      tempnode:=ctempcreatenode.create(n.resultdef,n.resultdef.size,tt_persistent,true);
+                      addstatement(newstatements,tempnode);
+                      addstatement(newstatements,cifnode.create_internal(
+                        caddnode.create_internal(equaln,tbinarynode(n).right.getcopy,cordconstnode.create(-1,n.resultdef,false)),
+                          cassignmentnode.create_internal(
+                            ctemprefnode.create(tempnode),
+                            cmoddivnode.create(n.nodetype,tbinarynode(originaldivtree).left.getcopy,cordconstnode.create(-1,tbinarynode(originaldivtree).right.resultdef,false))
+                          ),
+                          cassignmentnode.create_internal(
+                            ctemprefnode.create(tempnode),n
+                          )
+                        )
+                      );
+                      addstatement(newstatements,ctempdeletenode.create_normal_temp(tempnode));
+                      addstatement(newstatements,ctemprefnode.create(tempnode));
+                      n:=newblock;
+                      do_typecheckpass(n);
+                      originaldivtree.free;
+                    end;
                 end
               else
                 begin