xtensa: gcc: implement MI thunk generation for call0 ABI

Message ID 20220913215743.2712390-1-jcmvbkbc@gmail.com
State Committed
Commit 0bf60f68ed9db2e4b373b28c125aeda339f6cd59
Headers
Series xtensa: gcc: implement MI thunk generation for call0 ABI |

Commit Message

Max Filippov Sept. 13, 2022, 9:57 p.m. UTC
  Suwa-san, could you please take a look?

This change fixes the fowllowing testsuite failures when building for
call0 ABI:

g++.dg/ipa/pr60640-4.C
g++.dg/ipa/pr83549.C
g++.dg/ipa/pr83667.C
g++.dg/torture/pr81812.C

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.
---
 gcc/config/xtensa/xtensa.cc | 116 +++++++++++++++++++++++++++++++++++-
 1 file changed, 115 insertions(+), 1 deletion(-)
  

Comments

Max Filippov Sept. 22, 2022, 10:56 a.m. UTC | #1
On Tue, Sep 13, 2022 at 2:58 PM Max Filippov <jcmvbkbc@gmail.com> wrote:
>
> Suwa-san, could you please take a look?
>
> This change fixes the fowllowing testsuite failures when building for
> call0 ABI:
>
> g++.dg/ipa/pr60640-4.C
> g++.dg/ipa/pr83549.C
> g++.dg/ipa/pr83667.C
> g++.dg/torture/pr81812.C
>
> 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.
> ---
>  gcc/config/xtensa/xtensa.cc | 116 +++++++++++++++++++++++++++++++++++-
>  1 file changed, 115 insertions(+), 1 deletion(-)

Regtested for target=xtensa-linux-uclibc, no new regressions.
Committed to master.
  

Patch

diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc
index f1b3331ea558..e5abd356a745 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)
 {