This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PR gcc/7618: Support MI thunks in the MIPS backend


Here is a sample patch to add support for MI thunks to the MIPS
backend.  This is for PR gcc/7618.

I have only tested this patch by inspecting the code.  Somebody with
access to MIPS hardware needs to actually test it and to run the gcc
testsuite.  With luck, this is the right general approach, and it will
just need a bit of tweaking.

Ian


2004-01-13  Ian Lance Taylor  <ian@wasabisystems.com>

	* config/mips/mips.c (TARGET_ASM_OUTPUT_MI_THUNK): Define.
	(TARGET_ASM_CAN_OUTPUT_MI_THUNK): Define.
	(mips_can_output_mi_thunk): New static function.
	(mips_output_mi_thunk): New static function.


Index: mips.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.c,v
retrieving revision 1.362
diff -p -u -r1.362 mips.c
--- mips.c	13 Jan 2004 01:58:44 -0000	1.362
+++ mips.c	13 Jan 2004 19:18:01 -0000
@@ -277,6 +277,10 @@ static int mips_issue_rate (void);
 static int mips_use_dfa_pipeline_interface (void);
 static void mips_init_libfuncs (void);
 static tree mips_build_builtin_va_list (void);
+static bool mips_can_output_mi_thunk (tree, HOST_WIDE_INT, HOST_WIDE_INT,
+				      tree);
+static void mips_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT,
+				  tree);
 
 #if TARGET_IRIX
 static void irix_asm_named_section_1 (const char *, unsigned int,
@@ -752,6 +756,11 @@ const struct mips_cpu_info mips_cpu_info
 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
 #define TARGET_FUNCTION_OK_FOR_SIBCALL mips_function_ok_for_sibcall
 
+#undef TARGET_ASM_OUTPUT_MI_THUNK
+#define TARGET_ASM_OUTPUT_MI_THUNK mips_output_mi_thunk
+#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK mips_can_output_mi_thunk
+
 #undef TARGET_VALID_POINTER_MODE
 #define TARGET_VALID_POINTER_MODE mips_valid_pointer_mode
 #undef TARGET_RTX_COSTS
@@ -9379,6 +9388,163 @@ mips_emit_prefetch (rtx *operands)
   return "";
 }
 
