Browse Source

* call taddnode.simplify at the very end of taddnode.pass_typecheck, so
it doesn't have to duplicate any type checking code, and so constant
expressions get the same resultdefs as non-constant expressions
* properly fixed resultdef determination of "set + setelementn" (follows
same rules now as "set + set")
* also convert "longint or/xor cardinal" to int64 (needed for correct
results with negative numbers and Delphi-compatible) + test
* extended 64-to-32 type conversion simplification to also handle
or/xor nodes (so if the result is typecasted back to 32 bit, the
evaluation can still be done entirely in 32 bit). These changes also
enable that optimization in some extra cases (not just anymore for
expressions containing only uint32)

git-svn-id: trunk@10418 -

Jonas Maebe 17 years ago
parent
commit
97f4c0a130
4 changed files with 249 additions and 214 deletions
  1. 1 0
      .gitattributes
  2. 149 173
      compiler/nadd.pas
  3. 66 41
      compiler/ncnv.pas
  4. 33 0
      tests/test/cg/taddint.pp

+ 1 - 0
.gitattributes

@@ -6853,6 +6853,7 @@ tests/test/cg/ptest.pp svneol=native#text/plain
 tests/test/cg/taddbool.pp svneol=native#text/plain
 tests/test/cg/taddcard.pp svneol=native#text/plain
 tests/test/cg/taddcurr.pp svneol=native#text/plain
+tests/test/cg/taddint.pp svneol=native#text/plain
 tests/test/cg/taddlong.pp svneol=native#text/plain
 tests/test/cg/taddr1.pp svneol=native#text/plain
 tests/test/cg/taddr2.pp svneol=native#text/plain

+ 149 - 173
compiler/nadd.pas

@@ -140,8 +140,9 @@ implementation
 
     function taddnode.simplify : tnode;
       var
-        t : tnode;
+        t, hp   : tnode;
         lt,rt   : tnodetype;
+        realdef : tdef;
         rd,ld   : tdef;
         rv,lv,v : tconstexprint;
         rvd,lvd : bestreal;
@@ -204,28 +205,6 @@ implementation
             ) then
           begin
              t:=nil;
-             { when comparing/substracting  pointers, make sure they are }
-             { of the same  type (JM)                                    }
-             if (lt = pointerconstn) and (rt = pointerconstn) then
-              begin
-                if not(cs_extsyntax in current_settings.moduleswitches) and
-                   not(nodetype in [equaln,unequaln]) then
-                  CGMessage3(type_e_operator_not_supported_for_types,node2opstr(nodetype),ld.typename,rd.typename)
-                else
-                  if (nodetype <> subn) and
-                     is_voidpointer(rd) then
-                    inserttypeconv(right,left.resultdef)
-                  else if (nodetype <> subn) and
-                          is_voidpointer(ld) then
-                    inserttypeconv(left,right.resultdef)
-                  else if not(equal_defs(ld,rd)) then
-                    IncompatibleTypes(ld,rd);
-               end
-             else if (ld.typ=enumdef) and (rd.typ=enumdef) then
-              begin
-                if not(equal_defs(ld,rd)) then
-                  inserttypeconv(right,left.resultdef);
-               end;
 
              { load values }
              case lt of
@@ -248,12 +227,8 @@ implementation
                else
                  internalerror(2002080203);
              end;
-             if (lt = pointerconstn) and
-                (rt <> pointerconstn) then
-               rv := rv * tpointerdef(left.resultdef).pointeddef.size;
-             if (rt = pointerconstn) and
-                (lt <> pointerconstn) then
-               lv := lv * tpointerdef(right.resultdef).pointeddef.size;
+             { type checking already took care of multiplying      }
+             { integer constants with pointeddef.size if necessary }
              case nodetype of
                addn :
                  begin
@@ -265,12 +240,12 @@ implementation
                        t:=genintconstnode(0)
                      end
                    else if (lt=pointerconstn) then
