This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
RFA: Add new (ARM) sibcall test case
- From: Nick Clifton <nickc at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: 17 Jan 2003 14:00:47 +0000
- Subject: RFA: Add new (ARM) sibcall test case
Hi Guys,
I would like permission to add a new test case to
gcc.c-torture/execute:
*** /dev/null Sat Oct 19 15:41:17 2002
--- gcc/testsuite/gcc.c-torture/execute/20030117-1.c Fri Jan 17 13:49:15 2003
***************
*** 0 ****
--- 1,23 ----
+ int foo (int, int, int);
+ int bar (int, int, int);
+
+ int main (void)
+ {
+ if (foo (5, 10, 21) != 12)
+ abort ();
+
+ if (bar (9, 12, 15) != 150)
+ abort ();
+
+ exit (0);
+ }
+
+ int foo (int x, int y, int z)
+ {
+ return (x + y + z) / 3;
+ }
+
+ int bar (int x, int y, int z)
+ {
+ return foo (x * x, y * y, z * z);
+ }
The test reveals a bug in the ARM code generator when the program is
compiled at -O3. The problem is that gcc decides to compile 'bar'
using a sibcall to 'foo', but it elects to use the link register as
a temporary register for the result of one of the multiplications:
bar:
mul ip, r1, r1
mov r1, ip
mul lr, r0, r0 <--- return address corrupted here
mul ip, r2, r2
mov r0, lr
mov r2, ip
b foo
The problem is that although the "sibcall_epilogue" pattern
generates an unspec_volatile, this only generates a USE of all of
the hardware registers. After reload, USEs are ignored, so the
second flow pass marks the link register as dead after the
prologue, and hence available for use in the body of the function.
The solution I intend to apply is to add an unspec usage of the link
register, using the UNSPEC_PROLOGUE_USE value, which is specifically
intended to protect hard registers after reload. Like this:
Index: gcc/config/arm/arm.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.md,v
retrieving revision 1.115
diff -c -3 -p -w -r1.115 arm.md
*** gcc/config/arm/arm.md 8 Jan 2003 11:55:50 -0000 1.115
--- gcc/config/arm/arm.md 17 Jan 2003 13:45:13 -0000
***************
*** 8430,8437 ****
"
)
(define_insn "sibcall_epilogue"
! [(unspec_volatile [(const_int 0)] VUNSPEC_EPILOGUE)]
"TARGET_ARM"
"*
if (USE_RETURN_INSN (FALSE))
--- 8430,8443 ----
"
)
+ ;; Note - although unspec_volatile's USE all hard registers,
+ ;; USEs are ignored after relaod has completed. Thus we need
+ ;; to add an unspec of the link register to ensure that flow
+ ;; does not think that it is unused by the sibcall branch that
+ ;; will replace the standard function epilogue.
(define_insn "sibcall_epilogue"
! [(parallel [(unspec:SI [(reg:SI LR_REGNUM)] UNSPEC_PROLOGUE_USE)
! (unspec_volatile [(const_int 0)] VUNSPEC_EPILOGUE)])]
"TARGET_ARM"
"*
if (USE_RETURN_INSN (FALSE))
So - may I add this test case ?
Cheers
Nick
PS. Relevent ChangeLog entries:
gcc/testsuite/ChangeLog
2003-01-17 Nick Clifton <nickc@redhat.com>
* gcc.c-torture/execute/20030117-1.c: New test case. Exposes
problem with ARM sibcall code generation.
gcc/ChangeLog
2003-01-17 Nick Clifton <nickc@redhat.com>
* config/arm/arm.md (sibcall_epilogue): Add an
UNSPEC_PROLOGUE_USE to prevent the link register from being
considered dead.