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 C++ enums handling in build_range_check


Hi!

This bug has been caught in OOo, present in both 3.4.x and on the trunk.
Surprisingly it has not been introduced by my recent build_range_check
patch and exists on vanilla 3.4.x where that patch has not been commited.

extern "C" void abort (void);

enum E { E0, E1, E2, E3, E4, E5 };

void
test (enum E e)
{
  if (e == E2 || e == E3 || e == E1)
    abort ();
}

int
main (void)
{
  test (E4);
  test (E5);
  test (E0);
  return 0;
}

The above testcase will abort with -O1 and above.
The problem is that this enum has TYPE_PRECISION 3 and build_range_check
special cases c >= 1 && c <= 127 range comparisons (where 127 stands
for largest signed value in that type).
This results in "optimizing" the e >= 1 && e <= 3 test into
(signed E) e > 0, but as the comparison is in the end not done in the
3 bit type but in SImode which is the underlying enum's TYPE_MODE,
we get it wrong.

Ok for trunk and 3.4?

For 3.4 where the range-test-1.[cC] tests don't exist I'd like to commit
the whole tests instead of commiting a testcase like above.

2004-07-09  Jakub Jelinek  <jakub@redhat.com>

	* fold-const.c (build_range_check): Use TYPE_MODE's precision for
	enumerals.

	* g++.dg/opt/range-test-1.C: Add new test (#26).

--- gcc/fold-const.c.jj	2004-07-09 13:50:54.000000000 +0200
+++ gcc/fold-const.c	2004-07-09 18:10:52.945905468 +0200
@@ -3844,7 +3844,13 @@ build_range_check (tree type, tree exp, 
       HOST_WIDE_INT hi;
       int prec;
 
-      prec = TYPE_PRECISION (etype);
+      /* For enums the comparison will be done in the underlying type,
+	 so using enum's precision is wrong here.
+	 Consider e.g. enum { A, B, C, D, E }, low == B and high == D.  */
+      if (TREE_CODE (etype) == ENUMERAL_TYPE)
+	prec = GET_MODE_BITSIZE (TYPE_MODE (etype));
+      else
+	prec = TYPE_PRECISION (etype);
       if (prec <= HOST_BITS_PER_WIDE_INT)
 	{
 	  hi = 0;
--- gcc/testsuite/g++.dg/opt/range-test-1.C.jj	2004-06-19 00:38:06.000000000 +0200
+++ gcc/testsuite/g++.dg/opt/range-test-1.C	2004-07-09 18:06:27.501797366 +0200
@@ -176,6 +176,9 @@ T(24, signed char, x == SCHAR_MIN || x =
 T(25, integers, x == int_smallest || x == int_largest,
   { int_smallest C int_largest }, { int_minus1 C int_zero C int_one
     C int_2ndsmallest C int_2ndlargest C int_3rdsmallest C int_3rdlargest })
+T(26, enum3, x == enum3_one || x == enum3_two || x == enum3_three,
+  { enum3_one C enum3_two C enum3_three }, { enum3_zero C enum3_four
+    C enum3_five C enum3_six C enum3_seven })
 
 /* These should be optimized into unconditional jumps.  */
 T(o1, unsigned long, x <= 16 || (x >= 17 && x <= -1UL),

	Jakub


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