-                     t := cpointerconstnode.create(qword(v),left.resultdef)
+                     t := cpointerconstnode.create(qword(v),resultdef)
                    else
                      if is_integer(ld) then
                        t := genintconstnode(v)
                      else
-                       t := cordconstnode.create(v,left.resultdef,(ld.typ<>enumdef));
+                       t := cordconstnode.create(v,resultdef,(ld.typ<>enumdef));
                  end;
                subn :
                  begin
@@ -284,14 +259,18 @@ implementation
                    else if (lt=pointerconstn) then
                      { pointer-pointer results in an integer }
                      if (rt=pointerconstn) then
-                       t := genintconstnode(v div tpointerdef(ld).pointeddef.size)
+                       begin
+                         if not(nf_has_pointerdiv in flags) then
+                           internalerror(2008030101);
+                         t := genintconstnode(v)
+                       end
                      else
-                       t := cpointerconstnode.create(qword(v),left.resultdef)
+                       t := cpointerconstnode.create(qword(v),resultdef)
                    else
                      if is_integer(ld) then
                        t:=genintconstnode(v)
                      else
-                       t:=cordconstnode.create(v,left.resultdef,(ld.typ<>enumdef));
+                       t:=cordconstnode.create(v,resultdef,(ld.typ<>enumdef));
                  end;
                muln :
                  begin
@@ -309,17 +288,17 @@ implementation
                  if is_integer(ld) then
                    t:=genintconstnode(lv xor rv)
                  else
-                   t:=cordconstnode.create(lv xor rv,left.resultdef,true);
+                   t:=cordconstnode.create(lv xor rv,resultdef,true);
                orn :
                  if is_integer(ld) then
                    t:=genintconstnode(lv or rv)
                  else
-                   t:=cordconstnode.create(lv or rv,left.resultdef,true);
+                   t:=cordconstnode.create(lv or rv,resultdef,true);
                andn :
                  if is_integer(ld) then
                    t:=genintconstnode(lv and rv)
                  else
-                   t:=cordconstnode.create(lv and rv,left.resultdef,true);
+                   t:=cordconstnode.create(lv and rv,resultdef,true);
                ltn :
                  t:=cordconstnode.create(ord(lv<rv),booltype,true);
                lten :
@@ -340,10 +319,7 @@ implementation
                    t:=crealconstnode.create(lvd/rvd,resultrealdef);
                  end;
                else
-                 begin
-                   CGMessage3(type_e_operator_not_supported_for_types,node2opstr(nodetype),ld.typename,rd.typename);
-                   t:=cnothingnode.create;
-                 end;
+                 internalerror(2008022101);
              end;
              result:=t;
              exit;
@@ -358,8 +334,17 @@ implementation
             is_subequal(left.resultdef,right.resultdef) then
             begin
               t:=nil;
+              hp:=right;
+              realdef:=hp.resultdef;
+              while (hp.nodetype=typeconvn) and
+                    ([nf_internal,nf_explicit] * hp.flags = []) and
+                    is_in_limit(ttypeconvnode(hp).left.resultdef,realdef) do
+                begin
+                  hp:=ttypeconvnode(hp).left;
+                  realdef:=hp.resultdef;
+                end;
               lv:=Tordconstnode(left).value;
-              with Torddef(right.resultdef) do
+              with torddef(realdef) do
                 case nodetype of
                  ltn:
                    if lv<low then
@@ -395,15 +380,21 @@ implementation
                 end
             end
           else if (left.resultdef.typ=orddef) and is_constintnode(right) and
