Hi, As reported in PR78255 there is currently an issue with indirect sibling calls in ARM when the address of the sibling call is loaded into 'r3' and that same register is chosen to align the stack. See the report for further information.
As I mentioned in the bugzilla ticket I am not sure this is the right approach, though it works... Bootstrapped on ARM and no regressions. Do you think this is OK? Another solution would be to make sure that 'arm_get_frame_offsets' recalculates offsets after we know that the call is going to be indirect, i.e. after we know the address is going to be loaded into a register, but I do not know what a sane way would be to ensure this. Regards, Andre gcc/ChangeLog 2016-11-10 Andre Vieira <andre.simoesdiasvie...@arm.com> * config/arm/arm.md (sibcall_internal): Add 'use' to pattern. (sibcall_value_internal): Likewise. (sibcall_insn): Likewise. (sibcall_value_insn): Likewise. gcc/testsuite/ChangeLog 2016-11-10 Andre Vieira <andre.simoesdiasvie...@arm.com> * gcc.target/arm/pr78255.c: New.
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 8393f65bcf4c9c3e61b91e5adcd5f59ff7c6ec3f..ab28b15f3e4ebbaca2b8ec0523493b54cce8c306 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -8192,7 +8192,8 @@ [(parallel [(call (match_operand 0 "memory_operand" "") (match_operand 1 "general_operand" "")) (return) - (use (match_operand 2 "" ""))])]) + (use (match_operand 2 "" "")) + (use (match_dup 0))])]) ;; We may also be able to do sibcalls for Thumb, but it's much harder... (define_expand "sibcall" @@ -8225,7 +8226,8 @@ (call (match_operand 1 "memory_operand" "") (match_operand 2 "general_operand" ""))) (return) - (use (match_operand 3 "" ""))])]) + (use (match_operand 3 "" "")) + (use (match_dup 1))])]) (define_expand "sibcall_value" [(parallel [(set (match_operand 0 "" "") @@ -8258,7 +8260,8 @@ [(call (mem:SI (match_operand:SI 0 "call_insn_operand" "Cs, US")) (match_operand 1 "" "")) (return) - (use (match_operand 2 "" ""))] + (use (match_operand 2 "" "")) + (use (match_operand 3 "" ""))] "TARGET_32BIT && SIBLING_CALL_P (insn)" "* if (which_alternative == 1) @@ -8279,7 +8282,8 @@ (call (mem:SI (match_operand:SI 1 "call_insn_operand" "Cs,US")) (match_operand 2 "" ""))) (return) - (use (match_operand 3 "" ""))] + (use (match_operand 3 "" "")) + (use (match_operand 4 "" ""))] "TARGET_32BIT && SIBLING_CALL_P (insn)" "* if (which_alternative == 1) diff --git a/gcc/testsuite/gcc.target/arm/pr78255.c b/gcc/testsuite/gcc.target/arm/pr78255.c new file mode 100644 index 0000000000000000000000000000000000000000..4901acea51466c0bac92d9cb90e52b00b450d88a --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/pr78255.c @@ -0,0 +1,57 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#include <string.h> + +struct table_s + { + void (*fun0) + ( void ); + void (*fun1) + ( void ); + void (*fun2) + ( void ); + void (*fun3) + ( void ); + void (*fun4) + ( void ); + void (*fun5) + ( void ); + void (*fun6) + ( void ); + void (*fun7) + ( void ); + } table; + +void callback0(){__asm("mov r0, r0 \n\t");} +void callback1(){__asm("mov r0, r0 \n\t");} +void callback2(){__asm("mov r0, r0 \n\t");} +void callback3(){__asm("mov r0, r0 \n\t");} +void callback4(){__asm("mov r0, r0 \n\t");} + +void test (void) { + memset(&table, 0, sizeof table); + + asm volatile ("" : : : "r3"); + + table.fun0 = callback0; + table.fun1 = callback1; + table.fun2 = callback2; + table.fun3 = callback3; + table.fun4 = callback4; + table.fun0(); +} + +void foo (void) +{ + __builtin_abort (); +} + +int main (void) +{ + unsigned long p = (unsigned long) &foo; + asm volatile ("mov r3, %0" : : "r" (p)); + test (); + + return 0; +}