fix java interpreter on alpha

Richard Henderson rth@twiddle.net
Tue Sep 23 06:19:00 GMT 2003


Problem here is that c++ sets the precision of the enum to the minimum
number of bits required to represent it (8), but sets the mode to SImode
in order to preserve the ABI.  On Alpha, we prefer to store SImode values
in DImode registers, sign extended.  So store_expr looks at the extension
on the subreg, and tries to find a better mode to do the store in.  The
code here in c_common_signed_or_unsigned_type decides that, because of the
precision, the value can be loaded from a "signed char".  Which results 
in the unsigned enum value being sign-extended.

We're back to 3 java failures, instead of a hundred or more.


r~


        * c-common.c (c_common_signed_or_unsigned_type): Examine mode,
        not precision.
        * g++.dg/opt/enum1.C: New.

Index: c-common.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.c,v
retrieving revision 1.458
diff -c -p -d -r1.458 c-common.c
*** c-common.c	21 Sep 2003 05:07:06 -0000	1.458
--- c-common.c	23 Sep 2003 06:02:18 -0000
*************** c_common_signed_or_unsigned_type (int un
*** 1982,2013 ****
        || TREE_UNSIGNED (type) == unsignedp)
      return type;
  
!   if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node))
      return unsignedp ? unsigned_char_type_node : signed_char_type_node;
!   if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))
      return unsignedp ? unsigned_type_node : integer_type_node;
!   if (TYPE_PRECISION (type) == TYPE_PRECISION (short_integer_type_node))
      return unsignedp ? short_unsigned_type_node : short_integer_type_node;
!   if (TYPE_PRECISION (type) == TYPE_PRECISION (long_integer_type_node))
      return unsignedp ? long_unsigned_type_node : long_integer_type_node;
!   if (TYPE_PRECISION (type) == TYPE_PRECISION (long_long_integer_type_node))
      return (unsignedp ? long_long_unsigned_type_node
  	    : long_long_integer_type_node);
!   if (TYPE_PRECISION (type) == TYPE_PRECISION (widest_integer_literal_type_node))
      return (unsignedp ? widest_unsigned_literal_type_node
  	    : widest_integer_literal_type_node);
  
  #if HOST_BITS_PER_WIDE_INT >= 64
!   if (TYPE_PRECISION (type) == TYPE_PRECISION (intTI_type_node))
      return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
  #endif
!   if (TYPE_PRECISION (type) == TYPE_PRECISION (intDI_type_node))
      return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
!   if (TYPE_PRECISION (type) == TYPE_PRECISION (intSI_type_node))
      return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
!   if (TYPE_PRECISION (type) == TYPE_PRECISION (intHI_type_node))
      return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
!   if (TYPE_PRECISION (type) == TYPE_PRECISION (intQI_type_node))
      return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
  
    return type;
--- 1982,2018 ----
        || TREE_UNSIGNED (type) == unsignedp)
      return type;
  
!   /* Must check the mode of the types, not the precision.  Enumeral types
!      in C++ have precision set to match their range, but may use a wider
!      mode to match an ABI.  If we change modes, we may wind up with bad
!      conversions.  */
! 
!   if (TYPE_MODE (type) == TYPE_MODE (signed_char_type_node))
      return unsignedp ? unsigned_char_type_node : signed_char_type_node;
!   if (TYPE_MODE (type) == TYPE_MODE (integer_type_node))
      return unsignedp ? unsigned_type_node : integer_type_node;
!   if (TYPE_MODE (type) == TYPE_MODE (short_integer_type_node))
      return unsignedp ? short_unsigned_type_node : short_integer_type_node;
!   if (TYPE_MODE (type) == TYPE_MODE (long_integer_type_node))
      return unsignedp ? long_unsigned_type_node : long_integer_type_node;
!   if (TYPE_MODE (type) == TYPE_MODE (long_long_integer_type_node))
      return (unsignedp ? long_long_unsigned_type_node
  	    : long_long_integer_type_node);
!   if (TYPE_MODE (type) == TYPE_MODE (widest_integer_literal_type_node))
      return (unsignedp ? widest_unsigned_literal_type_node
  	    : widest_integer_literal_type_node);
  
  #if HOST_BITS_PER_WIDE_INT >= 64
!   if (TYPE_MODE (type) == TYPE_MODE (intTI_type_node))
      return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
  #endif
!   if (TYPE_MODE (type) == TYPE_MODE (intDI_type_node))
      return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
!   if (TYPE_MODE (type) == TYPE_MODE (intSI_type_node))
      return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
!   if (TYPE_MODE (type) == TYPE_MODE (intHI_type_node))
      return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
!   if (TYPE_MODE (type) == TYPE_MODE (intQI_type_node))
      return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
  
    return type;
Index: testsuite/g++.dg/opt/enum1.C
===================================================================
RCS file: testsuite/g++.dg/opt/enum1.C
diff -N testsuite/g++.dg/opt/enum1.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/opt/enum1.C	23 Sep 2003 06:02:18 -0000
***************
*** 0 ****
--- 1,30 ----
+ // Verify that we don't confuse precision and mode for enums.
+ // { dg-do run }
+ // { dg-options "-O" }
+ 
+ extern "C" void abort();
+ 
+ enum E {
+   zero = 0, 
+   test = 0xbb
+ };
+ 
+ static bool foo(unsigned char *x)
+ {
+   E e = static_cast<E>(*x);
+   switch (e)
+     {
+     case test:
+       return true;
+     default:
+       return false;
+     }
+ }
+ 
+ int main()
+ {
+   unsigned char dummy = test;
+   if (! foo(&dummy))
+     abort ();
+   return 0;
+ }



More information about the Gcc-patches mailing list