Patch: Alpha32 POINTERS_EXTEND_UNSIGNED doesn't quite work right. -- take 2

Donn Terry donn@interix.com
Mon May 31 20:56:00 GMT 1999


===================================================
Donn Terry                  mailto:donn@interix.com
Softway Systems, Inc.        http://www.interix.com
2850 McClelland Dr, Ste. 1800   Ft.Collins CO 80525
Tel: +1-970-204-9900           Fax: +1-970-204-9951
===================================================
Problem: Alpha32 POINTERS_EXTEND_UNSIGNED doesn't quite work right.  Take 2.

RTH submitted a fix for the above problem, which propigated
POINTERS_EXTEND_UNSIGNED into the pointer type.  That patch exposed
the latent bug below. 

This patch and RTH's patch were originally submitted together.  However,
RTH's patch may not prove applicable.  This patch remains valid,
although it may be that RTH's original patch is the only known way to cause
the bug to actually occur. 

This patch should be in place before RTH's is applied, to avoid a 
very unpretty compiler crash.

Details:
The RTH fix alone exposes a latent problem with an infinite recursion in
convert.c/c-convert.c.  (Subtitle, as suggested by a friend: lather,
rinse, repeat.)

    pointer_diff() calls convert (while setting up the MINUS).
    The operand being converted is an Alpha32 pointer (signed SI).
    (Other calls trigger the same problem.)

    Lather:
    Convert checks for various no-ops and then calls convert_to_integer.
    Convert to integer determines that it's converting from a
    pointer, and does expr=fold(build1(CONVERT...).

    That call to fold does nothing, and expr is returned as CONVERT.
    Convert_to_integer then calls itself with expr (now an integer
    because of the convert).

    This call to convert_to_integer determines that it has an
    integer and after checking that the current operation is not
    one of a few special cases determines if it is narrowing or
    widening the type.  If it's widening it (or it's a no-size-change)
    it converts this to a NOP_EXPR (so now we have NOP_EXPR(CONVERT(ptr...  ).

    Here we return to the outer convert_to_integer() which returns
    immediately to the original call in convert which is
    fold(convert_to_integer....

    Rinse:

    fold determines that this is NOP_EXPR(CONVERT(.... and treats
    that as a special case, see "Handle cases of two conversions
    in a row".  This ends up taking the branch where it discards
    the intermediate converison, Resulting in the object

    contained two levels down in the NOP_EXPR, which our original
    argument to convert, unmodified. 

    Repeat:

    convert() is then called on the resulting (unmodified) object.
    At this point, we recurse.

To break the recursion, we note that the "Handle cases..." code can
have the effect of undoing a conversion from a pointer to an integer
or vice-versa (because it treats pointers and integers equivalently).
If it is going to undo a conversion sequence that has a pointer on
one end and an integer on the other, don't allow that.

Fix: test for a change in type in fold().  (Note, the code there could
be hand-optimized a little, but this more clearly expresses the intent.)

Sun May 9 21:05:41 1999 Donn Terry (donn@interix.com)

	* fold-const.c (fold): Break recursion: pointer <-> integer
	conversion should not be undone by fold.
	  
diff -urP egcs.source.old/gcc/fold-const.c egcs.source/gcc/fold-const.c
--- egcs.source.old/gcc/fold-const.c	Fri Apr  9 10:02:46 1999
+++ egcs.source/gcc/fold-const.c	Mon May  3 10:18:37 1999
@@ -4550,7 +4550,8 @@ fold (expr) 
 	      && (inter_float || inter_unsignedp == inside_unsignedp)
 	      && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (final_type))
 		    && TYPE_MODE (final_type) == TYPE_MODE (inter_type))
-	      && ! final_ptr)
+	      && ! final_ptr
+	      && final_ptr == inside_ptr)
 	    return convert (final_type, TREE_OPERAND (TREE_OPERAND (t, 0), 0));
 
 	  /* If we have a sign-extension of a zero-extended value, we can
@@ -4581,7 +4582,8 @@ fold (expr) 
 	      && ! (final_ptr && inside_prec != inter_prec)
 	      && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (final_type))
 		    && TYPE_MODE (final_type) == TYPE_MODE (inter_type))
-	      && ! final_ptr)
+	      && ! final_ptr
+	      && final_ptr == inside_ptr)
 	    return convert (final_type, TREE_OPERAND (TREE_OPERAND (t, 0), 0));
 	}
 


More information about the Gcc-patches mailing list