void print_operand_address ();
char *index ();
+static int h8300_interrupt_function_p PROTO ((tree));
+static int h8300_funcvec_function_p PROTO ((tree));
+
/* CPU_TYPE, says what cpu we're compiling for. */
int cpu_type;
-/* True if a #pragma interrupt has been seen for the current function. */
-int pragma_interrupt;
+/* True if the current function is an interrupt handler
+ (either via #pragma or an attribute specification). */
+int interrupt_handler;
+
/* True if a #pragma saveall has been seen for the current function. */
int pragma_saveall;
#define WORD_REG_USED(regno) \
(regno < 7 && \
- (pragma_interrupt \
+ (interrupt_handler \
|| pragma_saveall \
|| (regno == FRAME_POINTER_REGNUM && regs_ever_live[regno]) \
|| (regs_ever_live[regno] & !call_used_regs[regno])))
int idx;
extra_pop = 0;
+ if (h8300_interrupt_function_p (current_function_decl))
+ interrupt_handler = 1;
+
if (current_function_anonymous_args && TARGET_QUICKCALL)
{
/* Push regs as if done by caller, and move around return address. */
}
else
{
- if (pragma_interrupt)
+ if (interrupt_handler)
fprintf (file, "\trte\n");
else
fprintf (file, "\trts\n");
}
- pragma_interrupt = 0;
+ interrupt_handler = 0;
pragma_saveall = 0;
current_function_anonymous_args = 0;
return 0;
}
+/* Return true if OP is a valid call operand, and OP represents
+ an operand for a small call (4 bytes instead of 6 bytes). */
+
+int
+small_call_insn_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (GET_CODE (op) == MEM)
+ {
+ rtx inside = XEXP (op, 0);
+
+ /* Register indirect is a small call. */
+ if (register_operand (inside, Pmode))
+ return 1;
+
+ /* A call through the function vector is a small
+ call too. */
+ if (GET_CODE (inside) == SYMBOL_REF
+ && SYMBOL_REF_FLAG (inside))
+ return 1;
+ }
+ /* Otherwise it's a large call. */
+ return 0;
+}
+
/* Return true if OP is a valid jump operand. */
int
pbuf[psize] = 0;
if (strcmp (pbuf, "interrupt") == 0)
- pragma_interrupt = 1;
+ interrupt_handler = 1;
else if (strcmp (pbuf, "saveall") == 0)
pragma_saveall = 1;
}
return 1;
}
+
+
+/* Return nonzero if FUNC is an interrupt function as specified
+ by the "interrupt" attribute. */
+
+static int
+h8300_interrupt_function_p (func)
+ tree func;
+{
+ tree a;
+
+ if (TREE_CODE (func) != FUNCTION_DECL)
+ return 0;
+
+ a = lookup_attribute ("interrupt-handler", DECL_MACHINE_ATTRIBUTES (func));
+ return a != NULL_TREE;
+}
+
+/* Return nonzero if FUNC is a function that should be called
+ through the function vector. */
+
+int
+h8300_funcvec_function_p (func)
+ tree func;
+{
+ tree a;
+
+ if (TREE_CODE (func) != FUNCTION_DECL)
+ return 0;
+
+ a = lookup_attribute ("function-vector", DECL_MACHINE_ATTRIBUTES (func));
+ return a != NULL_TREE;
+}
+
+/* Return nonzero if ATTR is a valid attribute for DECL.
+ ATTRIBUTES are any existing attributes and ARGS are the arguments
+ supplied with ATTR.
+
+ Supported attributes:
+
+ interrupt-handler: output a prologue and epilogue suitable for an
+ interrupt handler.
+
+ function-vector: This function should be called through the
+ function vector. */
+
+int
+h8300_valid_machine_decl_attribute (decl, attributes, attr, args)
+ tree decl;
+ tree attributes;
+ tree attr;
+ tree args;
+{
+ if (args != NULL_TREE)
+ return 0;
+
+ if (is_attribute_p ("interrupt-handler", attr)
+ || is_attribute_p ("function-vector", attr))
+ return TREE_CODE (decl) == FUNCTION_DECL;
+ return 0;
+}
+
so give the MEM rtx a byte's mode. */
#define FUNCTION_MODE QImode
+/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS
+ is a valid machine specific attribute for DECL.
+ The attributes in ATTRIBUTES have previously been assigned to DECL. */
+extern int h8300_valid_machine_decl_attribute ();
+#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \
+h8300_valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS)
+
/* Compute the cost of computing a constant rtl expression RTX
whose rtx-code is CODE. The body of this macro is a portion
of a switch statement. If the code is computed here,
} \
}
+/* If we are referencing a function that is supposed to be called
+ through the function vector, the SYMBOL_REF_FLAG in the rtl
+ so the call patterns can generate the correct code. */
+#define ENCODE_SECTION_INFO(DECL) \
+ if (TREE_CODE (DECL) == FUNCTION_DECL \
+ && h8300_funcvec_function_p (DECL)) \
+ SYMBOL_REF_FLAG (XEXP (DECL_RTL (DECL), 0)) = 1;
+
/* How to refer to registers in assembler output.
This sequence is indexed by compiler's hard-register-number (see above). */
[(call (match_operand:QI 0 "call_insn_operand" "or")
(match_operand:HI 1 "general_operand" "g"))]
""
- "jsr %0"
+ "*
+{
+ if (GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF
+ && SYMBOL_REF_FLAG (XEXP (operands[0], 0)))
+ return \"jsr\\t\@%0:8\";
+ else
+ return \"jsr\\t%0\";
+}"
[(set_attr "type" "call")
(set_attr "cc" "clobber")
- (set_attr "length" "4")])
+ (set (attr "length")
+ (if_then_else (match_operand:QI 0 "small_call_insn_operand" "")
+ (const_int 4)
+ (const_int 8)))])
;; Call subroutine, returning value in operand 0
;; (which must be a hard register).
(call (match_operand:QI 1 "call_insn_operand" "or")
(match_operand:HI 2 "general_operand" "g")))]
""
- "jsr %1"
+ "*
+{
+ if (GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF
+ && SYMBOL_REF_FLAG (XEXP (operands[1], 0)))
+ return \"jsr\\t\@%1:8\";
+ else
+ return \"jsr\\t%1\";
+}"
[(set_attr "type" "call")
(set_attr "cc" "clobber")
- (set_attr "length" "4")])
+ (set (attr "length")
+ (if_then_else (match_operand:QI 0 "small_call_insn_operand" "")
+ (const_int 4)
+ (const_int 8)))])
(define_insn "nop"
[(const_int 0)]