-(*              { all type limits are stored using tconstexprint = int64   }
-              { currently, so u64bit support would need extra type casts }
-              (Torddef(left.resultdef).ordtype<>u64bit) and*)
               { don't ignore type checks }
               is_subequal(left.resultdef,right.resultdef) then
             begin
               t:=nil;
+              hp:=left;
+              realdef:=hp.resultdef;
+              while (hp.nodetype=typeconvn) and
+                    ([nf_internal,nf_explicit] * hp.flags = []) and
+                    is_in_limit(ttypeconvnode(hp).left.resultdef,realdef) do
+                begin
+                  hp:=ttypeconvnode(hp).left;
+                  realdef:=hp.resultdef;
+                end;
               rv:=Tordconstnode(right).value;
-              with Torddef(left.resultdef) do
+              with torddef(realdef) do
                 case nodetype of
                  ltn:
                    if high<rv then
@@ -448,7 +439,7 @@ implementation
                   addn,subn:
                    result := left.getcopy;
                   muln:
-                   result:=cordconstnode.create(0,left.resultdef,true);
+                   result:=cordconstnode.create(0,resultdef,true);
                 end;
               end
             else if tordconstnode(right).value = 1 then
@@ -546,10 +537,7 @@ implementation
                 unequaln :
                   t:=cordconstnode.create(ord(lvd<>rvd),booltype,true);
                 else
-                  begin
-                    CGMessage3(type_e_operator_not_supported_for_types,node2opstr(nodetype),ld.typename,rd.typename);
-                    t:=cnothingnode.create;
-                  end;
+                  internalerror(2008022102);
              end;
              result:=t;
              exit;
@@ -588,10 +576,7 @@ implementation
                 unequaln :
                   t:=cordconstnode.create(byte(comparewidestrings(ws1,ws2)<>0),booltype,true);
                 else
-                  begin
-                    CGMessage3(type_e_operator_not_supported_for_types,node2opstr(nodetype),ld.typename,rd.typename);
-                    t:=cnothingnode.create;
-                  end;
+                  internalerror(2008022103);
              end;
              donewidestring(ws1);
              donewidestring(ws2);
@@ -661,10 +646,7 @@ implementation
                 unequaln :
                   t:=cordconstnode.create(byte(compareansistrings(s1,s2,l1,l2)<>0),booltype,true);
                 else
-                  begin
-                    CGMessage3(type_e_operator_not_supported_for_types,node2opstr(nodetype),ld.typename,rd.typename);
-                    t:=cnothingnode.create;
-                  end;
+                  internalerror(2008022104);
              end;
              result:=t;
              exit;
@@ -676,42 +658,26 @@ implementation
            (left.nodetype=setconstn) and
            not assigned(tsetconstnode(left).left) then
           begin
-             { check if size adjusting is needed, only for left
-               to right as the other way is checked in the typeconv }
-             if (tsetdef(right.resultdef).settype=smallset) and
-                (tsetdef(left.resultdef).settype<>smallset) then
-               right.resultdef:=tsetdef.create(tsetdef(right.resultdef).elementdef,0,255);
-             { check base types, keep the original type if right was an empty set }
-             if assigned(tsetdef(right.resultdef).elementdef) then
-               inserttypeconv(left,right.resultdef);
-
-             if codegenerror then
-              begin
-                { recover by only returning the left part }
-                result:=left;
-                left:=nil;
-                exit;
-              end;
              case nodetype of
                addn :
                  begin
                    resultset:=tsetconstnode(right).value_set^ + tsetconstnode(left).value_set^;
-                   t:=csetconstnode.create(@resultset,left.resultdef);
+                   t:=csetconstnode.create(@resultset,resultdef);
                  end;
                 muln :
                   begin
                     resultset:=tsetconstnode(right).value_set^ * tsetconstnode(left).value_set^;
-                    t:=csetconstnode.create(@resultset,left.resultdef);
+                    t:=csetconstnode.create(@resultset,resultdef);
                   end;
                subn :
                   begin
                     resultset:=tsetconstnode(left).value_set^ - tsetconstnode(right).value_set^;
-                            t:=csetconstnode.create(@resultset,left.resultdef);
+                            t:=csetconstnode.create(@resultset,resultdef);
                   end;
                symdifn :
                   begin
                     resultset:=tsetconstnode(right).value_set^ >< tsetconstnode(left).value_set^;
-                        t:=csetconstnode.create(@resultset,left.resultdef);
+                        t:=csetconstnode.create(@resultset,resultdef);
                   end;
                unequaln :
                   begin
@@ -734,10 +700,7 @@ implementation
                     t:=cordconstnode.create(byte(b),booltype,true);
                   end;
                 else
-                  begin
-                    CGMessage3(type_e_operator_not_supported_for_types,node2opstr(nodetype),ld.typename,rd.typename);
-                    t:=cnothingnode.create;
-                  end;
+                  internalerror(2008022105);
              end;
              result:=t;
              exit;
@@ -880,10 +843,6 @@ implementation
             inserttypeconv(left,cwidestringtype);
           end;
 
-         result:=simplify;
-         if assigned(result) then
-           exit;
-
         { load easier access variables }
         rd:=right.resultdef;
         ld:=left.resultdef;
@@ -1087,19 +1046,35 @@ implementation
                   if (torddef(rd).ordtype<>scurrency) then
                    inserttypeconv(right,s64currencytype);
                end
-             { and,or,xor work on bit patterns and don't care
-               about the sign of integers }
-             { compares don't need extension to native int size either }
-             { as long as both values are signed or unsigned           }
+             { "and" does't care about the sign of integers }
+             { "xor", "or" and compares don't need extension to native int }
+             { size either as long as both values are signed or unsigned   }
+             { "xor" and "or" also don't care about the sign if the values }
+             { occupy an entire register                                   }
              else if is_integer(ld) and is_integer(rd) and
-                     ((nodetype in [andn,orn,xorn]) or
-                      ((nodetype in [equaln,unequaln,gtn,gten,ltn,lten]) and
+                     ((nodetype=andn) or
+                      ((nodetype in [orn,xorn,equaln,unequaln,gtn,gten,ltn,lten]) and
                        not(is_signed(ld) xor is_signed(rd)))) then
                begin
-                 if rd.size>ld.size then
-                   inserttypeconv_internal(left,right.resultdef)
-                 else
-                   inserttypeconv_internal(right,left.resultdef);
+                 if (rd.size>ld.size) or
+                    { Delphi-compatible: prefer unsigned type for "and" with equal size }
+                    ((rd.size=ld.size) and
+                     not is_signed(rd)) then
+                   begin
+                     if (rd.size=ld.size) and
+                        is_signed(ld) then
+                       inserttypeconv_internal(left,right.resultdef)
+                     else
+                       inserttypeconv(left,right.resultdef)
+                   end
+                 else 
+                   begin
+                     if (rd.size=ld.size) and
+                        is_signed(rd) then
+                       inserttypeconv_internal(right,left.resultdef)
+                     else
+                       inserttypeconv(right,left.resultdef)
+                   end
                end
              { is there a signed 64 bit type ? }
              else if ((torddef(rd).ordtype=s64bit) or (torddef(ld).ordtype=s64bit)) then
@@ -1148,8 +1123,9 @@ implementation
                      { mustn't do it here because that would change  }
                      { overload choosing behaviour etc. The code in  }
                      { ncnv.pas is run after that is already decided }
-                     if not is_signed(left.resultdef) and
-                        not is_signed(right.resultdef) then
+                     if (not is_signed(left.resultdef) and
+                         not is_signed(right.resultdef)) or
+                        (nodetype in [orn,xorn]) then
                        include(flags,nf_internal);
                      inserttypeconv(left,s64inttype);
                      inserttypeconv(right,s64inttype);
@@ -1260,84 +1236,80 @@ implementation
            else array constructor can be seen as array of char (PFV) }
          else if (ld.typ=setdef) then
           begin
-            { trying to add a set element? }
-            if (nodetype=addn) and (rd.typ<>setdef) then
-             begin
-               if (rt=setelementn) then
-                 begin
-                   if not(equal_defs(tsetdef(ld).elementdef,rd)) then
-                     inserttypeconv(right,tsetdef(ld).elementdef);
-                 end
-               else
-                 CGMessage(type_e_mismatch);
-             end
-            else
-             begin
-               if not(nodetype in [addn,subn,symdifn,muln,equaln,unequaln,lten,gten]) then
-                CGMessage(type_e_set_operation_unknown);
-               { Make operands the same setdef. If one's elementtype fits   }
-               { entirely inside the other's, pick the one with the largest }
-               { range.  Otherwise create a new setdef with a range which   }
-               { can contain both.                                          }
-               if not(equal_defs(ld,rd)) then
-                begin
-                  { note: ld cannot be an empty set with elementdef=nil in }
-                  { case right is not a set, arrayconstructor_to_set takes }
-                  { care of that                                           }
-
-                  { 1: rd is a set with an assigned elementdef, and ld is    }
-                  {    either an empty set without elementdef or a set whose }
-                  {    elementdef fits in rd's elementdef -> convert to rd   }
-                  if ((rd.typ=setdef) and
-                      assigned(tsetdef(rd).elementdef) and
-                      (not assigned(tsetdef(ld).elementdef) or
-                       is_in_limit(ld,rd))) then
-                    inserttypeconv(left,right.resultdef)
-                  { 2: rd is either an empty set without elementdef or a set }
-                  {    whose elementdef fits in ld's elementdef, or a set    }
-                  {    element whose def fits in ld's elementdef -> convert  }
-                  {    to ld. ld's elementdef can't be nil here, is caught   }
-                  {    previous case and "note:" above                       }
-                  else if ((rd.typ=setdef) and
-                           (not assigned(tsetdef(rd).elementdef) or
-                            is_in_limit(rd,ld))) or
-                          ((rd.typ<>setdef) and
-                           is_in_limit(rd,tsetdef(ld).elementdef)) then
-                    inserttypeconv(right,left.resultdef)
-                  { 3: otherwise create setdef which encompasses both, taking }
-                  {    into account empty sets without elementdef             }
+             if not(nodetype in [addn,subn,symdifn,muln,equaln,unequaln,lten,gten]) then
+              CGMessage(type_e_set_operation_unknown);
+             { right must either be a set or a set element }
+             if (rd.typ<>setdef) and
+                (rt<>setelementn) then
+               CGMessage(type_e_mismatch)
+             { Make operands the same setdef. If one's elementtype fits   }
+             { entirely inside the other's, pick the one with the largest }
+             { range.  Otherwise create a new setdef with a range which   }
+             { can contain both.                                          }
+             else if not(equal_defs(ld,rd)) then
+              begin
+                { note: ld cannot be an empty set with elementdef=nil in }
+                { case right is not a set, arrayconstructor_to_set takes }
+                { care of that                                           }
+  
+                { 1: rd is a set with an assigned elementdef, and ld is    }
+                {    either an empty set without elementdef or a set whose }
+                {    elementdef fits in rd's elementdef -> convert to rd   }
+                if ((rd.typ=setdef) and
+                    assigned(tsetdef(rd).elementdef) and
+                    (not assigned(tsetdef(ld).elementdef) or
+                     is_in_limit(ld,rd))) then
+                  inserttypeconv(left,rd)
+                { 2: rd is either an empty set without elementdef or a set }
+                {    whose elementdef fits in ld's elementdef, or a set    }
+                {    element whose def fits in ld's elementdef -> convert  }
+                {    to ld. ld's elementdef can't be nil here, is caught   }
+                {    previous case and "note:" above                       }
+                else if ((rd.typ=setdef) and
+                         (not assigned(tsetdef(rd).elementdef) or
+                          is_in_limit(rd,ld))) or
+                        ((rd.typ<>setdef) and
+                         is_in_limit(rd,tsetdef(ld).elementdef)) then
+                   if (rd.typ=setdef) then
+                    inserttypeconv(right,ld)
                   else
-                    begin
-                      if assigned(tsetdef(ld).elementdef) then
+                    inserttypeconv(right,tsetdef(ld).elementdef)
+                { 3: otherwise create setdef which encompasses both, taking }
+                {    into account empty sets without elementdef             }
+                else
+                  begin
+                    if assigned(tsetdef(ld).elementdef) then
+                      begin
+                        llow:=tsetdef(ld).setbase;
+                        lhigh:=tsetdef(ld).setmax;
+                      end;
+                    if (rd.typ=setdef) then
+                      if assigned(tsetdef(rd).elementdef) then
                         begin
-                          llow:=tsetdef(ld).setbase;
-                          lhigh:=tsetdef(ld).setmax;
-                        end;
-                      if (rd.typ=setdef) then
-                        if assigned(tsetdef(rd).elementdef) then
-                          begin
-                            rlow:=tsetdef(rd).setbase;
-                            rhigh:=tsetdef(rd).setmax;
-                          end
-                        else
-                          begin
-                            { ld's elementdef must have been valid }
-                            rlow:=llow;
-                            rhigh:=lhigh;
-                          end
+                          rlow:=tsetdef(rd).setbase;
+                          rhigh:=tsetdef(rd).setmax;
+                        end
                       else
-                        getrange(rd,rlow,rhigh);
-                      if not assigned(tsetdef(ld).elementdef) then
                         begin
-                          llow:=rlow;
-                          lhigh:=rhigh;
-                        end;
-                      nd:=tsetdef.create(tsetdef(ld).elementdef,min(llow,rlow),max(lhigh,rhigh));
-                      inserttypeconv(left,nd);
-                      inserttypeconv(right,nd);
-                    end;
-                end;
-            end;
+                          { ld's elementdef must have been valid }
+                          rlow:=llow;
+                          rhigh:=lhigh;
+                        end
+                    else
+                      getrange(rd,rlow,rhigh);
+                    if not assigned(tsetdef(ld).elementdef) then
+                      begin
+                        llow:=rlow;
+                        lhigh:=rhigh;
+                      end;
+                    nd:=tsetdef.create(tsetdef(ld).elementdef,min(llow,rlow),max(lhigh,rhigh));
+                    inserttypeconv(left,nd);
+                    if (rd.typ=setdef) then
+                      inserttypeconv(right,nd)
+                    else
+                      inserttypeconv(right,tsetdef(nd).elementdef);
+                  end;
+              end;
           end
          { pointer comparision and subtraction }
          else if (
@@ -1802,6 +1774,10 @@ implementation
                 end;
             end;
           end;
+
+         if not codegenerror and
+            not assigned(result) then
+           result:=simplify;
       end;
 
 

+ 66 - 41
compiler/ncnv.pas

@@ -1958,58 +1958,83 @@ implementation
     { the result of this node tree is downcasted again to a      }
     { 8/16/32 bit value afterwards                               }
     function checkremove64bittypeconvs(n: tnode): boolean;
+      var
+        gotmuldivmod, gotsint: boolean;
 
       { checks whether a node is either an u32bit, or originally }
       { was one but was implicitly converted to s64bit           }
-      function wasoriginallyuint32(n: tnode): boolean;
+      function wasoriginallyint32(n: tnode): boolean;
         begin
           if (n.resultdef.typ<>orddef) then
             exit(false);
-          if (torddef(n.resultdef).ordtype=u32bit) then
-            exit(true);
-          result:=
-            (torddef(n.resultdef).ordtype=s64bit) 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 }
-            (((n.nodetype=typeconvn) and
-              (ttypeconvnode(n).left.resultdef.typ=orddef) and
-              (torddef(ttypeconvnode(n).left.resultdef).ordtype=u32bit)) or
-            { or an ordconstnode which was/is a valid cardinal }
-             ((n.nodetype=ordconstn) and
-              (tordconstnode(n).value>=0) and
-              (tordconstnode(n).value<=high(cardinal))));
-        end;
-
-
-      begin
-        result:=false;
-        if wasoriginallyuint32(n) then
-          exit(true);
-        case n.nodetype of
-          subn:
+          if (torddef(n.resultdef).ordtype in [s32bit,u32bit]) then
             begin
-              { nf_internal is set by taddnode.typecheckpass in  }
-              { case the arguments of this subn were u32bit, but }
-              { upcasted to s64bit for calculation correctness   }
-              { (normally only needed when range checking, but   }
-              {  also done otherwise so there is no difference   }
-              {  in overload choosing etc between $r+ and $r-)   }
-              if (nf_internal in n.flags) then
-                result:=true
-              else
-                result:=
-                  checkremove64bittypeconvs(tbinarynode(n).left) and
-                  checkremove64bittypeconvs(tbinarynode(n).right);
+              if (torddef(n.resultdef).ordtype=s32bit) then
+                gotsint:=true;
+              exit(true);
             end;
-          addn,muln,divn,modn,xorn,andn,orn:
+          if (torddef(n.resultdef).ordtype=s64bit) 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 }
+             (((n.nodetype=typeconvn) and
+               (ttypeconvnode(n).left.resultdef.typ=orddef) and
+               (torddef(ttypeconvnode(n).left.resultdef).ordtype in [s32bit,u32bit])) or
+             { or an ordconstnode which was/is a valid cardinal }
+              ((n.nodetype=ordconstn) and
+               (tordconstnode(n).value>=low(longint)) and
+               (tordconstnode(n).value<=high(cardinal)))) then
             begin
-              result:=
-                checkremove64bittypeconvs(tbinarynode(n).left) and
-                checkremove64bittypeconvs(tbinarynode(n).right);
+              if ((n.nodetype=typeconvn) and
+                  (torddef(ttypeconvnode(n).left.resultdef).ordtype=s32bit)) or
+                 ((n.nodetype=ordconstn) and
+                  (tordconstnode(n).value<0)) then
+                gotsint:=true;
+              exit(true);
             end;
+          result:=false;
+        end;
+  
+  
+      function docheckremove64bittypeconvs(n: tnode): boolean;
+        begin
+          result:=false;
+          if wasoriginallyint32(n) then
+            exit(true);
+          case n.nodetype of
+            subn,orn,xorn:
+              begin
+                { nf_internal is set by taddnode.typecheckpass in  }
+                { case the arguments of this subn were u32bit, but }
+                { upcasted to s64bit for calculation correctness   }
+                { (normally only needed when range checking, but   }
+                {  also done otherwise so there is no difference   }
+                {  in overload choosing etc between $r+ and $r-)   }
+                if (nf_internal in n.flags) then
+                  result:=true
+                else
+                  result:=
+                    docheckremove64bittypeconvs(tbinarynode(n).left) and
+                    docheckremove64bittypeconvs(tbinarynode(n).right);
+              end;
+            addn,muln,divn,modn,andn:
+              begin
+                if n.nodetype in [muln,divn,modn] then
+                  gotmuldivmod:=true;
+                result:=
+                  docheckremove64bittypeconvs(tbinarynode(n).left) and
+                  docheckremove64bittypeconvs(tbinarynode(n).right);
+              end;
+          end;
         end;
+
+      begin { checkremove64bittypeconvs }
+        gotmuldivmod:=false;
+        gotsint:=false;
+        result:=
+          docheckremove64bittypeconvs(n) and
+          not(gotmuldivmod and gotsint);
       end;
 
 

+ 33 - 0
tests/test/cg/taddint.pp

@@ -0,0 +1,33 @@
+var
+  b: byte;
+  s: shortint;
+  l: longint;
+  c: cardinal;
+  i: int64;
+begin
+  b:=10;
+  s:=-128;
+  l:=b or s;
+  writeln(l);
+  if (l<>-118) then
+    halt(1);
+  l:=b xor s;
+  writeln(l);
+  if (l<>-118) then
+    halt(2);
+  b:=129;
+  s:=-127;
+  l:=b and s;
+  writeln(l);
+  if (l<>129) then
+    halt(3);
+  l:=s and b;
+  writeln(l);
+  if (l<>129) then
+    halt(4);
+
+  l:=-127;
+  c:=129;
+  i:=l and c;
+  writeln(i);
+end.