This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Fix for short-enums comparison bug
- To: Gavin Romig-Koch <gavin at cygnus dot com>
- Subject: Re: [PATCH] Fix for short-enums comparison bug
- From: Charles G Waldman <cgw at alum dot mit dot edu>
- Date: Thu, 11 Feb 1999 11:10:20 -0500 (EST)
- Cc: law at cygnus dot com, Charles G Waldman <cgw at alum dot MIT dot EDU>, egcs at egcs dot cygnus dot com
- References: <x490ee6l2e.fsf@janus.pgt.com><4691.918719200@hurl.cygnus.com><14018.60839.325601.426391@cetus.cygnus.com>
Gavin Romig-Koch writes:
> It looks like GCC is choosing unsigned char for this particular enum
> with -fshort-enums, which is ok standard-wise. Given this though,
> I don't see why this example shouldn't work the same as it does without
> -fshort-enums.
I tried to explain this in my original posting.
Please see the block of code in the function shorten_compare (in
c-common.c) starting at line 2258 (in the egcs-1.1.1 release), which
for your convenience I've appended below.
In gcc-2.7.x the call to signed_or_unsigned_type (see ***) returned
the underlying integral type, but the following change:
Mon Oct 28 13:08:51 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
(signed_or_unsigned_type): If already right signedness, return.
caused signed_or_unsigned_type to return the enumerated type itself
rather than the underlying integral type.
Thus maxval and minval refer to the maximum and minimum of the
declared enum values rather than of the underlying integral type, and
the subsequent logic optimizes away the comparison.
My proposed patch fixes this.
--------------------------------------------
Excerpt from shorten_compare(c_common.c):
/* If comparing an integer against a constant more bits wide,
maybe we can deduce a value of 1 or 0 independent of the data.
Or else truncate the constant now
rather than extend the variable at run time.
This is only interesting if the constant is the wider arg.
Also, it is not safe if the constant is unsigned and the
variable arg is signed, since in this case the variable
would be sign-extended and then regarded as unsigned.
Our technique fails in this case because the lowest/highest
possible unsigned results don't follow naturally from the
lowest/highest possible values of the variable operand.
For just EQ_EXPR and NE_EXPR there is another technique that
could be used: see if the constant can be faithfully represented
in the other operand's type, by truncating it and reextending it
and see if that preserves the constant's value. */
if (!real1 && !real2
&& TREE_CODE (primop1) == INTEGER_CST
&& TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr))
{
int min_gt, max_gt, min_lt, max_lt;
tree maxval, minval;
/* 1 if comparison is nominally unsigned. */
int unsignedp = TREE_UNSIGNED (*restype_ptr);
tree val;
[***] type = signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0));
maxval = TYPE_MAX_VALUE (type);
minval = TYPE_MIN_VALUE (type);
if (unsignedp && !unsignedp0)
*restype_ptr = signed_type (*restype_ptr);
if (TREE_TYPE (primop1) != *restype_ptr)
primop1 = convert (*restype_ptr, primop1);
if (type != *restype_ptr)
{
minval = convert (*restype_ptr, minval);
maxval = convert (*restype_ptr, maxval);
}
if (unsignedp && unsignedp0)
{
min_gt = INT_CST_LT_UNSIGNED (primop1, minval);
max_gt = INT_CST_LT_UNSIGNED (primop1, maxval);
min_lt = INT_CST_LT_UNSIGNED (minval, primop1);
max_lt = INT_CST_LT_UNSIGNED (maxval, primop1);
}
else
{
min_gt = INT_CST_LT (primop1, minval);
max_gt = INT_CST_LT (primop1, maxval);
min_lt = INT_CST_LT (minval, primop1);
max_lt = INT_CST_LT (maxval, primop1);
}
val = 0;
/* This used to be a switch, but Genix compiler can't handle that. */
if (code == NE_EXPR)
{
if (max_lt || min_gt)
val = boolean_true_node;
}
else if (code == EQ_EXPR)
{
if (max_lt || min_gt)
val = boolean_false_node;
}
else if (code == LT_EXPR)
{
if (max_lt)
val = boolean_true_node;
if (!min_lt)
val = boolean_false_node;
}
else if (code == GT_EXPR)
{
if (min_gt)
val = boolean_true_node;
if (!max_gt)
val = boolean_false_node;
}
else if (code == LE_EXPR)
{
if (!max_gt)
val = boolean_true_node;
if (min_gt)
val = boolean_false_node;
}
else if (code == GE_EXPR)
{
if (!min_lt)
val = boolean_true_node;
if (max_lt)
val = boolean_false_node;
}