Browse Source

* fixed overflow checking for inc/dec on non-x86
+ test for the above

git-svn-id: trunk@5317 -

Jonas Maebe 18 years ago
parent
commit
b8c3fecd1d
4 changed files with 159 additions and 20 deletions
  1. 1 0
      .gitattributes
  2. 8 1
      compiler/ncginl.pas
  3. 35 19
      compiler/ninl.pas
  4. 115 0
      tests/test/cg/tincdec.pp

+ 1 - 0
.gitattributes

@@ -6334,6 +6334,7 @@ tests/test/cg/tfor.pp svneol=native#text/plain
 tests/test/cg/tformfnc.pp -text
 tests/test/cg/tfuncret.pp svneol=native#text/plain
 tests/test/cg/tin.pp svneol=native#text/plain
+tests/test/cg/tincdec.pp svneol=native#text/plain
 tests/test/cg/tincexc.pp svneol=native#text/plain
 tests/test/cg/tinitdon.pp svneol=native#text/plain
 tests/test/cg/tis.pp svneol=native#text/plain

+ 8 - 1
compiler/ncginl.pas

@@ -464,7 +464,14 @@ implementation
                  cg.a_op_reg_loc(current_asmdata.CurrAsmList,addsubop[inlinenumber],
                    hregister,tcallparanode(left).left.location);
              end;
