From cc48a87f9d1eae385269d87882517c183a06c383 Mon Sep 17 00:00:00 2001 From: Chung-Ju Wu Date: Wed, 4 Apr 2018 00:56:16 +0000 Subject: [PATCH] [NDS32] Refine implementation of sibcall patterns. gcc/ * config/nds32/nds32-md-auxiliary.c (nds32_long_call_p): New function. * config/nds32/nds32-protos.h (nds32_long_call_p): Declare. * config/nds32/nds32.c (nds32_function_ok_for_sibcall): New function. (TARGET_FUNCTION_OK_FOR_SIBCALL): Define. * config/nds32/nds32.md (sibcall_internal): New. (sibcall_register): Remove. (sibcall_immediate): Remove. (sibcall_value_internal): New. (sibcall_value_register): Remove. (sibcall_value_immediate): Remove. * config/nds32/predicates.md (nds32_general_register_operand): New. (nds32_call_address_operand): New. Co-Authored-By: Kito Cheng From-SVN: r259065 --- gcc/ChangeLog | 16 ++++ gcc/config/nds32/nds32-md-auxiliary.c | 7 ++ gcc/config/nds32/nds32-protos.h | 3 + gcc/config/nds32/nds32.c | 23 +++++ gcc/config/nds32/nds32.md | 123 ++++++++++++++------------ gcc/config/nds32/predicates.md | 15 ++++ 6 files changed, 130 insertions(+), 57 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index cd64aa46cc1..2b3369be703 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2018-04-04 Chung-Ju Wu + Kito Cheng + + * config/nds32/nds32-md-auxiliary.c (nds32_long_call_p): New function. + * config/nds32/nds32-protos.h (nds32_long_call_p): Declare. + * config/nds32/nds32.c (nds32_function_ok_for_sibcall): New function. + (TARGET_FUNCTION_OK_FOR_SIBCALL): Define. + * config/nds32/nds32.md (sibcall_internal): New. + (sibcall_register): Remove. + (sibcall_immediate): Remove. + (sibcall_value_internal): New. + (sibcall_value_register): Remove. + (sibcall_value_immediate): Remove. + * config/nds32/predicates.md (nds32_general_register_operand): New. + (nds32_call_address_operand): New. + 2018-04-03 Jakub Jelinek PR rtl-optimization/85167 diff --git a/gcc/config/nds32/nds32-md-auxiliary.c b/gcc/config/nds32/nds32-md-auxiliary.c index 755945f5f2a..5311b69ecf6 100644 --- a/gcc/config/nds32/nds32-md-auxiliary.c +++ b/gcc/config/nds32/nds32-md-auxiliary.c @@ -1145,3 +1145,10 @@ nds32_expand_unaligned_store (rtx *operands, enum machine_mode mode) } } } + +/* Return true X is need use long call. */ +bool +nds32_long_call_p (rtx symbol) +{ + return TARGET_CMODEL_LARGE; +} diff --git a/gcc/config/nds32/nds32-protos.h b/gcc/config/nds32/nds32-protos.h index 1387cca62ea..6a3281be1ba 100644 --- a/gcc/config/nds32/nds32-protos.h +++ b/gcc/config/nds32/nds32-protos.h @@ -116,6 +116,9 @@ extern bool nds32_symbol_load_store_p (rtx_insn *); extern const char *nds32_output_casesi_pc_relative (rtx *); extern const char *nds32_output_casesi (rtx *); +/* Auxiliary functions to identify long-call symbol. */ +extern bool nds32_long_call_p (rtx); + /* Auxiliary functions to identify 16 bit addresing mode. */ extern enum nds32_16bit_address_type nds32_mem_format (rtx); diff --git a/gcc/config/nds32/nds32.c b/gcc/config/nds32/nds32.c index 06a59beed26..829e097eae2 100644 --- a/gcc/config/nds32/nds32.c +++ b/gcc/config/nds32/nds32.c @@ -1762,6 +1762,26 @@ nds32_asm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, /* -- Permitting tail calls. */ +/* Return true if it is ok to do sibling call optimization. */ +static bool +nds32_function_ok_for_sibcall (tree decl, + tree exp ATTRIBUTE_UNUSED) +{ + /* The DECL is NULL if it is an indirect call. */ + + /* 1. Do not apply sibling call if -mv3push is enabled, + because pop25 instruction also represents return behavior. + 2. If this function is a variadic function, do not apply sibling call + because the stack layout may be a mess. + 3. We don't want to apply sibling call optimization for indirect + sibcall because the pop behavior in epilogue may pollute the + content of caller-saved regsiter when the register is used for + indirect sibcall. */ + return (!TARGET_V3PUSH + && (cfun->machine->va_args_size == 0) + && decl); +} + /* Determine whether we need to enable warning for function return check. */ static bool nds32_warn_func_return (tree decl) @@ -3764,6 +3784,9 @@ nds32_target_alignment (rtx_insn *label) /* -- Permitting tail calls. */ +#undef TARGET_FUNCTION_OK_FOR_SIBCALL +#define TARGET_FUNCTION_OK_FOR_SIBCALL nds32_function_ok_for_sibcall + #undef TARGET_WARN_FUNC_RETURN #define TARGET_WARN_FUNC_RETURN nds32_warn_func_return diff --git a/gcc/config/nds32/nds32.md b/gcc/config/nds32/nds32.md index e9bd7914eff..0ececef5081 100644 --- a/gcc/config/nds32/nds32.md +++ b/gcc/config/nds32/nds32.md @@ -1996,50 +1996,55 @@ create_template: ;; The sibcall patterns. ;; sibcall -;; sibcall_register -;; sibcall_immediate +;; sibcall_internal (define_expand "sibcall" [(parallel [(call (match_operand 0 "memory_operand" "") (const_int 0)) (clobber (reg:SI TA_REGNUM)) (return)])] - "" - "" -) - -(define_insn "*sibcall_register" - [(parallel [(call (mem (match_operand:SI 0 "register_operand" "r, r")) - (match_operand 1)) - (clobber (reg:SI TA_REGNUM)) - (return)])] - "" - "@ - jr5\t%0 - jr\t%0" - [(set_attr "type" "branch,branch") - (set_attr "length" " 2, 4")]) + "") -(define_insn "*sibcall_immediate" - [(parallel [(call (mem (match_operand:SI 0 "immediate_operand" "i")) +(define_insn "sibcall_internal" + [(parallel [(call (mem (match_operand:SI 0 "nds32_call_address_operand" "r, i")) (match_operand 1)) (clobber (reg:SI TA_REGNUM)) (return)])] "" { - if (TARGET_CMODEL_LARGE) - return "b\t%0"; - else - return "j\t%0"; + switch (which_alternative) + { + case 0: + if (TARGET_16_BIT) + return "jr5\t%0"; + else + return "jr\t%0"; + case 1: + if (nds32_long_call_p (operands[0])) + return "b\t%0"; + else + return "j\t%0"; + default: + gcc_unreachable (); + } } - [(set_attr "type" "branch") - (set (attr "length") - (if_then_else (match_test "TARGET_CMODEL_LARGE") - (const_int 12) - (const_int 4)))]) + [(set_attr "enabled" "1") + (set_attr "type" "branch") + (set_attr_alternative "length" + [ + ;; Alternative 0 + (if_then_else (match_test "TARGET_16_BIT") + (const_int 2) + (const_int 4)) + ;; Alternative 1 + (if_then_else (match_test "nds32_long_call_p (operands[0])") + (const_int 12) + (const_int 4)) + ])] +) ;; sibcall_value -;; sibcall_value_register +;; sibcall_value_internal ;; sibcall_value_immediate (define_expand "sibcall_value" @@ -2048,42 +2053,46 @@ create_template: (const_int 0))) (clobber (reg:SI TA_REGNUM)) (return)])] - "" - "" -) - -(define_insn "*sibcall_value_register" - [(parallel [(set (match_operand 0) - (call (mem (match_operand:SI 1 "register_operand" "r, r")) - (match_operand 2))) - (clobber (reg:SI TA_REGNUM)) - (return)])] - "" - "@ - jr5\t%1 - jr\t%1" - [(set_attr "type" "branch,branch") - (set_attr "length" " 2, 4")]) + "") -(define_insn "*sibcall_value_immediate" +(define_insn "sibcall_value_internal" [(parallel [(set (match_operand 0) - (call (mem (match_operand:SI 1 "immediate_operand" "i")) + (call (mem (match_operand:SI 1 "nds32_call_address_operand" "r, i")) (match_operand 2))) (clobber (reg:SI TA_REGNUM)) (return)])] "" { - if (TARGET_CMODEL_LARGE) - return "b\t%1"; - else - return "j\t%1"; + switch (which_alternative) + { + case 0: + if (TARGET_16_BIT) + return "jr5\t%1"; + else + return "jr\t%1"; + case 1: + if (nds32_long_call_p (operands[1])) + return "b\t%1"; + else + return "j\t%1"; + default: + gcc_unreachable (); + } } - [(set_attr "type" "branch") - (set (attr "length") - (if_then_else (match_test "TARGET_CMODEL_LARGE") - (const_int 12) - (const_int 4)))]) - + [(set_attr "enabled" "1") + (set_attr "type" "branch") + (set_attr_alternative "length" + [ + ;; Alternative 0 + (if_then_else (match_test "TARGET_16_BIT") + (const_int 2) + (const_int 4)) + ;; Alternative 1 + (if_then_else (match_test "nds32_long_call_p (operands[1])") + (const_int 12) + (const_int 4)) + ])] +) ;; ---------------------------------------------------------------------------- diff --git a/gcc/config/nds32/predicates.md b/gcc/config/nds32/predicates.md index bff37c71c4a..ad04b51baf2 100644 --- a/gcc/config/nds32/predicates.md +++ b/gcc/config/nds32/predicates.md @@ -57,6 +57,21 @@ return true; }) +(define_predicate "nds32_general_register_operand" + (match_code "reg,subreg") +{ + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + return (REG_P (op) + && (REGNO (op) >= FIRST_PSEUDO_REGISTER + || REGNO (op) <= NDS32_LAST_GPR_REGNUM)); +}) + +(define_predicate "nds32_call_address_operand" + (ior (match_operand 0 "nds32_symbolic_operand") + (match_operand 0 "nds32_general_register_operand"))) + (define_predicate "nds32_lmw_smw_base_operand" (and (match_code "mem") (match_test "nds32_valid_smw_lwm_base_p (op)"))) -- 2.30.2