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]

[ColdFire 55/63] Add support for vcall_offset thunks


This patch makes m68k_output_mi_thunk hnour vcall_offset.  It was
easier to do this in rtl than by writing assembly directly, so the
patch converts the entire function to use rtl.

The main difficulty is in using a call-clobbered PIC register for the
duration of the thunk.  I've used the same PIC_OFFSET_TABLE_REGNUM trick
that x86 and MIPS use.

Richard


gcc/
	* config/m68k/m68k.h (PIC_OFFSET_TABLE_REGNUM): Use the REGNO
	of pic_offset_table_rtx if reload_completed.
	(CONDITIONAL_REGISTER_USAGE): Use PIC_REG instead of
	PIC_OFFSET_TABLE_REGNUM.
	* config/m68k/m68k.c (TARGET_ASM_CAN_OUTPUT_MI_THUNK): Always
	return true.
	(m68k_save_reg): Use PIC_REG instead of PIC_OFFSET_TABLE_REGNO.
	(m68k_output_mi_thunk): Rewrite to use RTL.  Honor vcall_offset.

Index: gcc/config/m68k/m68k.h
===================================================================
--- gcc/config/m68k/m68k.h	2007-01-09 16:12:15.000000000 +0000
+++ gcc/config/m68k/m68k.h	2007-01-09 16:12:15.000000000 +0000
@@ -316,7 +316,10 @@ #define MAX_LIBRARY_ID 255
 #define FIRST_PSEUDO_REGISTER 25
 
 /* All m68k targets (except AmigaOS) use %a5 as the PIC register  */
-#define PIC_OFFSET_TABLE_REGNUM (flag_pic ? 13 : INVALID_REGNUM)
+#define PIC_OFFSET_TABLE_REGNUM				\
+  (!flag_pic ? INVALID_REGNUM				\
+   : reload_completed ? REGNO (pic_offset_table_rtx)	\
+   : PIC_REG)
 
 /* 1 for registers that have pervasive standard uses
    and are not available for the register allocator.
@@ -383,9 +386,8 @@ #define CONDITIONAL_REGISTER_USAGE				\
         if (TEST_HARD_REG_BIT (x, i))				\
 	  fixed_regs[i] = call_used_regs[i] = 1;		\
     }								\
-  if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)		\
-    fixed_regs[PIC_OFFSET_TABLE_REGNUM]				\
-      = call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;		\
+  if (flag_pic)							\
+    fixed_regs[PIC_REG] = call_used_regs[PIC_REG] = 1;		\
 }
 
 /* On the m68k, ordinary registers hold 32 bits worth;
Index: gcc/config/m68k/m68k.c
===================================================================
--- gcc/config/m68k/m68k.c	2007-01-09 15:53:34.000000000 +0000
+++ gcc/config/m68k/m68k.c	2007-01-09 20:10:07.000000000 +0000
@@ -191,7 +191,7 @@ #define TARGET_ASM_UNALIGNED_SI_OP TARGE
 #undef TARGET_ASM_OUTPUT_MI_THUNK
 #define TARGET_ASM_OUTPUT_MI_THUNK m68k_output_mi_thunk
 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
-#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
 
 #undef TARGET_DEFAULT_TARGET_FLAGS
 #define TARGET_DEFAULT_TARGET_FLAGS MASK_STRICT_ALIGNMENT
@@ -742,7 +742,7 @@ m68k_initial_elimination_offset (int fro
 static bool
 m68k_save_reg (unsigned int regno, bool interrupt_handler)
 {
-  if (flag_pic && regno == PIC_OFFSET_TABLE_REGNUM)
+  if (flag_pic && regno == PIC_REG)
     {
       /* We need to restore the PIC register on exceptional returns.  */
       if (current_function_calls_eh_return)
