testcase for hppa64 gcc bug
John David Anglin
dave@hiauly1.hia.nrc.ca
Thu, 9 Nov 2000 12:39:57 -0500 (EST)
> > 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
>
> I am making progress in trying to make the arg_pointer register eliminable.
> I have fixed the above problem. What was happening was that reload_as_needed
> was incorrectly trying to eliminate the return from millicode calls which
> is also register r29. I have figured out how to hide it from reload with
> unspec.
>
> However, the compiler is now too good at eliminating the arg_pointer. At
> -O3, it completely eliminates the arg_pointer. However, as I read the ABI,
> the call must always set the arg_pointer before calls.
For the record, here is my final patch regarding making the arg_pointer
eliminable for TARGET_64BIT. I think the code it generates is correct but
it hasn't been extensively tested. However, I don't recommend it for
installation since in comparing the assembler code generated with and
without elimination for a couple of test cases, I didn't observe any
significant improvement in the code with the patch. Possibly, the patch
implicitly disables elimination when the arg_pointer is needed.
I do find that Alan Modra's ARG_POINTER_INVARIANT patch needs to be installed
to get correct code with his test case.
There is one part of the patch below which I think needs to be installed.
That is
(call, call_value): Always USE the arg_pointer for TARGET_64BIT.
The use for the arg_pointer needs to be pulled out of the `if (flag_pic)'.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
2000-11-07 John David Anglin <dave@hiauly1.hia.nrc.ca>
* pa-linux64.h (ARG_POINTER_INVARIANT): Define even when the
arg_pointer is being eliminated.
(ELIMINABLE_REGS): Enable elimination of the arg_pointer.
(INITIAL_ELIMINATION_OFFSET): Revise offsets for arg_pointer.
* pa.md (mulsi3, divsi3, udivsi3, modsi3, umodsi3 and
canonicalize_funcptr_for_compare): Put "(reg:SI 26)" inside
unspec to prevent elimination.
(call, call_value): Always USE the arg_pointer for TARGET_64BIT.
Use the new addmovdi3 insn to load the arg_pointer register.
(addmovdi3 and mov_from_r29_si): New insn and expand which prevent
r29 from being eliminated in call setups and millicode returns.
--- pa-linux64.h.orig Tue Oct 31 18:38:24 2000
+++ pa-linux64.h Tue Nov 7 12:17:12 2000
@@ -209,21 +209,18 @@
that grow to lower addresses. What fun. */
#undef ARGS_GROW_DOWNWARD
#undef ARG_POINTER_REGNUM
-#define ARG_POINTER_INVARIANT 0
#define ARG_POINTER_REGNUM 29
+#define ARG_POINTER_INVARIANT 0
#undef STATIC_CHAIN_REGNUM
#define STATIC_CHAIN_REGNUM 31
-#if 1
-#define ARG_POINTER_INVARIANT 0
-#else
-/* If defined, this macro specifies a table of register pairs used to eliminate
- unneeded registers that point into the stack frame. */
+/* If defined, this macro specifies a table of register pairs used to
+ eliminate unneeded registers that point into the stack frame. */
#define ELIMINABLE_REGS \
{ \
- {ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ {ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
}
@@ -240,19 +237,18 @@
#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
do \
{ \
- int fsize; \
+ int fsize = compute_frame_size (get_frame_size (), 0); \
\
if ((TO) == FRAME_POINTER_REGNUM \
&& (FROM) == ARG_POINTER_REGNUM) \
{ \
- (OFFSET) = - current_function_pretend_args_size - 16; \
+ (OFFSET) = fsize + 48 - current_function_outgoing_args_size; \
break; \
} \
\
if ((TO) != STACK_POINTER_REGNUM) \
abort (); \
\
- fsize = compute_frame_size (get_frame_size (), 0); \
switch (FROM) \
{ \
case FRAME_POINTER_REGNUM: \
@@ -260,14 +256,13 @@
break; \
\
case ARG_POINTER_REGNUM: \
- (OFFSET) = - fsize - current_function_pretend_args_size - 16; \
+ (OFFSET) = 48 - current_function_outgoing_args_size; \
break; \
\
default: \
abort (); \
} \
} while (0)
-#endif
#undef SELECT_RTX_SECTION
#define SELECT_RTX_SECTION(MODE,RTX) \
--- pa.md.orig Tue Nov 7 13:50:34 2000
+++ pa.md.work Wed Nov 8 14:06:05 2000
@@ -3993,7 +3993,7 @@
(clobber (reg:SI 26))
(clobber (reg:SI 25))
(clobber (reg:SI 31))])
- (set (match_operand:SI 0 "general_operand" "") (reg:SI 29))]
+ (set (match_operand:SI 0 "general_operand" "") (unspec:SI [(reg:SI 29)] 0))]
""
"
{
@@ -4139,7 +4139,7 @@
(clobber (reg:SI 26))
(clobber (reg:SI 25))
(clobber (reg:SI 31))])
- (set (match_operand:SI 0 "general_operand" "") (reg:SI 29))]
+ (set (match_operand:SI 0 "general_operand" "") (unspec:SI [(reg:SI 29)] 0))]
""
"
{
@@ -4197,7 +4197,7 @@
(clobber (reg:SI 26))
(clobber (reg:SI 25))
(clobber (reg:SI 31))])
- (set (match_operand:SI 0 "general_operand" "") (reg:SI 29))]
+ (set (match_operand:SI 0 "general_operand" "") (unspec:SI [(reg:SI 29)] 0))]
""
"
{
@@ -4255,7 +4255,7 @@
(clobber (reg:SI 26))
(clobber (reg:SI 25))
(clobber (reg:SI 31))])
- (set (match_operand:SI 0 "general_operand" "") (reg:SI 29))]
+ (set (match_operand:SI 0 "general_operand" "") (unspec:SI [(reg:SI 29)] 0))]
""
"
{
@@ -4310,7 +4310,7 @@
(clobber (reg:SI 26))
(clobber (reg:SI 25))
(clobber (reg:SI 31))])
- (set (match_operand:SI 0 "general_operand" "") (reg:SI 29))]
+ (set (match_operand:SI 0 "general_operand" "") (unspec:SI [(reg:SI 29)] 0))]
""
"
{
@@ -5785,9 +5785,9 @@
op = XEXP (operands[0], 0);
if (TARGET_64BIT)
- emit_move_insn (arg_pointer_rtx,
- gen_rtx_PLUS (word_mode, virtual_outgoing_args_rtx,
- GEN_INT (64)));
+ emit_insn (gen_addmovdi3 (arg_pointer_rtx,
+ virtual_outgoing_args_rtx,
+ GEN_INT (64)));
/* Use two different patterns for calls to explicitly named functions
and calls through function pointers. This is necessary as these two
@@ -5809,13 +5809,14 @@
call_insn = emit_call_insn (gen_call_internal_reg (operands[1]));
}
+ if (TARGET_64BIT)
+ use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), arg_pointer_rtx);
+
if (flag_pic)
{
use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn),
gen_rtx_REG (word_mode, PIC_OFFSET_TABLE_REGNUM_SAVED));
- if (TARGET_64BIT)
- use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), arg_pointer_rtx);
/* After each call we must restore the PIC register, even if it
doesn't appear to be used.
@@ -5961,9 +5962,9 @@
op = XEXP (operands[1], 0);
if (TARGET_64BIT)
- emit_move_insn (arg_pointer_rtx,
- gen_rtx_PLUS (word_mode, virtual_outgoing_args_rtx,
- GEN_INT (64)));
+ emit_insn (gen_addmovdi3 (arg_pointer_rtx,
+ virtual_outgoing_args_rtx,
+ GEN_INT (64)));
/* Use two different patterns for calls to explicitly named functions
and calls through function pointers. This is necessary as these two
@@ -5989,6 +5990,10 @@
call_insn = emit_call_insn (gen_call_value_internal_reg (operands[0],
operands[2]));
}
+
+ if (TARGET_64BIT)
+ use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), arg_pointer_rtx);
+
if (flag_pic)
{
use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
@@ -7124,7 +7129,7 @@
(clobber (reg:SI 22))
(clobber (reg:SI 31))])
(set (match_operand:SI 0 "register_operand" "")
- (reg:SI 29))]
+ (unspec:SI [(reg:SI 29)] 0))]
"! TARGET_PORTABLE_RUNTIME && !TARGET_64BIT && !TARGET_ELF32"
"
{
@@ -7236,3 +7241,48 @@
emit_insn (gen_blockage ());
DONE;
}")
+
+;; For TARGET_64BIT, the arg_pointer register is also used for millicode
+;; returns. The ABI requires that the arg_pointer be set for all calls.
+;; When the arg_pointer is made an eliminable register, eliminate_regs
+;; will eliminate the arg_pointer register from the function call setup and
+;; millicode returns unless the arg_pointer is hidden in a use, clobber or
+;; unspec.
+
+;; This is for loading the arg_pointer in function calls.
+(define_insn "addmovdi3"
+ [(set (unspec:DI [(match_operand:DI 0 "register_operand" "=r,r")] 0)
+ (plus:DI (match_operand:DI 1 "register_operand" "r,r")
+ (match_operand 2 "const_int_operand" "J,i")))
+ (set (match_dup 0) (match_dup 0))]
+ "TARGET_64BIT"
+ "@
+ ldo %2(%1),%0
+ ldil L'%G2,%0\;add,l %0,%1,%0"
+ [(set_attr "type" "binary,binary")
+ (set_attr "pa_combine_type" "addmove,none")
+ (set_attr "length" "4,8")])
+
+;; This is for millicode return.
+(define_expand "mov_from_r29_si"
+ [(set (match_operand:SI 0 "" "")
+ (unspec:SI [(reg:SI 29)] 0))]
+ ""
+ "
+{
+ if (!TARGET_64BIT)
+ {
+ rtx tmp = gen_rtx_REG (SImode, 29);
+ emit_insn (gen_movsi (operands[0], tmp));
+ DONE;
+ }
+}")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(reg:SI 29)] 0))]
+ ""
+ "copy %%r29,%0"
+ [(set_attr "type" "multi")
+ (set_attr "length" "4")])
+