-          cg.g_overflowcheck(current_asmdata.CurrAsmList,tcallparanode(left).left.location,tcallparanode(left).resultdef);
+          { things which can overflow must NOT pass via here, but have to be  }
+          { handled via a regular add node (conversion in tinlinenode.pass_1) }
+          { Or someone has to rewrite the above to use a_op_const_reg_reg_ov  }
+          { and friends in case of overflow checking, and ask everyone to     }
+          { implement these methods since they don't exist for all cpus (JM)  }
+          if (cs_check_overflow in current_settings.localswitches) then
+            internalerror(2006111010);
+//          cg.g_overflowcheck(current_asmdata.CurrAsmList,tcallparanode(left).left.location,tcallparanode(left).resultdef);
           cg.g_rangecheck(current_asmdata.CurrAsmList,tcallparanode(left).left.location,tcallparanode(left).left.resultdef,
               tcallparanode(left).left.resultdef);
         end;

+ 35 - 19
compiler/ninl.pas

@@ -2191,7 +2191,7 @@ implementation
 
     function tinlinenode.pass_1 : tnode;
       var
-         hp,hpp  : tnode;
+         hp,hpp,resultnode  : tnode;
          shiftconst: longint;
          tempnode: ttempcreatenode;
          newstatement: tstatementnode;
@@ -2306,20 +2306,9 @@ implementation
             begin
                expectloc:=LOC_VOID;
 
-               { check type }
-               if
-{$ifndef cpu64bit}
-                  is_64bit(left.resultdef) or
-{$endif cpu64bit}
-                  { range/overflow checking doesn't work properly }
-                  { with the inc/dec code that's generated (JM)   }
-                  (
-                   (((left.resultdef.typ = orddef) and
-                     not(is_char(left.resultdef)) and
-                     not(is_boolean(left.resultdef))) or
-                    (left.resultdef.typ = pointerdef)) and
-                   (current_settings.localswitches * [cs_check_overflow,cs_check_range] <> [])
-                  ) then
+               { range/overflow checking doesn't work properly }
+               { with the inc/dec code that's generated (JM)   }
+               if (current_settings.localswitches * [cs_check_overflow,cs_check_range] <> []) then
                  { convert to simple add (JM) }
                  begin
                    newblock := internalstatements(newstatement);
@@ -2338,10 +2327,13 @@ implementation
                        hpp := cordconstnode.create(1,tcallparanode(left).left.resultdef,false);
                      end;
                    typecheckpass(hpp);
-{$ifndef cpu64bit}
+
                    if not((hpp.resultdef.typ=orddef) and
+{$ifndef cpu64bit}
                           (torddef(hpp.resultdef).ordtype<>u32bit)) then
-{$endif cpu64bit}
+{$else not cpu64bit}
+                          (torddef(hpp.resultdef).ordtype<>u64bit)) then
+{$endif not cpu64bit}
                      inserttypeconv_internal(hpp,sinttype);
                    { No overflow check for pointer operations, because inc(pointer,-1) will always
                      trigger an overflow. For uint32 it works because then the operation is done
@@ -2364,14 +2356,38 @@ implementation
                        hp := tcallparanode(left).left.getcopy;
                        tempnode := nil;
                      end;
+
+                   resultnode := hp.getcopy;
+                   { avoid type errors from the addn/subn }
+                   if not is_integer(resultnode.resultdef) and
+                      (resultnode.resultdef.typ <> pointerdef) then
+                     begin
+                       inserttypeconv_internal(hp,sinttype);
+                       inserttypeconv_internal(hpp,sinttype);
+                     end;
+
                    { addition/substraction depending on inc/dec }
                    if inlinenumber = in_inc_x then
                      hpp := caddnode.create(addn,hp,hpp)
                    else
                      hpp := caddnode.create(subn,hp,hpp);
                    { assign result of addition }
-                   inserttypeconv_internal(hpp,hp.resultdef);
-                   addstatement(newstatement,cassignmentnode.create(hp.getcopy,hpp));
+                   if not(is_integer(resultnode.resultdef)) and
+                      (resultnode.resultdef.typ <> pointerdef) then
+                     inserttypeconv(hpp,torddef.create(
+{$ifdef cpu64bit}
+                       s64bit,
+{$else cpu64bit}
+                       s32bit,
+{$endif cpu64bit}
+                       get_min_value(resultnode.resultdef),
+                       get_max_value(resultnode.resultdef)))
+                   else
+                     inserttypeconv(hpp,resultnode.resultdef);
+                   { avoid any possible warnings }
+                   inserttypeconv_internal(hpp,resultnode.resultdef);
+                   
+                   addstatement(newstatement,cassignmentnode.create(resultnode,hpp));
                    { deallocate the temp }
                    if assigned(tempnode) then
                      addstatement(newstatement,ctempdeletenode.create(tempnode));

+ 115 - 0
tests/test/cg/tincdec.pp

@@ -0,0 +1,115 @@
+{$mode objfpc}
+
+{$q+}
+{$r+}
+
+uses
+  sysutils;
+
+type
+  tenum = (ea,eb,ec,ed,ef,eg,eh);
+
+procedure testbool;
+var
+  b: boolean;
+  caught: boolean;
+begin
+  caught := false;
+  b := false;
+  inc(b);
+  try
+    inc(b);
+  except
+    on ERangeError do
+      caught := true;
+  end;
+  if not caught or
+     not b then
+    halt(1);
+
+  caught := false;
+  dec(b);
+  try
+    dec(b);
+  except
+    on ERangeError do
+      caught := true;
+  end;
+  if not caught or
+     b then
+    halt(2);
+end;
+
+
+procedure testchar;
+var
+  b: char;
+  caught: boolean;
+begin
+  caught := false;
+  b := #254;
+  inc(b);
+  try
+    inc(b);
+  except
+    on ERangeError do
+      caught := true;
+  end;
+  if not caught or
+     (b <> #255) then
+    halt(3);
+
+  caught := false;
+  b := #1;
+  dec(b);
+  try
+    dec(b);
+  except
+    on ERangeError do
+      caught := true;
+  end;
+  if not caught or
+     (b <> #0) then
+    halt(4);
+end;
+
+
+
+procedure testenum;
+var
+  b: tenum;
+  caught: boolean;
+begin
+  caught := false;
+  b := eg;
+  inc(b);
+  try
+    inc(b);
+  except
+    on ERangeError do
+      caught := true;
+  end;
+  if not caught or
+     (b <> eh) then
+    halt(5);
+
+  caught := false;
+  b := eb;
+  dec(b);
+  try
+    dec(b);
+  except
+    on ERangeError do
+      caught := true;
+  end;
+  if not caught or
+     (b <> ea) then
+    halt(6);
+end;
+
+
+begin
+  testbool;
+  testchar;
+  testenum;
+end.