xtensa: Add support for sibling call optimization
This patch introduces support for sibling call optimization, when call0 ABI is in effect. gcc/ChangeLog: * config/xtensa/xtensa-protos.h (xtensa_prepare_expand_call, xtensa_emit_sibcall): New prototypes. (xtensa_expand_epilogue): Add new argument that specifies whether or not sibling call. * config/xtensa/xtensa.cc (TARGET_FUNCTION_OK_FOR_SIBCALL): New macro definition. (xtensa_prepare_expand_call): New function in order to share the common code. (xtensa_emit_sibcall, xtensa_function_ok_for_sibcall): New functions. (xtensa_expand_epilogue): Add new argument sibcall_p and use it for sibling call handling. * config/xtensa/xtensa.md (call, call_value): Use xtensa_prepare_expand_call. (call_internal, call_value_internal): Add the condition in order to be disabled if sibling call. (sibcall, sibcall_value, sibcall_epilogue): New expansions. (sibcall_internal, sibcall_value_internal): New insn patterns, and split ones in order to take care of the indirect sibcalls. gcc/testsuite/ChangeLog: * gcc.target/xtensa/sibcalls.c: New.
This commit is contained in:
parent
96518f714e
commit
43b0c56fda
4 changed files with 155 additions and 20 deletions
|
@ -53,7 +53,9 @@ extern void xtensa_expand_atomic (enum rtx_code, rtx, rtx, rtx, bool);
|
|||
extern void xtensa_emit_loop_end (rtx_insn *, rtx *);
|
||||
extern char *xtensa_emit_branch (bool, rtx *);
|
||||
extern char *xtensa_emit_movcc (bool, bool, bool, rtx *);
|
||||
extern void xtensa_prepare_expand_call (int, rtx *);
|
||||
extern char *xtensa_emit_call (int, rtx *);
|
||||
extern char *xtensa_emit_sibcall (int, rtx *);
|
||||
extern bool xtensa_tls_referenced_p (rtx);
|
||||
extern enum rtx_code xtensa_shlrd_which_direction (rtx, rtx);
|
||||
|
||||
|
@ -73,7 +75,7 @@ extern int xtensa_dbx_register_number (int);
|
|||
extern long compute_frame_size (poly_int64);
|
||||
extern bool xtensa_use_return_instruction_p (void);
|
||||
extern void xtensa_expand_prologue (void);
|
||||
extern void xtensa_expand_epilogue (void);
|
||||
extern void xtensa_expand_epilogue (bool);
|
||||
extern void order_regs_for_local_alloc (void);
|
||||
extern enum reg_class xtensa_regno_to_class (int regno);
|
||||
extern HOST_WIDE_INT xtensa_initial_elimination_offset (int from, int to);
|
||||
|
|
|
@ -189,7 +189,7 @@ static bool xtensa_can_eliminate (const int from ATTRIBUTE_UNUSED,
|
|||
const int to);
|
||||
static HOST_WIDE_INT xtensa_starting_frame_offset (void);
|
||||
static unsigned HOST_WIDE_INT xtensa_asan_shadow_offset (void);
|
||||
|
||||
static bool xtensa_function_ok_for_sibcall (tree, tree);
|
||||
static rtx xtensa_delegitimize_address (rtx);
|
||||
|
||||
|
||||
|
@ -347,6 +347,9 @@ static rtx xtensa_delegitimize_address (rtx);
|
|||
#undef TARGET_DELEGITIMIZE_ADDRESS
|
||||
#define TARGET_DELEGITIMIZE_ADDRESS xtensa_delegitimize_address
|
||||
|
||||
#undef TARGET_FUNCTION_OK_FOR_SIBCALL
|
||||
#define TARGET_FUNCTION_OK_FOR_SIBCALL xtensa_function_ok_for_sibcall
|
||||
|
||||
struct gcc_target targetm = TARGET_INITIALIZER;
|
||||
|
||||
|
||||
|
@ -2127,6 +2130,20 @@ xtensa_emit_movcc (bool inverted, bool isfp, bool isbool, rtx *operands)
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
xtensa_prepare_expand_call (int callop, rtx *operands)
|
||||
{
|
||||
rtx addr = XEXP (operands[callop], 0);
|
||||
|
||||
if (flag_pic && SYMBOL_REF_P (addr)
|
||||
&& (!SYMBOL_REF_LOCAL_P (addr) || SYMBOL_REF_EXTERNAL_P (addr)))
|
||||
addr = gen_sym_PLT (addr);
|
||||
|
||||
if (!call_insn_operand (addr, VOIDmode))
|
||||
XEXP (operands[callop], 0) = copy_to_mode_reg (Pmode, addr);
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
xtensa_emit_call (int callop, rtx *operands)
|
||||
{
|
||||
|
@ -2145,6 +2162,24 @@ xtensa_emit_call (int callop, rtx *operands)
|
|||
}
|
||||
|
||||
|
||||
char *
|
||||
xtensa_emit_sibcall (int callop, rtx *operands)
|
||||
{
|
||||
static char result[64];
|
||||
rtx tgt = operands[callop];
|
||||
|
||||
if (GET_CODE (tgt) == CONST_INT)
|
||||
sprintf (result, "j.l\t" HOST_WIDE_INT_PRINT_HEX ", a9",
|
||||
INTVAL (tgt));
|
||||
else if (register_operand (tgt, VOIDmode))
|
||||
sprintf (result, "jx\t%%%d", callop);
|
||||
else
|
||||
sprintf (result, "j.l\t%%%d, a9", callop);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
xtensa_legitimate_address_p (machine_mode mode, rtx addr, bool strict)
|
||||
{
|
||||
|
@ -3270,7 +3305,7 @@ xtensa_expand_prologue (void)
|
|||
}
|
||||
|
||||
void
|
||||
xtensa_expand_epilogue (void)
|
||||
xtensa_expand_epilogue (bool sibcall_p)
|
||||
{
|
||||
if (!TARGET_WINDOWED_ABI)
|
||||
{
|
||||
|
@ -3304,10 +3339,13 @@ xtensa_expand_epilogue (void)
|
|||
if (xtensa_call_save_reg(regno))
|
||||
{
|
||||
rtx x = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset));
|
||||
rtx reg;
|
||||
|
||||
offset -= UNITS_PER_WORD;
|
||||
emit_move_insn (gen_rtx_REG (SImode, regno),
|
||||
emit_move_insn (reg = gen_rtx_REG (SImode, regno),
|
||||
gen_frame_mem (SImode, x));
|
||||
if (regno == A0_REG && sibcall_p)
|
||||
emit_use (reg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3342,7 +3380,8 @@ xtensa_expand_epilogue (void)
|
|||
EH_RETURN_STACKADJ_RTX));
|
||||
}
|
||||
cfun->machine->epilogue_done = true;
|
||||
emit_jump_insn (gen_return ());
|
||||
if (!sibcall_p)
|
||||
emit_jump_insn (gen_return ());
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -4869,6 +4908,17 @@ xtensa_asan_shadow_offset (void)
|
|||
return HOST_WIDE_INT_UC (0x10000000);
|
||||
}
|
||||
|
||||
/* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
|
||||
static bool
|
||||
xtensa_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED, tree exp ATTRIBUTE_UNUSED)
|
||||
{
|
||||
/* Do not allow sibcalls when windowed registers ABI is in effect. */
|
||||
if (TARGET_WINDOWED_ABI)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static rtx
|
||||
xtensa_delegitimize_address (rtx op)
|
||||
{
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
(A7_REG 7)
|
||||
(A8_REG 8)
|
||||
(A9_REG 9)
|
||||
(A10_REG 10)
|
||||
|
||||
(UNSPEC_NOP 2)
|
||||
(UNSPEC_PLT 3)
|
||||
|
@ -2148,18 +2149,13 @@
|
|||
(match_operand 1 "" ""))]
|
||||
""
|
||||
{
|
||||
rtx addr = XEXP (operands[0], 0);
|
||||
if (flag_pic && GET_CODE (addr) == SYMBOL_REF
|
||||
&& (!SYMBOL_REF_LOCAL_P (addr) || SYMBOL_REF_EXTERNAL_P (addr)))
|
||||
addr = gen_sym_PLT (addr);
|
||||
if (!call_insn_operand (addr, VOIDmode))
|
||||
XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, addr);
|
||||
xtensa_prepare_expand_call (0, operands);
|
||||
})
|
||||
|
||||
(define_insn "call_internal"
|
||||
[(call (mem (match_operand:SI 0 "call_insn_operand" "nir"))
|
||||
(match_operand 1 "" "i"))]
|
||||
""
|
||||
"!SIBLING_CALL_P (insn)"
|
||||
{
|
||||
return xtensa_emit_call (0, operands);
|
||||
}
|
||||
|
@ -2173,19 +2169,14 @@
|
|||
(match_operand 2 "" "")))]
|
||||
""
|
||||
{
|
||||
rtx addr = XEXP (operands[1], 0);
|
||||
if (flag_pic && GET_CODE (addr) == SYMBOL_REF
|
||||
&& (!SYMBOL_REF_LOCAL_P (addr) || SYMBOL_REF_EXTERNAL_P (addr)))
|
||||
addr = gen_sym_PLT (addr);
|
||||
if (!call_insn_operand (addr, VOIDmode))
|
||||
XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, addr);
|
||||
xtensa_prepare_expand_call (1, operands);
|
||||
})
|
||||
|
||||
(define_insn "call_value_internal"
|
||||
[(set (match_operand 0 "register_operand" "=a")
|
||||
(call (mem (match_operand:SI 1 "call_insn_operand" "nir"))
|
||||
(match_operand 2 "" "i")))]
|
||||
""
|
||||
"!SIBLING_CALL_P (insn)"
|
||||
{
|
||||
return xtensa_emit_call (1, operands);
|
||||
}
|
||||
|
@ -2193,6 +2184,70 @@
|
|||
(set_attr "mode" "none")
|
||||
(set_attr "length" "3")])
|
||||
|
||||
(define_expand "sibcall"
|
||||
[(call (match_operand 0 "memory_operand" "")
|
||||
(match_operand 1 "" ""))]
|
||||
"!TARGET_WINDOWED_ABI"
|
||||
{
|
||||
xtensa_prepare_expand_call (0, operands);
|
||||
})
|
||||
|
||||
(define_insn "sibcall_internal"
|
||||
[(call (mem:SI (match_operand:SI 0 "call_insn_operand" "nir"))
|
||||
(match_operand 1 "" "i"))]
|
||||
"!TARGET_WINDOWED_ABI && SIBLING_CALL_P (insn)"
|
||||
{
|
||||
return xtensa_emit_sibcall (0, operands);
|
||||
}
|
||||
[(set_attr "type" "call")
|
||||
(set_attr "mode" "none")
|
||||
(set_attr "length" "3")])
|
||||
|
||||
(define_split
|
||||
[(call (mem:SI (match_operand:SI 0 "register_operand"))
|
||||
(match_operand 1 ""))]
|
||||
"reload_completed
|
||||
&& !TARGET_WINDOWED_ABI && SIBLING_CALL_P (insn)
|
||||
&& IN_RANGE (REGNO (operands[0]), 12, 15)"
|
||||
[(set (reg:SI A10_REG)
|
||||
(match_dup 0))
|
||||
(call (mem:SI (reg:SI A10_REG))
|
||||
(match_dup 1))])
|
||||
|
||||
(define_expand "sibcall_value"
|
||||
[(set (match_operand 0 "register_operand" "")
|
||||
(call (match_operand 1 "memory_operand" "")
|
||||
(match_operand 2 "" "")))]
|
||||
"!TARGET_WINDOWED_ABI"
|
||||
{
|
||||
xtensa_prepare_expand_call (1, operands);
|
||||
})
|
||||
|
||||
(define_insn "sibcall_value_internal"
|
||||
[(set (match_operand 0 "register_operand" "=a")
|
||||
(call (mem:SI (match_operand:SI 1 "call_insn_operand" "nir"))
|
||||
(match_operand 2 "" "i")))]
|
||||
"!TARGET_WINDOWED_ABI && SIBLING_CALL_P (insn)"
|
||||
{
|
||||
return xtensa_emit_sibcall (1, operands);
|
||||
}
|
||||
[(set_attr "type" "call")
|
||||
(set_attr "mode" "none")
|
||||
(set_attr "length" "3")])
|
||||
|
||||
(define_split
|
||||
[(set (match_operand 0 "register_operand")
|
||||
(call (mem:SI (match_operand:SI 1 "register_operand"))
|
||||
(match_operand 2 "")))]
|
||||
"reload_completed
|
||||
&& !TARGET_WINDOWED_ABI && SIBLING_CALL_P (insn)
|
||||
&& IN_RANGE (REGNO (operands[1]), 12, 15)"
|
||||
[(set (reg:SI A10_REG)
|
||||
(match_dup 1))
|
||||
(set (match_dup 0)
|
||||
(call (mem:SI (reg:SI A10_REG))
|
||||
(match_dup 2)))])
|
||||
|
||||
(define_insn "entry"
|
||||
[(set (reg:SI A1_REG)
|
||||
(unspec_volatile:SI [(match_operand:SI 0 "const_int_operand" "i")]
|
||||
|
@ -2260,7 +2315,15 @@
|
|||
[(return)]
|
||||
""
|
||||
{
|
||||
xtensa_expand_epilogue ();
|
||||
xtensa_expand_epilogue (false);
|
||||
DONE;
|
||||
})
|
||||
|
||||
(define_expand "sibcall_epilogue"
|
||||
[(return)]
|
||||
"!TARGET_WINDOWED_ABI"
|
||||
{
|
||||
xtensa_expand_epilogue (true);
|
||||
DONE;
|
||||
})
|
||||
|
||||
|
|
20
gcc/testsuite/gcc.target/xtensa/sibcalls.c
Normal file
20
gcc/testsuite/gcc.target/xtensa/sibcalls.c
Normal file
|
@ -0,0 +1,20 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -mabi=call0 -foptimize-sibling-calls" } */
|
||||
|
||||
extern int foo(int);
|
||||
extern void bar(int);
|
||||
|
||||
int test_0(int a) {
|
||||
return foo(a);
|
||||
}
|
||||
|
||||
void test_1(int a) {
|
||||
bar(a);
|
||||
}
|
||||
|
||||
int test_2(int (*a)(void)) {
|
||||
bar(0);
|
||||
return a();
|
||||
}
|
||||
|
||||
/* { dg-final { scan-assembler-not "ret" } } */
|
Loading…
Add table
Reference in a new issue