Hi all, This patch refactors the code used in call, call_value, sibcall, sibcall_value expanders.
Before the change, the logic is following: call expander --> call_internal --> call_reg/call_symbol call_vlaue expander --> call_value_internal --> call_value_reg/call_value_symbol sibcall expander --> sibcall_internal --> sibcall_insn sibcall_value expander --> sibcall_value_internal --> sibcall_value_insn After the change, the logic is simplified into: call expander --> aarch64_expand_call() --> call_insn call_value expander --> aarch64_expand_call() --> call_value_insn sibcall expander --> aarch64_expand_call() --> sibcall_insn sibcall_value expander --> aarch64_expand_call() --> sibcall_value_insn The code are factored out from each expander into aarch64_expand_call (). This also fixes the two issues Richard Henderson suggests in comments 8: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64971 aarch64-none-elf regression test Okay, aarch64-linux bootstrap Okay. Okay for trunk? Regards, Renlin Li gcc/ChangeLog: 2016-12-01 Renlin Li <renlin...@arm.com> * config/aarch64/aarch64-protos.h (aarch64_expand_call): Declare. * config/aarch64/aarch64.c (aarch64_expand_call): Define. * config/aarch64/constraints.md (Usf): Add long call check. * config/aarch64/aarch64.md (call): Use aarch64_expand_call. (call_value): Likewise. (sibcall): Likewise. (sibcall_value): Likewise. (call_insn): New. (call_value_insn): New. (sibcall_insn): Update rtx pattern. (sibcall_value_insn): Likewise. (call_internal): Remove. (call_value_internal): Likewise. (sibcall_internal): Likewise. (sibcall_value_internal): Likewise. (call_reg): Likewise. (call_symbol): Likewise. (call_value_reg): Likewise. (call_value_symbol): Likewise.
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index 7f67f14..3a5babb 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -305,6 +305,7 @@ bool aarch64_const_vec_all_same_int_p (rtx, HOST_WIDE_INT); bool aarch64_constant_address_p (rtx); bool aarch64_emit_approx_div (rtx, rtx, rtx); bool aarch64_emit_approx_sqrt (rtx, rtx, bool); +void aarch64_expand_call (rtx, rtx, bool); bool aarch64_expand_movmem (rtx *); bool aarch64_float_const_zero_rtx_p (rtx); bool aarch64_function_arg_regno_p (unsigned); diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 68a3380..c313cf5 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -4343,6 +4343,51 @@ aarch64_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2) return true; } +/* This function is used by the call expanders of the machine description. + RESULT is the register in which the result is returned. It's NULL for + "call" and "sibcall". + MEM is the location of the function call. + SIBCALL indicates whether this function call is normal call or sibling call. + It will generate different pattern accordingly. */ + +void +aarch64_expand_call (rtx result, rtx mem, bool sibcall) +{ + rtx call, callee, tmp; + rtvec vec; + machine_mode mode; + + gcc_assert (MEM_P (mem)); + callee = XEXP (mem, 0); + mode = GET_MODE (callee); + gcc_assert (mode == Pmode); + + /* Decide if we should generate indirect calls by loading the + 64-bit address of the callee into a register before performing + the branch-and-link. */ + + if (GET_CODE (callee) == SYMBOL_REF + ? (aarch64_is_long_call_p (callee) + || aarch64_is_noplt_call_p (callee)) + : !REG_P (callee)) + XEXP (mem, 0) = force_reg (mode, callee); + + call = gen_rtx_CALL (VOIDmode, mem, const0_rtx); + + if (result != NULL_RTX) + call = gen_rtx_SET (result, call); + + if (sibcall) + tmp = ret_rtx; + else + tmp = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, LR_REGNUM)); + + vec = gen_rtvec (2, call, tmp); + call = gen_rtx_PARALLEL (VOIDmode, vec); + + aarch64_emit_call_insn (call); +} + /* Emit call insn with PAT and do aarch64-specific handling. */ void diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index bc6d8a2..5682686 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -718,12 +718,6 @@ ;; Subroutine calls and sibcalls ;; ------------------------------------------------------------------- -(define_expand "call_internal" - [(parallel [(call (match_operand 0 "memory_operand" "") - (match_operand 1 "general_operand" "")) - (use (match_operand 2 "" "")) - (clobber (reg:DI LR_REGNUM))])]) - (define_expand "call" [(parallel [(call (match_operand 0 "memory_operand" "") (match_operand 1 "general_operand" "")) @@ -732,57 +726,22 @@ "" " { - rtx callee, pat; - - /* In an untyped call, we can get NULL for operand 2. */ - if (operands[2] == NULL) - operands[2] = const0_rtx; - - /* Decide if we should generate indirect calls by loading the - 64-bit address of the callee into a register before performing - the branch-and-link. */ - callee = XEXP (operands[0], 0); - if (GET_CODE (callee) == SYMBOL_REF - ? (aarch64_is_long_call_p (callee) - || aarch64_is_noplt_call_p (callee)) - : !REG_P (callee)) - XEXP (operands[0], 0) = force_reg (Pmode, callee); - - pat = gen_call_internal (operands[0], operands[1], operands[2]); - aarch64_emit_call_insn (pat); + aarch64_expand_call (NULL_RTX, operands[0], false); DONE; }" ) -(define_insn "*call_reg" - [(call (mem:DI (match_operand:DI 0 "register_operand" "r")) +(define_insn "*call_insn" + [(call (mem:DI (match_operand:DI 0 "aarch64_call_insn_operand" "r, Usf")) (match_operand 1 "" "")) - (use (match_operand 2 "" "")) (clobber (reg:DI LR_REGNUM))] "" - "blr\\t%0" - [(set_attr "type" "call")] -) - -(define_insn "*call_symbol" - [(call (mem:DI (match_operand:DI 0 "" "")) - (match_operand 1 "" "")) - (use (match_operand 2 "" "")) - (clobber (reg:DI LR_REGNUM))] - "GET_CODE (operands[0]) == SYMBOL_REF - && !aarch64_is_long_call_p (operands[0]) - && !aarch64_is_noplt_call_p (operands[0])" - "bl\\t%a0" - [(set_attr "type" "call")] + "@ + blr\\t%0 + bl\\t%a0" + [(set_attr "type" "call, call")] ) -(define_expand "call_value_internal" - [(parallel [(set (match_operand 0 "" "") - (call (match_operand 1 "memory_operand" "") - (match_operand 2 "general_operand" ""))) - (use (match_operand 3 "" "")) - (clobber (reg:DI LR_REGNUM))])]) - (define_expand "call_value" [(parallel [(set (match_operand 0 "" "") (call (match_operand 1 "memory_operand" "") @@ -792,60 +751,23 @@ "" " { - rtx callee, pat; - - /* In an untyped call, we can get NULL for operand 3. */ - if (operands[3] == NULL) - operands[3] = const0_rtx; - - /* Decide if we should generate indirect calls by loading the - 64-bit address of the callee into a register before performing - the branch-and-link. */ - callee = XEXP (operands[1], 0); - if (GET_CODE (callee) == SYMBOL_REF - ? (aarch64_is_long_call_p (callee) - || aarch64_is_noplt_call_p (callee)) - : !REG_P (callee)) - XEXP (operands[1], 0) = force_reg (Pmode, callee); - - pat = gen_call_value_internal (operands[0], operands[1], operands[2], - operands[3]); - aarch64_emit_call_insn (pat); + aarch64_expand_call (operands[0], operands[1], false); DONE; }" ) -(define_insn "*call_value_reg" +(define_insn "*call_value_insn" [(set (match_operand 0 "" "") - (call (mem:DI (match_operand:DI 1 "register_operand" "r")) + (call (mem:DI (match_operand:DI 1 "aarch64_call_insn_operand" "r, Usf")) (match_operand 2 "" ""))) - (use (match_operand 3 "" "")) (clobber (reg:DI LR_REGNUM))] "" - "blr\\t%1" - [(set_attr "type" "call")] - -) - -(define_insn "*call_value_symbol" - [(set (match_operand 0 "" "") - (call (mem:DI (match_operand:DI 1 "" "")) - (match_operand 2 "" ""))) - (use (match_operand 3 "" "")) - (clobber (reg:DI LR_REGNUM))] - "GET_CODE (operands[1]) == SYMBOL_REF - && !aarch64_is_long_call_p (operands[1]) - && !aarch64_is_noplt_call_p (operands[1])" - "bl\\t%a1" - [(set_attr "type" "call")] + "@ + blr\\t%1 + bl\\t%a1" + [(set_attr "type" "call, call")] ) -(define_expand "sibcall_internal" - [(parallel [(call (match_operand 0 "memory_operand" "") - (match_operand 1 "general_operand" "")) - (return) - (use (match_operand 2 "" ""))])]) - (define_expand "sibcall" [(parallel [(call (match_operand 0 "memory_operand" "") (match_operand 1 "general_operand" "")) @@ -853,29 +775,11 @@ (use (match_operand 2 "" ""))])] "" { - rtx pat; - rtx callee = XEXP (operands[0], 0); - if (!REG_P (callee) - && ((GET_CODE (callee) != SYMBOL_REF) - || aarch64_is_noplt_call_p (callee))) - XEXP (operands[0], 0) = force_reg (Pmode, callee); - - if (operands[2] == NULL_RTX) - operands[2] = const0_rtx; - - pat = gen_sibcall_internal (operands[0], operands[1], operands[2]); - aarch64_emit_call_insn (pat); + aarch64_expand_call (NULL_RTX, operands[0], true); DONE; } ) -(define_expand "sibcall_value_internal" - [(parallel [(set (match_operand 0 "" "") - (call (match_operand 1 "memory_operand" "") - (match_operand 2 "general_operand" ""))) - (return) - (use (match_operand 3 "" ""))])]) - (define_expand "sibcall_value" [(parallel [(set (match_operand 0 "" "") (call (match_operand 1 "memory_operand" "") @@ -884,19 +788,7 @@ (use (match_operand 3 "" ""))])] "" { - rtx pat; - rtx callee = XEXP (operands[1], 0); - if (!REG_P (callee) - && ((GET_CODE (callee) != SYMBOL_REF) - || aarch64_is_noplt_call_p (callee))) - XEXP (operands[1], 0) = force_reg (Pmode, callee); - - if (operands[3] == NULL_RTX) - operands[3] = const0_rtx; - - pat = gen_sibcall_value_internal (operands[0], operands[1], operands[2], - operands[3]); - aarch64_emit_call_insn (pat); + aarch64_expand_call (operands[0], operands[1], true); DONE; } ) @@ -904,8 +796,7 @@ (define_insn "*sibcall_insn" [(call (mem:DI (match_operand:DI 0 "aarch64_call_insn_operand" "Ucs, Usf")) (match_operand 1 "" "")) - (return) - (use (match_operand 2 "" ""))] + (return)] "SIBLING_CALL_P (insn)" "@ br\\t%0 @@ -918,8 +809,7 @@ (call (mem:DI (match_operand:DI 1 "aarch64_call_insn_operand" "Ucs, Usf")) (match_operand 2 "" ""))) - (return) - (use (match_operand 3 "" ""))] + (return)] "SIBLING_CALL_P (insn)" "@ br\\t%1 diff --git a/gcc/config/aarch64/constraints.md b/gcc/config/aarch64/constraints.md index 7a2847a..bd28386 100644 --- a/gcc/config/aarch64/constraints.md +++ b/gcc/config/aarch64/constraints.md @@ -118,7 +118,8 @@ (define_constraint "Usf" "@internal Usf is a symbol reference under the context where plt stub allowed." (and (match_code "symbol_ref") - (match_test "!aarch64_is_noplt_call_p (op)"))) + (match_test "!(aarch64_is_noplt_call_p (op) + || aarch64_is_long_call_p (op))"))) (define_constraint "UsM" "@internal