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]

[m68k] Add __attribute__((interrupt_handler)) - rev. 4


This patch introduces __attribute__((interrupt_handler)) support for m68k
targets.

This updated version incorporates some improvements suggested by
Gunther Nikl's review.

The interrupt_handler attribute is meant to be attached to FUNCTION_DECL
nodes because, unlike attributes for specifying different calling
conventions such 'cdecl', its pourpose is to generate a function which
isn't directly callable by C code. The only meaningful way to use such a
function is by placing its address in the processor interrupt vector table.


2003-09-11 Peter Barada <peter@baradas.org> Bernardo Innocenti <bernie@develer.com>

	* config/m68k/m68k.c (m68k_frame): Move before protos referencing it.
	* config/m68k/m68k.c (m68k_save_reg): Add boolean parameter
	`interrupt_handler'.
	* config/m68k/m68k.c (m68k_interrupt_function_p): New function.
	* config/m68k/m68k.c (m68k_handle_fndecl_attribute): Ditto.
	* config/m68k/m68k.c (m68k_compute_frame_layout): Ditto.
	* config/m68k/m68k.c (m68k_attribute_table): Define back-end specific
	attributes.
	* config/m68k/m68k.c (m68k_output_function_epilogue): Emit rte
	instruction for interrupt functions.


diff -Nru gcc-3.4-20030806.orig/gcc/config/m68k/m68k.c gcc-3.4-20030806/gcc/config/m68k/m68k.c --- gcc-3.4-20030806.orig/gcc/config/m68k/m68k.c 2003-08-07 19:06:25.000000000 +0200 +++ gcc-3.4-20030806/gcc/config/m68k/m68k.c 2003-08-07 19:21:01.000000000 +0200 @@ -45,6 +45,23 @@ /* Needed for use_return_insn. */ #include "flags.h"

+/* Structure describing stack frame layout. */
+struct m68k_frame {
+  HOST_WIDE_INT offset;
+  HOST_WIDE_INT size;
+  /* data and address register */
+  int reg_no;
+  unsigned int reg_mask;
+  unsigned int reg_rev_mask;
+  /* fpu registers */
+  int fpu_no;
+  unsigned int fpu_mask;
+  unsigned int fpu_rev_mask;
+  /* offsets relative to ARG_POINTER.  */
+  HOST_WIDE_INT frame_pointer_offset;
+  HOST_WIDE_INT stack_pointer_offset;
+};
+
/* This flag is used to communicate between movhi and ASM_OUTPUT_CASE_END,
   if SGS_SWITCH_TABLE.  */
int switch_table_difference_label_flag;
@@ -59,7 +77,12 @@
#endif
static void m68k_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
					  HOST_WIDE_INT, tree);
-static int m68k_save_reg (unsigned int);
+static bool m68k_interrupt_function_p (tree func);
+static tree m68k_handle_fndecl_attribute (tree *node, tree name,
+					  tree args, int flags,
+					  bool *no_add_attrs);
+static void m68k_compute_frame_layout (struct m68k_frame *frame);
+static bool m68k_save_reg (unsigned int regno, bool interrupt_handler);
static int const_int_cost (rtx);
static bool m68k_rtx_costs (rtx, int, int, int *);

@@ -138,6 +161,16 @@
#undef TARGET_RTX_COSTS
#define TARGET_RTX_COSTS m68k_rtx_costs

+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE m68k_attribute_table
+
+static const struct attribute_spec m68k_attribute_table[] =
+{
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+  { "interrupt_handler", 0, 0, true,  false, false, m68k_handle_fndecl_attribute },
+  { NULL,                0, 0, false, false, false, NULL }
+};
+
struct gcc_target targetm = TARGET_INITIALIZER;

/* Sometimes certain combinations of command options do not make
@@ -216,24 +249,37 @@
  real_format_for_mode[XFmode - QFmode] = &ieee_extended_motorola_format;
}

-/* Structure describing stack frame layout. */
-struct m68k_frame {
-  HOST_WIDE_INT offset;
-  HOST_WIDE_INT size;
-  /* data and address register */
-  int reg_no;
-  unsigned int reg_mask;
-  unsigned int reg_rev_mask;
-  /* fpu registers */
-  int fpu_no;
-  unsigned int fpu_mask;
-  unsigned int fpu_rev_mask;
-  /* fpa registers */
-  int fpa_no;
-  /* offsets relative to ARG_POINTER.  */
-  HOST_WIDE_INT frame_pointer_offset;
-  HOST_WIDE_INT stack_pointer_offset;
-};
+/* Return nonzero if FUNC is an interrupt function as specified by the
+   "interrupt_handler" attribute.  */
+static bool
+m68k_interrupt_function_p(tree func)
+{
+  tree a;
+
+  if (TREE_CODE (func) != FUNCTION_DECL)
+    return false;
+
+  a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
+  return (a != NULL_TREE);
+}
+
+/* Handle an attribute requiring a FUNCTION_DECL; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+m68k_handle_fndecl_attribute (tree *node, tree name,
+			      tree args ATTRIBUTE_UNUSED,
+			      int flags ATTRIBUTE_UNUSED,
+			      bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning ("`%s' attribute only applies to functions",
+	       IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}