@@ -4050,59 +4050,93 @@ m68k_coff_asm_named_section (const char 
 
 static void
 m68k_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
-		      HOST_WIDE_INT delta,
-		      HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
+		      HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
 		      tree function)
 {
-  rtx xops[1];
-  const char *fmt;
+  rtx this_slot, offset, addr, mem, insn;
 
-  if (delta > 0 && delta <= 8)
-    asm_fprintf (file, (MOTOROLA
-			? "\taddq.l %I%d,4(%Rsp)\n"
-			: "\taddql %I%d,%Rsp@(4)\n"),
-		 (int) delta);
-  else if (delta < 0 && delta >= -8)
-    asm_fprintf (file, (MOTOROLA
-			? "\tsubq.l %I%d,4(%Rsp)\n"
-			: "\tsubql %I%d,%Rsp@(4)\n"),
-		 (int) -delta);
-  else if (TARGET_COLDFIRE)
-    {
-      /* ColdFire can't add/sub a constant to memory unless it is in
-	 the range of addq/subq.  So load the value into %d0 and
-	 then add it to 4(%sp). */
-      if (delta >= -128 && delta <= 127)
-	asm_fprintf (file, (MOTOROLA
-			    ? "\tmoveq.l %I%wd,%Rd0\n"
-			    : "\tmoveql %I%wd,%Rd0\n"),
-		     delta);
-      else
-	asm_fprintf (file, (MOTOROLA
-			    ? "\tmove.l %I%wd,%Rd0\n"
-			    : "\tmovel %I%wd,%Rd0\n"),
-		     delta);
-      asm_fprintf (file, (MOTOROLA
-			  ? "\tadd.l %Rd0,4(%Rsp)\n"
-			  : "\taddl %Rd0,%Rsp@(4)\n"));
+  /* Pretend to be a post-reload pass while generating rtl.  */
+  no_new_pseudos = 1;
+  reload_completed = 1;
+  reset_block_changes ();
+  allocate_reg_info (FIRST_PSEUDO_REGISTER, true, true);
+
+  /* The "this" pointer is stored at 4(%sp).  */
+  this_slot = gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx, 4));
+
+  /* Add DELTA to THIS.  */
+  if (delta != 0)
+    {
+      /* Make the offset a legitimate operand for memory addition.  */
+      offset = GEN_INT (delta);
+      if ((delta < -8 || delta > 8)
+	  && (TARGET_COLDFIRE || USE_MOVQ (delta)))
+	{
+	  emit_move_insn (gen_rtx_REG (Pmode, D0_REG), offset);
+	  offset = gen_rtx_REG (Pmode, D0_REG);
+	}
+      emit_insn (gen_add3_insn (copy_rtx (this_slot),
+				copy_rtx (this_slot), offset));
     }
-  else
-    asm_fprintf (file, (MOTOROLA
-			? "\tadd.l %I%wd,4(%Rsp)\n"
-			: "\taddl %I%wd,%Rsp@(4)\n"),
-		 delta);
-
-  xops[0] = DECL_RTL (function);
-
-  gcc_assert (MEM_P (xops[0])
-	      && symbolic_operand (XEXP (xops[0], 0), VOIDmode));
-  xops[0] = XEXP (xops[0], 0);
-
-  fmt = m68k_symbolic_jump;
-  if (m68k_symbolic_jump == NULL)
-    fmt = "move.l %%a1@GOT(%%a5), %%a1\n\tjmp (%%a1)";
 
-  output_asm_insn (fmt, xops);
+  /* If needed, add *(*THIS + VCALL_OFFSET) to THIS.  */
+  if (vcall_offset != 0)
+    {
+      /* Set the static chain register to *THIS.  */
+      emit_move_insn (static_chain_rtx, this_slot);
+      emit_move_insn (static_chain_rtx, gen_rtx_MEM (Pmode, static_chain_rtx));
+
+      /* Set ADDR to a legitimate address for *THIS + VCALL_OFFSET.  */
+      addr = plus_constant (static_chain_rtx, vcall_offset);
+      if (!m68k_legitimate_address_p (Pmode, addr, true))
+	{
+	  emit_insn (gen_rtx_SET (VOIDmode, static_chain_rtx, addr));
+	  addr = static_chain_rtx;
+	}
+
+      /* Load the offset into %d0 and add it to THIS.  */
+      emit_move_insn (gen_rtx_REG (Pmode, D0_REG),
+		      gen_rtx_MEM (Pmode, addr));
+      emit_insn (gen_add3_insn (copy_rtx (this_slot),
+				copy_rtx (this_slot),
+				gen_rtx_REG (Pmode, D0_REG)));
+    }
+
+  /* Jump to the target function.  Use a sibcall if direct jumps are
+     allowed, otherwise load the address into a register first.  */
+  mem = DECL_RTL (function);
+  if (!sibcall_operand (XEXP (mem, 0), VOIDmode))
+    {
+      gcc_assert (flag_pic);
+
+      if (!TARGET_SEP_DATA)
+	{
+	  /* Use the static chain register as a temporary (call-clobbered)
+	     GOT pointer for this function.  We can use the static chain
+	     register because it isn't live on entry to the thunk.  */
+	  REGNO (pic_offset_table_rtx) = STATIC_CHAIN_REGNUM;
+	  emit_insn (gen_load_got (pic_offset_table_rtx));
+	}
+      legitimize_pic_address (XEXP (mem, 0), Pmode, static_chain_rtx);
+      mem = replace_equiv_address (mem, static_chain_rtx);
+    }
+  insn = emit_call_insn (gen_sibcall (mem, const0_rtx));
+  SIBLING_CALL_P (insn) = 1;
+
+  /* Run just enough of rest_of_compilation.  */
+  insn = get_insns ();
+  split_all_insns_noflow ();
+  final_start_function (insn, file, 1);
+  final (insn, file, 1);
+  final_end_function ();
+
+  /* Clean up the vars set above.  */
+  reload_completed = 0;
+  no_new_pseudos = 0;
+
+  /* Restore the original PIC register.  */
+  if (flag_pic)
+    REGNO (pic_offset_table_rtx) = PIC_REG;
 }
 
 /* Worker function for TARGET_STRUCT_VALUE_RTX.  */


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