+/* Return whether we can output a thunk function.  There are some
+   restrictions on MIPS16 code.  These restrictions could be lifted by
+   handling them in mips_output_mi_thunk(); basically we would have to
+   store the contents in the code stream and load them from there.  */
+
+static bool
+mips_can_output_mi_thunk (tree thunk ATTRIBUTE_UNUSED,
+			  HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
+			  tree function ATTRIBUTE_UNUSED)
+{
+  /* We are always OK if we are not in MIPS16 mode.  */
+  if (! TARGET_MIPS16)
+    return true;
+  /* MIPS16 code can handle up to a 16 bit signed delta.  */
+  if (! SMALL_OPERAND (delta))
+    return false;
+  /* MIPS16 code can handle up to a 16 bit signed vcall_offset.  */
+  if (! SMALL_OPERAND (vcall_offset))
+    return false;
+  return true;
+}
+
+/* Output the assembler code for a thunk function.  THUNK_DECL is the
+   declaration for the thunk function itself.  FUNCTION is the
+   declaration for the target function.  DELTA is an immediate
+   constant offset to be added to THIS.  If VCALL_OFFSET is non-zero,
+   the word at *(*this + vcall_offset) should be added to THIS.  */
+
+static void
+mips_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
+		      tree thunk_fndecl ATTRIBUTE_UNUSED,
+		      HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
+		      tree function)
+{
+  rtx this;
+  rtx ops[3];
+  rtx funexp;
+
+  if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
+    this = gen_rtx_REG (Pmode, GP_ARG_FIRST + 1);
+  else
+    this = gen_rtx_REG (Pmode, GP_ARG_FIRST);
+
+  /* Rather than deal with large offsets ourselves, we just let the
+     assembler macros handle them for us.  The resulting code may not
+     be optimal, but the large offset case is going to be pretty
+     unusual anyhow.  */
+
+  if (delta != 0)
+    {
+      ops[0] = this;
+      ops[1] = this;
+      ops[2] = GEN_INT (delta);
+      if (TARGET_MIPS16)
+	{
+	  if (TARGET_64BIT)
+	    output_asm_insn ("daddu\t%0,%2", ops);
+	  else
+	    output_asm_insn ("addu\t%0,%2", ops);
+	}
+      else
+	{
+	  if (TARGET_64BIT)
+	    output_asm_insn ("daddu\t%0,%1,%2", ops);
+	  else
+	    output_asm_insn ("addu\t%0,%1,%2", ops);
+	}
+    }
+
+  if (vcall_offset != 0)
+    {
+      rtx tmp;
+
+      /* Use $2 as a temporary register.  It is where the return value
+	 is stored, and it can't hold anything meaningful at this
+	 point.  */
+      tmp = gen_rtx_REG (Pmode, GP_REG_FIRST + 2);
+
+      ops[0] = tmp;
+      ops[1] = gen_rtx_MEM (Pmode, this);
+      if (TARGET_64BIT)
+	output_asm_insn ("ld\t%0,%1", ops);
+      else
+	output_asm_insn ("lw\t%0,%1", ops);
+
+      /* Assembler macros will handle a large offset for us.  */
+      ops[0] = tmp;
+      ops[1] = gen_rtx_MEM (Pmode,
+			    gen_rtx_PLUS (Pmode, tmp,
+					  GEN_INT (vcall_offset)));
+      if (TARGET_64BIT)
+	output_asm_insn ("ld\t%0,%1", ops);
+      else
+	output_asm_insn ("lw\t%0,%1", ops);
+
+      ops[0] = this;
+      ops[1] = this;
+      ops[2] = tmp;
+      if (TARGET_64BIT)
+	output_asm_insn ("daddu\t%0,%1,%2", ops);
+      else
+	output_asm_insn ("addu\t%0,%1,%2", ops);
+    }
+
+  if (! TREE_USED (function))
+    {
+      assemble_external (function);
+      TREE_USED (function) = 1;
+    }
+  funexp = XEXP (DECL_RTL (function), 0);
+
+  if (TARGET_MIPS16)
+    {
+      rtx tmp;
+
+      tmp = gen_rtx_REG (Pmode, GP_REG_FIRST + 2);
+      ops[0] = tmp;
+      ops[1] = funexp;
+      if (TARGET_64BIT)
+	output_asm_insn ("dla\t%0,%1", ops);
+      else
+	output_asm_insn ("la\t%0,%1", ops);
+
+      ops[0] = tmp;
+      output_asm_insn ("jr\t%0", ops);
+    }
+  else if (! TARGET_ABICALLS)
+    {
+      ops[0] = funexp;
+      output_asm_insn ("j\t%0", ops);
+    }
+  else
+    {
+      rtx picreg;
+
+      /* The ABI requires that the address of the function we are
+	 calling be in $25 on function entry.  So we load the addres,
+	 and jump.  ??? This is not ideal, because the it will force
+	 the dynamic linker to resolve the function address at program
+	 startup time, rather than lazily.  I don't know of a reliable
+	 way to force lazy resolution of a function which is defined
+	 in the same object file.  Even lca doesn't seem to do the
+	 right thing.  This may be a gas bug.  */
+
+      picreg = gen_rtx_REG (Pmode, PIC_FUNCTION_ADDR_REGNUM);
+
+      ops[0] = picreg;
+      ops[1] = funexp;
+      if (TARGET_64BIT)
+	output_asm_insn ("dla\t%0,%1", ops);
+      else
+	output_asm_insn ("la\t%0,%1", ops);
+
+      ops[0] = picreg;
+      output_asm_insn ("jr\t%0", ops);
+    }
+}
 
 
 #if TARGET_IRIX


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]