static void
m68k_compute_frame_layout (struct m68k_frame *frame)
@@ -242,12 +290,13 @@
{
  int regno, saved;
  unsigned int mask, rmask;
+  bool interrupt_handler = m68k_interrupt_function_p (current_function_decl);

frame->size = (get_frame_size () + 3) & -4;

  mask = rmask = saved = 0;
  for (regno = 0; regno < 16; regno++)
-    if (m68k_save_reg (regno))
+    if (m68k_save_reg (regno, interrupt_handler))
      {
	mask |= 1 << regno;
	rmask |= 1 << (15 - regno);
@@ -311,13 +360,13 @@
  abort();
}

-/* Return 1 if we need to save REGNO.  */
-static int
-m68k_save_reg (unsigned int regno)
+/* Return true if we need to save REGNO. */
+static bool
+m68k_save_reg (unsigned int regno, bool interrupt_handler)
{
  if (flag_pic && current_function_uses_pic_offset_table
      && regno == PIC_OFFSET_TABLE_REGNUM)
-    return 1;
+    return true;

  if (current_function_calls_eh_return)
    {
@@ -329,14 +379,35 @@
	  if (test == INVALID_REGNUM)
	    break;
	  if (test == regno)
-	    return 1;
+	    return true;
	}
    }

-  return (regs_ever_live[regno]
-	  && !call_used_regs[regno]
-	  && !fixed_regs[regno]
-	  && !(regno == FRAME_POINTER_REGNUM && frame_pointer_needed));
+  /* Fixed regs we never touch.  */
+  if (fixed_regs[regno])
+    return false;
+
+  /* The frame pointer (if it is such) is handled specially.  */
+  if (regno == FRAME_POINTER_REGNUM && frame_pointer_needed)
+    return false;
+
+  /* Interrupt handlers must also save call_used_regs
+     if they are live or when calling nested functions.  */
+  if (interrupt_handler)
+  {
+     if (regs_ever_live[regno])
+       return true;
+
+     if (!current_function_is_leaf && call_used_regs[regno])
+       return true;
+  }
+
+  /* Never need to save registers that aren't touched.  */
+  if (!regs_ever_live[regno])
+    return false;
+
+  /* Otherwise save everthing that isn't call-clobbered.  */
+  return !call_used_regs[regno];
}

/* This function generates the assembly code for function entry.
@@ -363,6 +419,7 @@
HOST_WIDE_INT fsize = (size + 3) & -4;
HOST_WIDE_INT fsize_with_regs;
HOST_WIDE_INT cfa_offset = INCOMING_FRAME_SP_OFFSET;
+ bool interrupt_handler = m68k_interrupt_function_p (current_function_decl);
/* If the stack limit is a symbol, we can check it here,
before actually allocating the space. */
@@ -382,7 +439,7 @@
{
/* on Coldfire add register save into initial stack frame setup, if possible */
for (regno = 0; regno < 16; regno++)
- if (m68k_save_reg (regno))
+ if (m68k_save_reg (regno, interrupt_handler))
num_saved_regs++;


      if (num_saved_regs <= 2)
@@ -534,7 +591,7 @@
  if (TARGET_68881)
    {
      for (regno = 16; regno < 24; regno++)
-	if (m68k_save_reg (regno))
+	if (m68k_save_reg (regno, interrupt_handler))
	  {
	    mask |= 1 << (regno - 16);
	    num_saved_regs++;
@@ -567,7 +624,7 @@
      num_saved_regs = 0;
    }
  for (regno = 0; regno < 16; regno++)
-    if (m68k_save_reg (regno))
+    if (m68k_save_reg (regno, interrupt_handler))
      {
        mask |= 1 << (15 - regno);
        num_saved_regs++;
@@ -696,12 +753,15 @@
use_return_insn ()
{
  int regno;
+  bool interrupt_handler;

if (!reload_completed || frame_pointer_needed || get_frame_size () != 0)
return 0;
+ interrupt_handler = m68k_interrupt_function_p (current_function_decl);
+
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- if (m68k_save_reg (regno))
+ if (m68k_save_reg (regno, interrupt_handler))
return 0;


return 1;
@@ -729,6 +787,7 @@
int big = 0;
rtx insn = get_last_insn ();
int restore_from_sp = 0;
+ bool interrupt_handler = m68k_interrupt_function_p (current_function_decl);
/* If the last insn was a BARRIER, we don't have to write any code. */
if (GET_CODE (insn) == NOTE)
@@ -748,7 +807,7 @@
if (TARGET_68881)
{
for (regno = 16; regno < 24; regno++)
- if (m68k_save_reg (regno))
+ if (m68k_save_reg (regno, interrupt_handler))
{
nregs++;
fmask |= 1 << (23 - regno);
@@ -757,7 +816,7 @@
foffset = nregs * 12;
nregs = 0; mask = 0;
for (regno = 0; regno < 16; regno++)
- if (m68k_save_reg (regno))
+ if (m68k_save_reg (regno, interrupt_handler))
{
nregs++;
mask |= 1 << regno;
@@ -1049,7 +1108,9 @@
asm_fprintf (stream, "\taddl %Ra0,%Rsp\n");
#endif
}
- if (current_function_pops_args)
+ if (interrupt_handler)
+ fprintf (stream, "\trte\n");
+ else if (current_function_pops_args)
asm_fprintf (stream, "\trtd %I%d\n", current_function_pops_args);
else
fprintf (stream, "\trts\n");


--
 // Bernardo Innocenti - Develer S.r.l., R&D dept.
\X/  http://www.develer.com/

Please don't send Word attachments - http://www.gnu.org/philosophy/no-word-attachments.html




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