From 9adcfa3c1f4f3194b50c893f06bb52f1058aebe8 Mon Sep 17 00:00:00 2001 From: Ramana Radhakrishnan Date: Wed, 15 May 2013 11:49:06 +0000 Subject: [PATCH] Fix PR target/19599 - tailcall function pointers. 2013-05-15 Ramana Radhakrishnan PR target/19599 * config/arm/predicates.md (call_insn_operand): New predicate. * config/arm/constraints.md ("Cs", "Ss"): New constraints. * config/arm/arm.md (*call_insn, *call_value_insn): Match only if insn is not a tail call. (*sibcall_insn, *sibcall_value_insn): Adjust for tailcalling through registers. * config/arm/arm.h (enum reg_class): New caller save register class. (REG_CLASS_NAMES): Likewise. (REG_CLASS_CONTENTS): Likewise. * config/arm/arm.c (arm_function_ok_for_sibcall): Allow tailcalling without decls. 2013-05-15 Ramana Radhakrishnan PR target/19599 * gcc.target/arm/pr40887.c: Adjust testcase. * gcc.target/arm/pr19599.c: New test. From-SVN: r198928 --- gcc/ChangeLog | 15 +++++++ gcc/config/arm/arm.c | 10 ++--- gcc/config/arm/arm.h | 3 ++ gcc/config/arm/arm.md | 57 +++++++++++++++++++------- gcc/config/arm/constraints.md | 9 ++++ gcc/config/arm/predicates.md | 4 ++ gcc/testsuite/ChangeLog | 6 +++ gcc/testsuite/gcc.target/arm/pr19599.c | 10 +++++ gcc/testsuite/gcc.target/arm/pr40887.c | 4 +- 9 files changed, 96 insertions(+), 22 deletions(-) create mode 100644 gcc/testsuite/gcc.target/arm/pr19599.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e0c5c322b72..4b6c6038989 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2013-05-15 Ramana Radhakrishnan + + PR target/19599 + * config/arm/predicates.md (call_insn_operand): New predicate. + * config/arm/constraints.md ("Cs", "Ss"): New constraints. + * config/arm/arm.md (*call_insn, *call_value_insn): Match only + if insn is not a tail call. + (*sibcall_insn, *sibcall_value_insn): Adjust for tailcalling through + registers. + * config/arm/arm.h (enum reg_class): New caller save register class. + (REG_CLASS_NAMES): Likewise. + (REG_CLASS_CONTENTS): Likewise. + * config/arm/arm.c (arm_function_ok_for_sibcall): Allow tailcalling + without decls. + 2013-05-15 Richard Biener * tree-vect-loop.c (vect_transform_loop): Use MSG_NOTE instead diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 170dcb70428..036db8ab6fb 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -5376,9 +5376,8 @@ arm_function_ok_for_sibcall (tree decl, tree exp) if (cfun->machine->sibcall_blocked) return false; - /* Never tailcall something for which we have no decl, or if we - are generating code for Thumb-1. */ - if (decl == NULL || TARGET_THUMB1) + /* Never tailcall something if we are generating code for Thumb-1. */ + if (TARGET_THUMB1) return false; /* The PIC register is live on entry to VxWorks PLT entries, so we @@ -5388,13 +5387,14 @@ arm_function_ok_for_sibcall (tree decl, tree exp) /* Cannot tail-call to long calls, since these are out of range of a branch instruction. */ - if (arm_is_long_call_p (decl)) + if (decl && arm_is_long_call_p (decl)) return false; /* If we are interworking and the function is not declared static then we can't tail-call it unless we know that it exists in this compilation unit (since it might be a Thumb routine). */ - if (TARGET_INTERWORK && TREE_PUBLIC (decl) && !TREE_ASM_WRITTEN (decl)) + if (TARGET_INTERWORK && decl && TREE_PUBLIC (decl) + && !TREE_ASM_WRITTEN (decl)) return false; func_type = arm_current_func_type (); diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index 46450b35440..3a49a90c184 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -1142,6 +1142,7 @@ enum reg_class STACK_REG, BASE_REGS, HI_REGS, + CALLER_SAVE_REGS, GENERAL_REGS, CORE_REGS, VFP_D0_D7_REGS, @@ -1168,6 +1169,7 @@ enum reg_class "STACK_REG", \ "BASE_REGS", \ "HI_REGS", \ + "CALLER_SAVE_REGS", \ "GENERAL_REGS", \ "CORE_REGS", \ "VFP_D0_D7_REGS", \ @@ -1193,6 +1195,7 @@ enum reg_class { 0x00002000, 0x00000000, 0x00000000, 0x00000000 }, /* STACK_REG */ \ { 0x000020FF, 0x00000000, 0x00000000, 0x00000000 }, /* BASE_REGS */ \ { 0x00005F00, 0x00000000, 0x00000000, 0x00000000 }, /* HI_REGS */ \ + { 0x0000100F, 0x00000000, 0x00000000, 0x00000000 }, /* CALLER_SAVE_REGS */ \ { 0x00005FFF, 0x00000000, 0x00000000, 0x00000000 }, /* GENERAL_REGS */ \ { 0x00007FFF, 0x00000000, 0x00000000, 0x00000000 }, /* CORE_REGS */ \ { 0xFFFF0000, 0x00000000, 0x00000000, 0x00000000 }, /* VFP_D0_D7_REGS */ \ diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 06b3c18a7f4..d3bc760952d 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -8889,7 +8889,7 @@ (match_operand 1 "" "")) (use (match_operand 2 "" "")) (clobber (reg:SI LR_REGNUM))] - "TARGET_ARM && arm_arch5" + "TARGET_ARM && arm_arch5 && !SIBLING_CALL_P (insn)" "blx%?\\t%0" [(set_attr "type" "call")] ) @@ -8899,7 +8899,7 @@ (match_operand 1 "" "")) (use (match_operand 2 "" "")) (clobber (reg:SI LR_REGNUM))] - "TARGET_ARM && !arm_arch5" + "TARGET_ARM && !arm_arch5 && !SIBLING_CALL_P (insn)" "* return output_call (operands); " @@ -8918,7 +8918,7 @@ (match_operand 1 "" "")) (use (match_operand 2 "" "")) (clobber (reg:SI LR_REGNUM))] - "TARGET_ARM && !arm_arch5" + "TARGET_ARM && !arm_arch5 && !SIBLING_CALL_P (insn)" "* return output_call_mem (operands); " @@ -8931,7 +8931,7 @@ (match_operand 1 "" "")) (use (match_operand 2 "" "")) (clobber (reg:SI LR_REGNUM))] - "TARGET_THUMB1 && arm_arch5" + "TARGET_THUMB1 && arm_arch5 && !SIBLING_CALL_P (insn)" "blx\\t%0" [(set_attr "length" "2") (set_attr "type" "call")] @@ -8942,7 +8942,7 @@ (match_operand 1 "" "")) (use (match_operand 2 "" "")) (clobber (reg:SI LR_REGNUM))] - "TARGET_THUMB1 && !arm_arch5" + "TARGET_THUMB1 && !arm_arch5 && !SIBLING_CALL_P (insn)" "* { if (!TARGET_CALLER_INTERWORKING) @@ -9001,7 +9001,7 @@ (match_operand 2 "" ""))) (use (match_operand 3 "" "")) (clobber (reg:SI LR_REGNUM))] - "TARGET_ARM && arm_arch5" + "TARGET_ARM && arm_arch5 && !SIBLING_CALL_P (insn)" "blx%?\\t%1" [(set_attr "type" "call")] ) @@ -9012,7 +9012,7 @@ (match_operand 2 "" ""))) (use (match_operand 3 "" "")) (clobber (reg:SI LR_REGNUM))] - "TARGET_ARM && !arm_arch5" + "TARGET_ARM && !arm_arch5 && !SIBLING_CALL_P (insn)" "* return output_call (&operands[1]); " @@ -9028,7 +9028,8 @@ (match_operand 2 "" ""))) (use (match_operand 3 "" "")) (clobber (reg:SI LR_REGNUM))] - "TARGET_ARM && !arm_arch5 && (!CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))" + "TARGET_ARM && !arm_arch5 && (!CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + && !SIBLING_CALL_P (insn)" "* return output_call_mem (&operands[1]); " @@ -9078,6 +9079,7 @@ (use (match_operand 2 "" "")) (clobber (reg:SI LR_REGNUM))] "TARGET_32BIT + && !SIBLING_CALL_P (insn) && (GET_CODE (operands[0]) == SYMBOL_REF) && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[0]))" "* @@ -9094,6 +9096,7 @@ (use (match_operand 3 "" "")) (clobber (reg:SI LR_REGNUM))] "TARGET_32BIT + && !SIBLING_CALL_P (insn) && (GET_CODE (operands[1]) == SYMBOL_REF) && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[1]))" "* @@ -9139,6 +9142,10 @@ "TARGET_32BIT" " { + if (!REG_P (XEXP (operands[0], 0)) + && (GET_CODE (XEXP (operands[0], 0)) != SYMBOL_REF)) + XEXP (operands[0], 0) = force_reg (SImode, XEXP (operands[0], 0)); + if (operands[2] == NULL_RTX) operands[2] = const0_rtx; }" @@ -9153,32 +9160,52 @@ "TARGET_32BIT" " { + if (!REG_P (XEXP (operands[1], 0)) && + (GET_CODE (XEXP (operands[1],0)) != SYMBOL_REF)) + XEXP (operands[1], 0) = force_reg (SImode, XEXP (operands[1], 0)); + if (operands[3] == NULL_RTX) operands[3] = const0_rtx; }" ) (define_insn "*sibcall_insn" - [(call (mem:SI (match_operand:SI 0 "" "X")) + [(call (mem:SI (match_operand:SI 0 "call_insn_operand" "Cs,Ss")) (match_operand 1 "" "")) (return) (use (match_operand 2 "" ""))] - "TARGET_32BIT && GET_CODE (operands[0]) == SYMBOL_REF" + "TARGET_32BIT && SIBLING_CALL_P (insn)" "* - return NEED_PLT_RELOC ? \"b%?\\t%a0(PLT)\" : \"b%?\\t%a0\"; + if (which_alternative == 1) + return NEED_PLT_RELOC ? \"b%?\\t%a0(PLT)\" : \"b%?\\t%a0\"; + else + { + if (arm_arch5 || arm_arch4t) + return \" bx\\t%0\\t%@ indirect register sibling call\"; + else + return \"mov%?\\t%|pc, %0\\t%@ indirect register sibling call\"; + } " [(set_attr "type" "call")] ) (define_insn "*sibcall_value_insn" - [(set (match_operand 0 "" "") - (call (mem:SI (match_operand:SI 1 "" "X")) + [(set (match_operand 0 "s_register_operand" "") + (call (mem:SI (match_operand:SI 1 "call_insn_operand" "Cs,Ss")) (match_operand 2 "" ""))) (return) (use (match_operand 3 "" ""))] - "TARGET_32BIT && GET_CODE (operands[1]) == SYMBOL_REF" + "TARGET_32BIT && SIBLING_CALL_P (insn)" "* - return NEED_PLT_RELOC ? \"b%?\\t%a1(PLT)\" : \"b%?\\t%a1\"; + if (which_alternative == 1) + return NEED_PLT_RELOC ? \"b%?\\t%a1(PLT)\" : \"b%?\\t%a1\"; + else + { + if (arm_arch5 || arm_arch4t) + return \"bx\\t%1\"; + else + return \"mov%?\\t%|pc, %1\\t@ indirect sibling call \"; + } " [(set_attr "type" "call")] ) diff --git a/gcc/config/arm/constraints.md b/gcc/config/arm/constraints.md index 767ebfb6080..7e7b3e69e0a 100644 --- a/gcc/config/arm/constraints.md +++ b/gcc/config/arm/constraints.md @@ -96,6 +96,9 @@ (define_register_constraint "c" "CC_REG" "@internal The condition code register.") +(define_register_constraint "Cs" "CALLER_SAVE_REGS" + "@internal The caller save registers. Useful for sibcalls.") + (define_constraint "I" "In ARM/Thumb-2 state a constant that can be used as an immediate value in a Data Processing instruction. In Thumb-1 state a constant in the range @@ -400,3 +403,9 @@ ;; Additionally, we used to have a Q constraint in Thumb state, but ;; this wasn't really a valid memory constraint. Again, all uses of ;; this now seem to have been removed. + +(define_constraint "Ss" + "@internal + Ss is a symbol reference." + (match_code "symbol_ref") +) diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md index 2e0de08a8d0..92de9fe8bd9 100644 --- a/gcc/config/arm/predicates.md +++ b/gcc/config/arm/predicates.md @@ -635,3 +635,7 @@ (define_predicate "mem_noofs_operand" (and (match_code "mem") (match_code "reg" "0"))) + +(define_predicate "call_insn_operand" + (ior (match_code "symbol_ref") + (match_operand 0 "s_register_operand"))) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 984ee6d5b17..d69fbd4e74f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2013-05-15 Ramana Radhakrishnan + + PR target/19599 + * gcc.target/arm/pr40887.c: Adjust testcase. + * gcc.target/arm/pr19599.c: New test. + 2013-05-15 Richard Biener PR tree-optimization/57275 diff --git a/gcc/testsuite/gcc.target/arm/pr19599.c b/gcc/testsuite/gcc.target/arm/pr19599.c new file mode 100644 index 00000000000..e3e066cf820 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/pr19599.c @@ -0,0 +1,10 @@ +/* { dg-skip-if "need at least armv5te" { *-*-* } { "-march=armv[234]*" } { "" } } */ +/* { dg-options "-O2 -march=armv5te -marm" } */ +/* { dg-final { scan-assembler "bx" } } */ + +int (*indirect_func)(); + +int indirect_call() +{ + return indirect_func(); +} diff --git a/gcc/testsuite/gcc.target/arm/pr40887.c b/gcc/testsuite/gcc.target/arm/pr40887.c index 0b5e873a5c9..5cabe3ab7fe 100644 --- a/gcc/testsuite/gcc.target/arm/pr40887.c +++ b/gcc/testsuite/gcc.target/arm/pr40887.c @@ -2,9 +2,9 @@ /* { dg-options "-O2 -march=armv5te" } */ /* { dg-final { scan-assembler "blx" } } */ -int (*indirect_func)(); +int (*indirect_func)(int x); int indirect_call() { - return indirect_func(); + return indirect_func(20) + indirect_func (40); } -- 2.30.2