testcase for hppa64 gcc bug
Alan Modra
alan@linuxcare.com.au
Mon, 30 Oct 2000 18:04:44 +1100 (EST)
On Fri, 27 Oct 2000, Alan Modra wrote:
> char *f3 (char *a, char *b)
> {
> char *c = 0;
>
> if (f1 (&b) != 0)
> goto out;
>
> /* hppa64 passes bogus value for b */
> f2 (b, &c);
>
> out:
> return c;
> }
I think I know what's going on here. The root of the problem is that
pa-64.h defines an ARG_POINTER_REGNUM that isn't a fixed reg, and isn't
eliminable. The arg_pointer isn't even a call-saved reg. That breaks a
number of places in the compiler.
So I went down the path of trying to fix things properly by defining
ELIMINABLE_REGS and so on, but I ended in a maze of twisty little passages
labelled "Unrecognizable instruction", like this one:
/src/parisc/gcc/gcc/libgcc2.c: In function `__moddi3':
/src/parisc/gcc/gcc/libgcc2.c:601: Unrecognizable insn:
(insn 1289 209 1298 (set (reg:SI 50 %fr22)
(subreg:SI (plus:DI (reg:DI 30 %r30)
(const_int -272 [0xfffffef0])) 0)) -1 (nil)
(nil))
/src/parisc/gcc/gcc/libgcc2.c:601: Internal compiler error in
extract_insn, at recog.c:2134
Anyway, this hack seems to fix it for me.
* rtl.h (ARG_POINTER_INVARIANT): Define as 1 if undef.
* rtlanal.c (rtx_unstable_p): Qualify arg_pointer_rtx match with
ARG_POINTER_INVARIANT.
(rtx_varies_p): Likewise.
(rtx_addr_can_trap_p): Likewise.
* local-alloc.c (function_invariant_p): Likewise.
* loop.c (loop_invariant_p): Likewise.
* tm.texi (ARG_POINTER_INVARIANT): Describe.
Alan Modra
--
Linuxcare. Support for the Revolution.
Index: gcc/local-alloc.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/local-alloc.c,v
retrieving revision 1.72
diff -u -p -r1.72 local-alloc.c
--- gcc/local-alloc.c 2000/10/23 18:42:52 1.72
+++ gcc/local-alloc.c 2000/10/30 03:57:35
@@ -780,10 +780,12 @@ function_invariant_p (x)
{
if (CONSTANT_P (x))
return 1;
- if (x == frame_pointer_rtx || x == arg_pointer_rtx)
+ if (x == frame_pointer_rtx
+ || (ARG_POINTER_INVARIANT && x == arg_pointer_rtx))
return 1;
if (GET_CODE (x) == PLUS
- && (XEXP (x, 0) == frame_pointer_rtx || XEXP (x, 0) == arg_pointer_rtx)
+ && (XEXP (x, 0) == frame_pointer_rtx
+ || (ARG_POINTER_INVARIANT && XEXP (x, 0) == arg_pointer_rtx))
&& CONSTANT_P (XEXP (x, 1)))
return 1;
return 0;
Index: gcc/loop.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/loop.c,v
retrieving revision 1.293
diff -u -p -r1.293 loop.c
--- gcc/loop.c 2000/10/21 12:12:07 1.293
+++ gcc/loop.c 2000/10/30 03:58:24
@@ -3038,7 +3038,7 @@ loop_invariant_p (loop, x)
since the reg might be set by initialization within the loop. */
if ((x == frame_pointer_rtx || x == hard_frame_pointer_rtx
- || x == arg_pointer_rtx)
+ || (ARG_POINTER_INVARIANT && x == arg_pointer_rtx))
&& ! current_function_has_nonlocal_goto)
return 1;
Index: gcc/rtl.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/rtl.h,v
retrieving revision 1.228
diff -u -p -r1.228 rtl.h
--- gcc/rtl.h 2000/10/16 16:24:54 1.228
+++ gcc/rtl.h 2000/10/30 04:03:31
@@ -1504,6 +1504,10 @@ extern rtx global_rtl[GR_MAX];
#define hard_frame_pointer_rtx (global_rtl[GR_HARD_FRAME_POINTER])
#define arg_pointer_rtx (global_rtl[GR_ARG_POINTER])
+#ifndef ARG_POINTER_INVARIANT
+#define ARG_POINTER_INVARIANT 1
+#endif
+
extern rtx pic_offset_table_rtx;
extern rtx struct_value_rtx;
extern rtx struct_value_incoming_rtx;
Index: gcc/rtlanal.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/rtlanal.c,v
retrieving revision 1.74
diff -u -p -r1.74 rtlanal.c
--- gcc/rtlanal.c 2000/10/24 23:01:11 1.74
+++ gcc/rtlanal.c 2000/10/30 04:03:51
@@ -71,7 +71,8 @@ rtx_unstable_p (x)
case REG:
/* As in rtx_varies_p, we have to use the actual rtx, not reg number. */
if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
- || x == arg_pointer_rtx || RTX_UNCHANGING_P (x))
+ || (ARG_POINTER_INVARIANT && x == arg_pointer_rtx)
+ || RTX_UNCHANGING_P (x))
return 0;
#ifndef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
/* ??? When call-clobbered, the value is stable modulo the restore
@@ -144,7 +145,7 @@ rtx_varies_p (x)
eliminated the frame and/or arg pointer and are using it
for pseudos. */
if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
- || x == arg_pointer_rtx)
+ || (ARG_POINTER_INVARIANT && x == arg_pointer_rtx))
return 0;
#ifndef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
/* ??? When call-clobbered, the value is stable modulo the restore
@@ -209,7 +210,8 @@ rtx_addr_can_trap_p (x)
case REG:
/* As in rtx_varies_p, we have to use the actual rtx, not reg number. */
return ! (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
- || x == stack_pointer_rtx || x == arg_pointer_rtx);
+ || (ARG_POINTER_INVARIANT && x == arg_pointer_rtx)
+ || x == stack_pointer_rtx);
case CONST:
return rtx_addr_can_trap_p (XEXP (x, 0));
Index: gcc/tm.texi
===================================================================
RCS file: /cvs/gcc/egcs/gcc/tm.texi,v
retrieving revision 1.149
diff -u -p -r1.149 tm.texi
--- gcc/tm.texi 2000/10/18 17:51:54 1.149
+++ gcc/tm.texi 2000/10/30 04:06:49
@@ -2564,7 +2564,12 @@ register this is. On other machines, yo
wish for this purpose. If this is not the same register as the frame
pointer register, then you must mark it as a fixed register according to
@code{FIXED_REGISTERS}, or arrange to be able to eliminate it
-(@pxref{Elimination}).
+(@pxref{Elimination}), or clear ARG_POINTER_INVARIANT
+
+@findex ARG_POINTER_INVARIANT
+@item ARG_POINTER_INVARIANT
+ARG_POINTER_INVARIANT allows the compiler to assume that
+ARG_POINTER_REGNUM is unchanging over the life of a function.
@findex RETURN_ADDRESS_POINTER_REGNUM
@item RETURN_ADDRESS_POINTER_REGNUM
Index: gcc/config/pa/pa-64.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/pa/pa-64.h,v
retrieving revision 1.3
diff -u -p -r1.3 pa-64.h
--- gcc/config/pa/pa-64.h 2000/09/25 13:39:45 1.3
+++ gcc/config/pa/pa-64.h 2000/10/30 04:30:51
@@ -129,6 +129,7 @@ do { \
#undef ARGS_GROW_DOWNWARD
#undef ARG_POINTER_REGNUM
#define ARG_POINTER_REGNUM 29
+#define ARG_POINTER_INVARIANT 0
#undef STATIC_CHAIN_REGNUM
#define STATIC_CHAIN_REGNUM 31