This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] Fix wrong code with boolean negation


Hi,

this is a regression present in the Ada compiler since 4.5: the issue had been 
latent for ages, but an unrelated streamlining of the IR made it appear.

When make_range_step is invoked on:

  (integer)!b < 0

where b is a boolean, it returns "always true" instead of "always false".

The sequence is as follows:

  (integer)!b < 0   is_true_if   not in [0:0]
  (integer)!b       is_true_if   not in [0;+inf[
  !b                is_true_if   not in [0;255]
  b                 is_true_if       in [0;255]

The wrong step is the last one: when TRUTH_NOT_EXPR is seen in make_range_step 
the "in" value is unconditionally toggled.  Of course that doesn't work in the 
general case, just if the range is the "boolean" range.  As a matter of fact, 
this is explained just below for the comparison operators:

      /* We can only do something if the range is testing for zero
	 and if the second operand is an integer constant.  Note that
	 saying something is "in" the range we make is done by
	 complementing IN_P since it will set in the initial case of
	 being not equal to zero; "out" is leaving it alone.  */

so the fix is to use the zero range condition in the TRUTH_NOT_EXPR case.

Tested on x86_64-suse-linux, OK for mainline?  And for branch(es)?


2013-01-21  Eric Botcazou  <ebotcazou@adacore.com>

	* fold-const.c (make_range_step) <TRUTH_NOT_EXPR>: Bail out if the
	range isn't testing for zero.


2013-01-21  Eric Botcazou  <ebotcazou@adacore.com>

	* gnat.dg/opt26.adb: New test.


-- 
Eric Botcazou
Index: fold-const.c
===================================================================
--- fold-const.c	(revision 195310)
+++ fold-const.c	(working copy)
@@ -3813,6 +3813,10 @@ make_range_step (location_t loc, enum tr
   switch (code)
     {
     case TRUTH_NOT_EXPR:
+      /* We can only do something if the range is testing for zero.  */
+      if (low == NULL_TREE || high == NULL_TREE
+	  || ! integer_zerop (low) || ! integer_zerop (high))
+	return NULL_TREE;
       *p_in_p = ! in_p;
       return arg0;
 
-- { dg-do run }
-- { dg-options "-gnato -O" }

with Interfaces; use Interfaces;

procedure Opt26 is

   procedure Shift_Left_Bool
     (Bool : in Boolean;
      U8 : out Interfaces.Unsigned_8)
   is
   begin
      U8 := Shift_Left (Boolean'Pos (Bool), 6);
   end Shift_Left_Bool;

   procedure Shift_Left_Not_Bool
     (Bool : in Boolean;
      U8 : out Interfaces.Unsigned_8)
   is
   begin
      U8 := Shift_Left (Boolean'Pos (not Bool), 6);
   end Shift_Left_Not_Bool;

   Bool         : constant Boolean := True;
   Byte1, Byte2 : Interfaces.Unsigned_8;

begin

   Shift_Left_Bool (Bool, Byte1);

   Shift_Left_Not_Bool (Bool, Byte2);

   if Byte1 + Byte2 /= 64 then
     raise Program_Error;
   end if;

end;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]