{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
{ "interrupt_handler", 0, 0, true, false, false, m68k_handle_fndecl_attribute },
+ { "interrupt_thread", 0, 0, true, false, false, m68k_handle_fndecl_attribute },
{ NULL, 0, 0, false, false, false, NULL }
};
return concat ("__m", prefix, "_family_", m68k_cpu_entry->family, NULL);
}
\f
-/* Return nonzero if FUNC is an interrupt function as specified by the
- "interrupt_handler" attribute. */
-bool
-m68k_interrupt_function_p (tree func)
+/* Return m68k_fk_interrupt_handler if FUNC has an "interrupt_handler"
+ attribute and interrupt_thread if FUNC has an "interrupt_thread"
+ attribute. Otherwise, return m68k_fk_normal_function. */
+
+enum m68k_function_kind
+m68k_get_function_kind (tree func)
{
tree a;
return false;
a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
- return (a != NULL_TREE);
+ if (a != NULL_TREE)
+ return m68k_fk_interrupt_handler;
+
+ a = lookup_attribute ("interrupt_thread", DECL_ATTRIBUTES (func));
+ if (a != NULL_TREE)
+ return m68k_fk_interrupt_thread;
+
+ return m68k_fk_normal_function;
}
/* Handle an attribute requiring a FUNCTION_DECL; arguments as in
*no_add_attrs = true;
}
+ if (m68k_get_function_kind (*node) != m68k_fk_normal_function)
+ {
+ error ("multiple interrupt attributes not allowed");
+ *no_add_attrs = true;
+ }
+
+ if (!TARGET_FIDOA
+ && !strcmp (IDENTIFIER_POINTER (name), "interrupt_thread"))
+ {
+ error ("interrupt_thread is available only on fido");
+ *no_add_attrs = true;
+ }
+
return NULL_TREE;
}
{
int regno, saved;
unsigned int mask;
- bool interrupt_handler = m68k_interrupt_function_p (current_function_decl);
+ enum m68k_function_kind func_kind =
+ m68k_get_function_kind (current_function_decl);
+ bool interrupt_handler = func_kind == m68k_fk_interrupt_handler;
+ bool interrupt_thread = func_kind == m68k_fk_interrupt_thread;
/* Only compute the frame once per function.
Don't cache information until reload has been completed. */
current_frame.size = (get_frame_size () + 3) & -4;
mask = saved = 0;
- for (regno = 0; regno < 16; regno++)
- if (m68k_save_reg (regno, interrupt_handler))
- {
- mask |= 1 << (regno - D0_REG);
- saved++;
- }
+
+ /* Interrupt thread does not need to save any register. */
+ if (!interrupt_thread)
+ for (regno = 0; regno < 16; regno++)
+ if (m68k_save_reg (regno, interrupt_handler))
+ {
+ mask |= 1 << (regno - D0_REG);
+ saved++;
+ }
current_frame.offset = saved * 4;
current_frame.reg_no = saved;
current_frame.reg_mask = mask;
mask = saved = 0;
if (TARGET_HARD_FLOAT)
{
- for (regno = 16; regno < 24; regno++)
- if (m68k_save_reg (regno, interrupt_handler))
- {
- mask |= 1 << (regno - FP0_REG);
- saved++;
- }
+ /* Interrupt thread does not need to save any register. */
+ if (!interrupt_thread)
+ for (regno = 16; regno < 24; regno++)
+ if (m68k_save_reg (regno, interrupt_handler))
+ {
+ mask |= 1 << (regno - FP0_REG);
+ saved++;
+ }
current_frame.foffset = saved * TARGET_FP_REG_SIZE;
current_frame.offset += current_frame.foffset;
}
if (count == 7
&& next_insn_tests_no_inequality (insn))
return "tst%.b %1";
+ /* Try to use `movew to ccr' followed by the appropriate branch insn.
+ On some m68k variants unfortunately that's slower than btst.
+ On 68000 and higher, that should also work for all HImode operands. */
+ if (TUNE_CPU32 || TARGET_COLDFIRE || optimize_size)
+ {
+ if (count == 3 && DATA_REG_P (operands[1])
+ && next_insn_tests_no_inequality (insn))
+ {
+ cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N | CC_NO_OVERFLOW;
+ return "move%.w %1,%%ccr";
+ }
+ if (count == 2 && DATA_REG_P (operands[1])
+ && next_insn_tests_no_inequality (insn))
+ {
+ cc_status.flags = CC_NOT_NEGATIVE | CC_INVERTED | CC_NO_OVERFLOW;
+ return "move%.w %1,%%ccr";
+ }
+ /* count == 1 followed by bvc/bvs and
+ count == 0 followed by bcc/bcs are also possible, but need
+ m68k-specific CC_Z_IN_NOT_V and CC_Z_IN_NOT_C flags. */
+ }
cc_status.flags = CC_NOT_NEGATIVE;
}
/* 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). */
saved by the prologue, even if they would normally be
call-clobbered. */
- if (m68k_interrupt_function_p (current_function_decl)
+ if ((m68k_get_function_kind (current_function_decl)
+ == m68k_fk_interrupt_handler)
&& !regs_ever_live[new_reg])
return 0;
case DFmode:
case XFmode:
if (TARGET_68881)
- return gen_rtx_REG (mode, 16);
+ return gen_rtx_REG (mode, FP0_REG);
break;
default:
break;
}
- return gen_rtx_REG (mode, 0);
+ return gen_rtx_REG (mode, D0_REG);
}
rtx
case DFmode:
case XFmode:
if (TARGET_68881)
- return gen_rtx_REG (mode, 16);
+ return gen_rtx_REG (mode, FP0_REG);
break;
default:
break;