This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[m32c] add bank_switch and fast_interrupt attributes
- From: DJ Delorie <dj at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 17 Aug 2009 18:25:09 -0400
- Subject: [m32c] add bank_switch and fast_interrupt attributes
Committed.
* config/m32c/m32c.md (UNS_FSETB, UNS_FREIT): New.
* config/m32c/prologue.md (epilogue_freit): New.
(fset_b): New.
* config/m32c/m32c.c (m32c_function_needs_enter): Add prototype.
(bank_switch_p): Likewise.
(fast_interrupt_p): Likewise.
(interrupt_p): Likewise.
(m32c_conditional_register_usage): Round memregs size up.
(need_to_save): We only need to save $a0 when we use ENTER.
(interrupt_p): Check for fast_interrupt too.
(bank_switch_p): New.
(fast_interrupt_p): New.
(m32c_attribute_table): Add bank_switch and fast_interrupt.
(m32c_emit_prolog): Support bank switching and fast interrupts.
* doc/extend.texi (Function Attributes): Add bank_switch and
fast_interrupt.
Index: doc/extend.texi
===================================================================
--- doc/extend.texi (revision 150861)
+++ doc/extend.texi (working copy)
@@ -2016,12 +2016,18 @@ behavior.
This attribute is useful for small inline wrappers which if possible
should appear during debugging as a unit, depending on the debug
info format it will either mean marking the function as artificial
or using the caller location for all instructions within the inlined
body.
+@item bank_switch
+@cindex interrupt handler functions
+When added to an interrupt handler with the M32C port, causes the
+prologue and epilogue to use bank switching to preserve the registers
+rather than saving them on the stack.
+
@item flatten
@cindex @code{flatten} function attribute
Generally, inlining into a function is limited. For a function marked with
this attribute, every call inside this function will be inlined, if possible.
Whether the function itself is considered for inlining depends on its size and
the current inlining parameters.
@@ -2269,12 +2275,19 @@ instead of using @code{rts}. The board-
the @code{rtc}.
On MeP targets this causes the compiler to use a calling convention
which assumes the called function is too far away for the built-in
addressing modes.
+@item fast_interrupt
+@cindex interrupt handler functions
+Use this attribute on the M32C port to indicate that the specified
+function is a fast interrupt handler. This is just like the
+@code{interrupt} attribute, except that @code{freit} is used to return
+instead of @code{reit}.
+
@item fastcall
@cindex functions that pop the argument stack on the 386
On the Intel 386, the @code{fastcall} attribute causes the compiler to
pass the first argument (if of integral type) in the register ECX and
the second argument (if of integral type) in the register EDX@. Subsequent
and other typed arguments are passed on the stack. The called function will
Index: config/m32c/m32c.c
===================================================================
--- config/m32c/m32c.c (revision 150861)
+++ config/m32c/m32c.c (working copy)
@@ -57,15 +57,19 @@ typedef enum
{
PP_pushm,
PP_popm,
PP_justcount
} Push_Pop_Type;
+static bool m32c_function_needs_enter (void);
static tree interrupt_handler (tree *, tree, tree, int, bool *);
static tree function_vector_handler (tree *, tree, tree, int, bool *);
static int interrupt_p (tree node);
+static int bank_switch_p (tree node);
+static int fast_interrupt_p (tree node);
+static int interrupt_p (tree node);
static bool m32c_asm_integer (rtx, unsigned int, int);
static int m32c_comp_type_attributes (const_tree, const_tree);
static bool m32c_fixed_condition_code_regs (unsigned int *, unsigned int *);
static struct machine_function *m32c_init_machine_status (void);
static void m32c_insert_attributes (tree, tree *);
static bool m32c_legitimate_address_p (enum machine_mode, rtx, bool);
@@ -490,13 +494,13 @@ m32c_conditional_register_usage (void)
int i;
if (0 <= target_memregs && target_memregs <= 16)
{
/* The command line option is bytes, but our "registers" are
16-bit words. */
- for (i = target_memregs/2; i < 8; i++)
+ for (i = (target_memregs+1)/2; i < 8; i++)
{
fixed_regs[MEM0_REGNO + i] = 1;
CLEAR_HARD_REG_BIT (reg_class_contents[MEM_REGS], MEM0_REGNO + i);
}
}
@@ -1252,13 +1256,16 @@ need_to_save (int regno)
return 0;
if (crtl->calls_eh_return)
return 1;
if (regno == FP_REGNO)
return 0;
if (cfun->machine->is_interrupt
- && (!cfun->machine->is_leaf || regno == A0_REGNO))
+ && (!cfun->machine->is_leaf
+ || (regno == A0_REGNO
+ && m32c_function_needs_enter ())
+ ))
return 1;
if (df_regs_ever_live_p (regno)
&& (!call_used_regs[regno] || cfun->machine->is_interrupt))
return 1;
return 0;
}
@@ -2730,12 +2737,40 @@ interrupt_p (tree node ATTRIBUTE_UNUSED)
while (list)
{
if (is_attribute_p ("interrupt", TREE_PURPOSE (list)))
return 1;
list = TREE_CHAIN (list);
}
+ return fast_interrupt_p (node);
+}
+
+/* Returns TRUE if the given tree has the "bank_switch" attribute. */
+static int
+bank_switch_p (tree node ATTRIBUTE_UNUSED)
+{
+ tree list = M32C_ATTRIBUTES (node);
+ while (list)
+ {
+ if (is_attribute_p ("bank_switch", TREE_PURPOSE (list)))
+ return 1;
+ list = TREE_CHAIN (list);
+ }
+ return 0;
+}
+
+/* Returns TRUE if the given tree has the "fast_interrupt" attribute. */
+static int
+fast_interrupt_p (tree node ATTRIBUTE_UNUSED)
+{
+ tree list = M32C_ATTRIBUTES (node);
+ while (list)
+ {
+ if (is_attribute_p ("fast_interrupt", TREE_PURPOSE (list)))
+ return 1;
+ list = TREE_CHAIN (list);
+ }
return 0;
}
static tree
interrupt_handler (tree * node ATTRIBUTE_UNUSED,
tree name ATTRIBUTE_UNUSED,
@@ -2843,12 +2878,14 @@ current_function_special_page_vector (rt
}
#undef TARGET_ATTRIBUTE_TABLE
#define TARGET_ATTRIBUTE_TABLE m32c_attribute_table
static const struct attribute_spec m32c_attribute_table[] = {
{"interrupt", 0, 0, false, false, false, interrupt_handler},
+ {"bank_switch", 0, 0, false, false, false, interrupt_handler},
+ {"fast_interrupt", 0, 0, false, false, false, interrupt_handler},
{"function_vector", 1, 1, true, false, false, function_vector_handler},
{0, 0, 0, 0, 0, 0, 0}
};
#undef TARGET_COMP_TYPE_ATTRIBUTES
#define TARGET_COMP_TYPE_ATTRIBUTES m32c_comp_type_attributes
@@ -3925,22 +3962,29 @@ m32c_emit_prologue (void)
cfun->machine->is_leaf = m32c_leaf_function_p ();
if (interrupt_p (cfun->decl))
{
cfun->machine->is_interrupt = 1;
complex_prologue = 1;
}
+ else if (bank_switch_p (cfun->decl))
+ warning (OPT_Wattributes,
+ "%<bank_switch%> has no effect on non-interrupt functions");
reg_save_size = m32c_pushm_popm (PP_justcount);
if (interrupt_p (cfun->decl))
- emit_insn (gen_pushm (GEN_INT (cfun->machine->intr_pushm)));
+ {
+ if (bank_switch_p (cfun->decl))
+ emit_insn (gen_fset_b ());
+ else if (cfun->machine->intr_pushm)
+ emit_insn (gen_pushm (GEN_INT (cfun->machine->intr_pushm)));
+ }
frame_size =
m32c_initial_elimination_offset (FB_REGNO, SP_REGNO) - reg_save_size;
if (frame_size == 0
- && !cfun->machine->is_interrupt
&& !m32c_function_needs_enter ())
cfun->machine->use_rts = 1;
if (frame_size > 254)
{
extra_frame_size = frame_size - 254;
@@ -3985,22 +4029,35 @@ m32c_emit_epilogue (void)
m32c_pushm_popm (PP_popm);
if (cfun->machine->is_interrupt)
{
enum machine_mode spmode = TARGET_A16 ? HImode : PSImode;
- emit_move_insn (gen_rtx_REG (spmode, A0_REGNO),
- gen_rtx_REG (spmode, FP_REGNO));
- emit_move_insn (gen_rtx_REG (spmode, SP_REGNO),
- gen_rtx_REG (spmode, A0_REGNO));
- if (TARGET_A16)
- emit_insn (gen_pophi_16 (gen_rtx_REG (HImode, FP_REGNO)));
- else
- emit_insn (gen_poppsi (gen_rtx_REG (PSImode, FP_REGNO)));
- emit_insn (gen_popm (GEN_INT (cfun->machine->intr_pushm)));
- if (TARGET_A16)
+ /* REIT clears B flag and restores $fp for us, but we still
+ have to fix up the stack. USE_RTS just means we didn't
+ emit ENTER. */
+ if (!cfun->machine->use_rts)
+ {
+ emit_move_insn (gen_rtx_REG (spmode, A0_REGNO),
+ gen_rtx_REG (spmode, FP_REGNO));
+ emit_move_insn (gen_rtx_REG (spmode, SP_REGNO),
+ gen_rtx_REG (spmode, A0_REGNO));
+ /* We can't just add this to the POPM because it would be in
+ the wrong order, and wouldn't fix the stack if we're bank
+ switching. */
+ if (TARGET_A16)
+ emit_insn (gen_pophi_16 (gen_rtx_REG (HImode, FP_REGNO)));
+ else
+ emit_insn (gen_poppsi (gen_rtx_REG (PSImode, FP_REGNO)));
+ }
+ if (!bank_switch_p (cfun->decl) && cfun->machine->intr_pushm)
+ emit_insn (gen_popm (GEN_INT (cfun->machine->intr_pushm)));
+
+ if (fast_interrupt_p (cfun->decl))
+ emit_jump_insn (gen_epilogue_freit ());
+ else if (TARGET_A16)
emit_jump_insn (gen_epilogue_reit_16 ());
else
emit_jump_insn (gen_epilogue_reit_24 ());
}
else if (cfun->machine->use_rts)
emit_jump_insn (gen_epilogue_rts ());
Index: config/m32c/prologue.md
===================================================================
--- config/m32c/prologue.md (revision 150861)
+++ config/m32c/prologue.md (working copy)
@@ -146,12 +146,21 @@
]
"TARGET_A24"
"reit"
[(set_attr "flags" "x")]
)
+(define_insn "epilogue_freit"
+ [(unspec [(const_int 0)] UNS_FREIT)
+ (return)
+ ]
+ ""
+ "freit"
+ [(set_attr "flags" "x")]
+ )
+
(define_insn "epilogue_rts"
[(return)
]
""
"rts"
[(set_attr "flags" "x")]
@@ -177,6 +186,14 @@
(define_insn "popm"
[(unspec [(match_operand 0 "const_int_operand" "i")] UNS_POPM)]
""
"popm\t%p0"
[(set_attr "flags" "n")]
)
+
+(define_insn "fset_b"
+ [(unspec [(const_int 0)] UNS_FSETB)]
+ ""
+ "fset\tB"
+ [(set_attr "flags" "n")]
+ )
+
Index: config/m32c/m32c.md
===================================================================
--- config/m32c/m32c.md (revision 150861)
+++ config/m32c/m32c.md (working copy)
@@ -44,12 +44,14 @@
(UNS_PUSHM 4)
(UNS_POPM 5)
(UNS_SMOVF 6)
(UNS_SSTR 7)
(UNS_SCMPU 8)
(UNS_SMOVU 9)
+ (UNS_FSETB 10)
+ (UNS_FREIT 11)
])
;; n = no change, x = clobbered. The first 16 values are chosen such
;; that the enum has one bit set for each flag.
(define_attr "flags" "x,c,z,zc,s,sc,sz,szc,o,oc,oz,ozc,os,osc,osz,oszc,n" (const_string "n"))
(define_asm_attributes [(set_attr "flags" "x")])