diff options
author | Max Filippov <jcmvbkbc@gmail.com> | 2022-07-14 02:39:59 -0700 |
---|---|---|
committer | Max Filippov <jcmvbkbc@gmail.com> | 2022-09-22 03:53:43 -0700 |
commit | 0bf60f68ed9db2e4b373b28c125aeda339f6cd59 (patch) | |
tree | fea5b1cadfdd4d3ebda6b23fa9cd5810e265a584 | |
parent | 4bdf739f835520ccbc433dc9eac461895741f317 (diff) | |
download | gcc-0bf60f68ed9db2e4b373b28c125aeda339f6cd59.tar.gz |
xtensa: gcc: implement MI thunk generation for call0 ABI
gcc/
* config/xtensa/xtensa.cc (xtensa_can_output_mi_thunk)
(xtensa_output_mi_thunk): New functions.
(TARGET_ASM_CAN_OUTPUT_MI_THUNK)
(TARGET_ASM_OUTPUT_MI_THUNK): New macro definitions.
(xtensa_prepare_expand_call): Use fixed register a8 as temporary
when called with reload_completed set to 1.
-rw-r--r-- | gcc/config/xtensa/xtensa.cc | 116 |
1 files changed, 115 insertions, 1 deletions
diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc index f1b3331ea55..e5abd356a74 100644 --- a/gcc/config/xtensa/xtensa.cc +++ b/gcc/config/xtensa/xtensa.cc @@ -191,6 +191,15 @@ static bool xtensa_can_eliminate (const int from ATTRIBUTE_UNUSED, 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 bool xtensa_can_output_mi_thunk (const_tree thunk_fndecl ATTRIBUTE_UNUSED, + HOST_WIDE_INT delta ATTRIBUTE_UNUSED, + HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED, + const_tree function ATTRIBUTE_UNUSED); +static void xtensa_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, + HOST_WIDE_INT delta, + HOST_WIDE_INT vcall_offset, + tree function); + static rtx xtensa_delegitimize_address (rtx); @@ -351,6 +360,12 @@ static rtx xtensa_delegitimize_address (rtx); #undef TARGET_FUNCTION_OK_FOR_SIBCALL #define TARGET_FUNCTION_OK_FOR_SIBCALL xtensa_function_ok_for_sibcall +#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK +#define TARGET_ASM_CAN_OUTPUT_MI_THUNK xtensa_can_output_mi_thunk + +#undef TARGET_ASM_OUTPUT_MI_THUNK +#define TARGET_ASM_OUTPUT_MI_THUNK xtensa_output_mi_thunk + struct gcc_target targetm = TARGET_INITIALIZER; @@ -2173,7 +2188,16 @@ xtensa_prepare_expand_call (int callop, rtx *operands) addr = gen_sym_PLT (addr); if (!call_insn_operand (addr, VOIDmode)) - XEXP (operands[callop], 0) = copy_to_mode_reg (Pmode, addr); + { + /* This may be called while generating MI thunk when we pretend + that reload is over. Use a8 as a temporary register in that case. */ + rtx reg = can_create_pseudo_p () + ? copy_to_mode_reg (Pmode, addr) + : copy_to_suggested_reg (addr, + gen_rtx_REG (Pmode, A8_REG), + Pmode); + XEXP (operands[callop], 0) = reg; + } } @@ -4983,6 +5007,96 @@ xtensa_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED, tree exp ATTRIBUTE_U return true; } +static bool +xtensa_can_output_mi_thunk (const_tree thunk_fndecl ATTRIBUTE_UNUSED, + HOST_WIDE_INT delta ATTRIBUTE_UNUSED, + HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED, + const_tree function ATTRIBUTE_UNUSED) +{ + if (TARGET_WINDOWED_ABI) + return false; + + return true; +} + +/* Output code to add DELTA to the first argument, and then jump + to FUNCTION. Used for C++ multiple inheritance. */ +static void +xtensa_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, + HOST_WIDE_INT delta, + HOST_WIDE_INT vcall_offset, + tree function) +{ + rtx this_rtx; + rtx funexp; + rtx_insn *insn; + int this_reg_no; + rtx temp0 = gen_rtx_REG (Pmode, A9_REG); + const char *fnname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk)); + + reload_completed = 1; + + if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) + this_reg_no = 3; + else + this_reg_no = 2; + + this_rtx = gen_rtx_REG (Pmode, A0_REG + this_reg_no); + + if (delta) + { + if (xtensa_simm8 (delta)) + emit_insn (gen_addsi3 (this_rtx, this_rtx, GEN_INT (delta))); + else + { + emit_move_insn (temp0, GEN_INT (delta)); + emit_insn (gen_addsi3 (this_rtx, this_rtx, temp0)); + } + } + + if (vcall_offset) + { + rtx temp1 = gen_rtx_REG (Pmode, A0_REG + 10); + rtx addr = temp1; + + emit_move_insn (temp0, gen_rtx_MEM (Pmode, this_rtx)); + if (xtensa_uimm8x4 (vcall_offset)) + addr = plus_constant (Pmode, temp0, vcall_offset); + else if (xtensa_simm8 (vcall_offset)) + emit_insn (gen_addsi3 (temp1, temp0, GEN_INT (vcall_offset))); + else + { + emit_move_insn (temp1, GEN_INT (vcall_offset)); + emit_insn (gen_addsi3 (temp1, temp0, temp1)); + } + emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr)); + emit_insn (gen_add2_insn (this_rtx, temp1)); + } + + /* Generate a tail call to the target function. */ + if (!TREE_USED (function)) + { + assemble_external (function); + TREE_USED (function) = 1; + } + + funexp = XEXP (DECL_RTL (function), 0); + funexp = gen_rtx_MEM (FUNCTION_MODE, funexp); + insn = emit_call_insn (gen_sibcall (funexp, const0_rtx)); + SIBLING_CALL_P (insn) = 1; + + insn = get_insns (); + shorten_branches (insn); + assemble_start_function (thunk, fnname); + final_start_function (insn, file, 1); + final (insn, file, 1); + final_end_function (); + assemble_end_function (thunk, fnname); + + /* Stop pretending to be a post-reload pass. */ + reload_completed = 0; +} + static rtx xtensa_delegitimize_address (rtx op) { |