Consider this sample code:

        x = foo[i];

when pointers are larger than integers and size_t [*], we compute the
offset (i) and extend it to pointer size.  However, there's no check
to see if a sign or zero extension should be used.  If the offset is
unsigned (say, i is "unsigned int") it sign extends it anyway,
resulting in an incorrect offset.  Does it make sense to check for
signed vs unsigned offsets and pass the right flag to convert_to_mode?
This results in smaller code on m32c, where HI moves to address
registers (PSI) are zero extended.

Alternately, we should at least use the POINTERS_EXTEND_UNSIGNED
*value* in convert_to_mode.

[*] There aren't any pointer-sized math operations on m32c, just SI
    and HI sized ones.  Pointers are 24 bits.  Thus, pointers and
    addresses are 24 bits, but no single data item can exceed 64k, so
    offsets are 16 bits.

Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.814
diff -p -U3 -r1.814 expr.c
--- expr.c      1 Sep 2005 01:06:45 -0000       1.814
+++ expr.c      2 Sep 2005 05:01:10 -0000
@@ -7210,6 +7210,7 @@ expand_expr_real_1 (tree exp, rtx target
 
        if (offset != 0)
          {
+           int unsigned_p = TYPE_UNSIGNED (TREE_TYPE (offset));
            rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode,
                                          EXPAND_SUM);
 
@@ -7217,10 +7218,10 @@ expand_expr_real_1 (tree exp, rtx target
 
 #ifdef POINTERS_EXTEND_UNSIGNED
            if (GET_MODE (offset_rtx) != Pmode)
-             offset_rtx = convert_to_mode (Pmode, offset_rtx, 0);
+             offset_rtx = convert_to_mode (Pmode, offset_rtx, unsigned_p);
 #else
            if (GET_MODE (offset_rtx) != ptr_mode)
-             offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
+             offset_rtx = convert_to_mode (ptr_mode, offset_rtx, unsigned_p);
 #endif
 
            if (GET_MODE (op0) == BLKmode

Reply via email to