#define GEN_ADD3 (*(TARGET_SHMEDIA64 ? gen_adddi3 : gen_addsi3))
#define GEN_SUB3 (*(TARGET_SHMEDIA64 ? gen_subdi3 : gen_subsi3))
+/* Used to simplify the logic below. Find the attributes wherever
+ they may be. */
+#define SH_ATTRIBUTES(decl) \
+ (TYPE_P (decl)) ? TYPE_ATTRIBUTES (decl) \
+ : DECL_ATTRIBUTES (decl) \
+ ? (DECL_ATTRIBUTES (decl)) \
+ : TYPE_ATTRIBUTES (TREE_TYPE (decl))
+
/* Set to 1 by expand_prologue() when the function is an interrupt handler. */
int current_function_interrupt;
static rtx mark_constant_pool_use (rtx);
const struct attribute_spec sh_attribute_table[];
static tree sh_handle_interrupt_handler_attribute (tree *, tree, tree, int, bool *);
+static tree sh_handle_resbank_handler_attribute (tree *, tree,
+ tree, int, bool *);
+static tree sh2a_handle_function_vector_handler_attribute (tree *, tree,
+ tree, int, bool *);
static tree sh_handle_sp_switch_attribute (tree *, tree, tree, int, bool *);
static tree sh_handle_trap_exit_attribute (tree *, tree, tree, int, bool *);
static tree sh_handle_renesas_attribute (tree *, tree, tree, int, bool *);
tree, bool);
static bool sh_scalar_mode_supported_p (enum machine_mode);
static int sh_dwarf_calling_convention (const_tree);
+static void sh_encode_section_info (tree, rtx, int);
+static int sh2a_function_vector_p (tree);
\f
/* Initialize the GCC target structure. */
/* Return current register pressure for regmode. */
#define CURR_REGMODE_PRESSURE(MODE) curr_regmode_pressure[((MODE) == SImode) ? 0 : 1]
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO sh_encode_section_info
+
#ifdef SYMBIAN
#undef TARGET_ENCODE_SECTION_INFO
#undef TARGET_SECONDARY_RELOAD
#define TARGET_SECONDARY_RELOAD sh_secondary_reload
+/* Machine-specific symbol_ref flags. */
+#define SYMBOL_FLAG_FUNCVEC_FUNCTION (SYMBOL_FLAG_MACH_DEP << 0)
+
struct gcc_target targetm = TARGET_INITIALIZER;
\f
/* Implement TARGET_HANDLE_OPTION. */
fprintf (stream, "trapa #%ld",
(long) TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (trapa_attr))));
else if (sh_cfun_interrupt_handler_p ())
- fprintf (stream, "rte");
+ {
+ if (sh_cfun_resbank_handler_p ())
+ fprintf (stream, "resbank\n");
+ fprintf (stream, "rte");
+ }
else
fprintf (stream, "rts");
break;
}
}
\f
+
+/* Encode symbol attributes of a SYMBOL_REF into its
+ SYMBOL_REF_FLAGS. */
+static void
+sh_encode_section_info (tree decl, rtx rtl, int first)
+{
+ default_encode_section_info (decl, rtl, first);
+
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && sh2a_function_vector_p (decl) && TARGET_SH2A)
+ SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_FUNCVEC_FUNCTION;
+}
+
/* Like force_operand, but guarantees that VALUE ends up in TARGET. */
static void
force_into (rtx value, rtx target)
if (i != PR_REG
&& (i != FPSCR_REG || ! skip_fpscr)
&& TEST_HARD_REG_BIT (*mask, i))
- push (i);
+ {
+ /* If the ISR has RESBANK attribute assigned, don't push any of
+ the following registers - R0-R14, MACH, MACL and GBR. */
+ if (! (sh_cfun_resbank_handler_p ()
+ && ((i >= FIRST_GENERAL_REG && i < LAST_GENERAL_REG)
+ || i == MACH_REG
+ || i == MACL_REG
+ || i == GBR_REG)))
+ push (i);
+ }
}
/* Push banked registers last to improve delay slot opportunities. */
if (TEST_HARD_REG_BIT (*mask, i))
push (i);
- if (TEST_HARD_REG_BIT (*mask, PR_REG))
+ /* Don't push PR register for an ISR with RESBANK attribute assigned. */
+ if (TEST_HARD_REG_BIT (*mask, PR_REG) && !sh_cfun_resbank_handler_p ())
push (PR_REG);
}
int last_reg;
save_size = 0;
- if (TEST_HARD_REG_BIT (live_regs_mask, PR_REG))
+ /* For an ISR with RESBANK attribute assigned, don't pop PR
+ register. */
+ if (TEST_HARD_REG_BIT (live_regs_mask, PR_REG)
+ && !sh_cfun_resbank_handler_p ())
{
if (!frame_pointer_needed)
emit_insn (gen_blockage ());
&& hard_reg_set_intersect_p (live_regs_mask,
reg_class_contents[DF_REGS]))
fpscr_deferred = 1;
- else if (j != PR_REG && TEST_HARD_REG_BIT (live_regs_mask, j))
+ /* For an ISR with RESBANK attribute assigned, don't pop
+ following registers, R0-R14, MACH, MACL and GBR. */
+ else if (j != PR_REG && TEST_HARD_REG_BIT (live_regs_mask, j)
+ && ! (sh_cfun_resbank_handler_p ()
+ && ((j >= FIRST_GENERAL_REG
+ && j < LAST_GENERAL_REG)
+ || j == MACH_REG
+ || j == MACL_REG
+ || j == GBR_REG)))
pop (j);
if (j == FIRST_FP_REG && fpscr_deferred)
java frontend. */
attrs
= tree_cons (get_identifier("interrupt_handler"), NULL_TREE, attrs);
- /* However, for sp_switch, trap_exit and nosave_low_regs, if the
- interrupt attribute is missing, we ignore the attribute and warn. */
+ /* However, for sp_switch, trap_exit, nosave_low_regs and resbank,
+ if the interrupt attribute is missing, we ignore the attribute
+ and warn. */
else if (lookup_attribute ("sp_switch", attrs)
|| lookup_attribute ("trap_exit", attrs)
- || lookup_attribute ("nosave_low_regs", attrs))
+ || lookup_attribute ("nosave_low_regs", attrs)
+ || lookup_attribute ("resbank", attrs))
{
tree *tail;
{
if (is_attribute_p ("sp_switch", TREE_PURPOSE (attrs))
|| is_attribute_p ("trap_exit", TREE_PURPOSE (attrs))
- || is_attribute_p ("nosave_low_regs", TREE_PURPOSE (attrs)))
+ || is_attribute_p ("nosave_low_regs", TREE_PURPOSE (attrs))
+ || is_attribute_p ("resbank", TREE_PURPOSE (attrs)))
warning (OPT_Wattributes,
"%qs attribute only applies to interrupt functions",
IDENTIFIER_POINTER (TREE_PURPOSE (attrs)));
renesas -- use Renesas calling/layout conventions (functions and
structures).
+ resbank -- In case of an ISR, use a register bank to save registers
+ R0-R14, MACH, MACL, GBR and PR. This is useful only on SH2A targets.
*/
const struct attribute_spec sh_attribute_table[] =
{ "renesas", 0, 0, false, true, false, sh_handle_renesas_attribute },
{ "trapa_handler", 0, 0, true, false, false, sh_handle_interrupt_handler_attribute },
{ "nosave_low_regs", 0, 0, true, false, false, sh_handle_interrupt_handler_attribute },
+ { "resbank", 0, 0, true, false, false, sh_handle_resbank_handler_attribute },
+ { "function_vector", 1, 1, true, false, false, sh2a_handle_function_vector_handler_attribute },
#ifdef SYMBIAN
/* Symbian support adds three new attributes:
dllexport - for exporting a function/variable that will live in a dll
{ NULL, 0, 0, false, false, false, NULL }
};
+/* Handle a 'resbank' attribute. */
+static tree
+sh_handle_resbank_handler_attribute (tree * node, tree name,
+ tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED,
+ bool * no_add_attrs)
+{
+ if (!TARGET_SH2A)
+ {
+ warning (OPT_Wattributes, "%qs attribute is supported only for SH2A",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qs attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
/* Handle an "interrupt_handler" attribute; arguments as in
struct attribute_spec.handler. */
static tree
sh_handle_interrupt_handler_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED,
- bool *no_add_attrs)
+ tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED,
+ bool *no_add_attrs)
{
if (TREE_CODE (*node) != FUNCTION_DECL)
{
warning (OPT_Wattributes, "%qs attribute only applies to functions",
- IDENTIFIER_POINTER (name));
+ IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
else if (TARGET_SHCOMPACT)
return NULL_TREE;
}
+/* Handle an 'function_vector' attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+sh2a_handle_function_vector_handler_attribute (tree * node, tree name,
+ tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED,
+ bool * no_add_attrs)
+{
+ if (!TARGET_SH2A)
+ {
+ warning (OPT_Wattributes, "%qs attribute only applies to SH2A",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qs attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else if (TREE_CODE (TREE_VALUE (args)) != INTEGER_CST)
+ {
+ /* The argument must be a constant integer. */
+ warning (OPT_Wattributes,
+ "`%s' attribute argument not an integer constant",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else if (TREE_INT_CST_LOW (TREE_VALUE (args)) > 255)
+ {
+ /* The argument value must be between 0 to 255. */
+ warning (OPT_Wattributes,
+ "`%s' attribute argument should be between 0 to 255",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ return NULL_TREE;
+}
+
+/* Returns 1 if current function has been assigned the attribute
+ 'function_vector'. */
+int
+sh2a_is_function_vector_call (rtx x)
+{
+ if (GET_CODE (x) == SYMBOL_REF
+ && (SYMBOL_REF_FLAGS (x) & SYMBOL_FLAG_FUNCVEC_FUNCTION))
+ {
+ tree tr = SYMBOL_REF_DECL (x);
+
+ if (sh2a_function_vector_p (tr))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Returns the function vector number, if the the attribute
+ 'function_vector' is assigned, otherwise returns zero. */
+int
+sh2a_get_function_vector_number (rtx x)
+{
+ int num;
+ tree list, t;
+
+ if ((GET_CODE (x) == SYMBOL_REF)
+ && (SYMBOL_REF_FLAGS (x) & SYMBOL_FLAG_FUNCVEC_FUNCTION))
+ {
+ t = SYMBOL_REF_DECL (x);
+
+ if (TREE_CODE (t) != FUNCTION_DECL)
+ return 0;
+
+ list = SH_ATTRIBUTES (t);
+ while (list)
+ {
+ if (is_attribute_p ("function_vector", TREE_PURPOSE (list)))
+ {
+ num = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (list)));
+ return num;
+ }
+
+ list = TREE_CHAIN (list);
+ }
+
+ return 0;
+ }
+ else
+ return 0;
+}
+
/* Handle an "sp_switch" attribute; arguments as in
struct attribute_spec.handler. */
static tree
!= NULL_TREE);
}
+/* Returns 1 if FUNC has been assigned the attribute
+ "function_vector". */
+int
+sh2a_function_vector_p (tree func)
+{
+ tree list;
+ if (TREE_CODE (func) != FUNCTION_DECL)
+ return 0;
+
+ list = SH_ATTRIBUTES (func);
+ while (list)
+ {
+ if (is_attribute_p ("function_vector", TREE_PURPOSE (list)))
+ return 1;
+
+ list = TREE_CHAIN (list);
+ }
+ return 0;
+}
+
+/* Returns TRUE if given tree has the "resbank" attribute. */
+
+int
+sh_cfun_resbank_handler_p (void)
+{
+ return ((lookup_attribute ("resbank",
+ DECL_ATTRIBUTES (current_function_decl))
+ != NULL_TREE)
+ && (lookup_attribute ("interrupt_handler",
+ DECL_ATTRIBUTES (current_function_decl))
+ != NULL_TREE) && TARGET_SH2A);
+}
+
/* Implement TARGET_CHECK_PCH_TARGET_FLAGS. */
static const char *
(use (reg:PSI FPSCR_REG))
(clobber (reg:SI PR_REG))]
"TARGET_SH1"
- "jsr @%0%#"
+ "*
+ {
+ if (TARGET_SH2A && (dbr_sequence_length () == 0))
+ return \"jsr/n\\t@%0\";
+ else
+ return \"jsr\\t@%0%#\";
+ }"
+
[(set_attr "type" "call")
(set (attr "fp_mode")
(if_then_else (eq_attr "fpu_single" "yes")
(set_attr "needs_delay_slot" "yes")
(set_attr "fp_set" "unknown")])
+;; This is TBR relative jump instruction for SH2A architecture.
+;; Its use is enabled assigning an attribute "function_vector"
+;; and the vector number to a function during its declaration.
+
+(define_insn "calli_tbr_rel"
+ [(call (mem (match_operand:SI 0 "symbol_ref_operand" ""))
+ (match_operand 1 "" ""))
+ (use (reg:PSI FPSCR_REG))
+ (clobber (reg:SI PR_REG))]
+ "TARGET_SH2A && sh2a_is_function_vector_call (operands[0])"
+ "*
+{
+ unsigned HOST_WIDE_INT vect_num;
+ vect_num = sh2a_get_function_vector_number (operands[0]);
+ operands[2] = GEN_INT (vect_num * 4);
+
+ return \"jsr/n\\t@@(%O2,tbr)\";
+}"
+ [(set_attr "type" "call")
+ (set (attr "fp_mode")
+ (if_then_else (eq_attr "fpu_single" "yes")
+ (const_string "single") (const_string "double")))
+ (set_attr "needs_delay_slot" "no")
+ (set_attr "fp_set" "unknown")])
+
;; This is a pc-rel call, using bsrf, for use with PIC.
(define_insn "calli_pcrel"
(use (reg:PSI FPSCR_REG))
(clobber (reg:SI PR_REG))]
"TARGET_SH1"
- "jsr @%1%#"
+ "*
+ {
+ if (TARGET_SH2A && (dbr_sequence_length () == 0))
+ return \"jsr/n\\t@%1\";
+ else
+ return \"jsr\\t@%1%#\";
+ }"
[(set_attr "type" "call")
(set (attr "fp_mode")
(if_then_else (eq_attr "fpu_single" "yes")
(set_attr "needs_delay_slot" "yes")
(set_attr "fp_set" "unknown")])
+;; This is TBR relative jump instruction for SH2A architecture.
+;; Its use is enabled assigning an attribute "function_vector"
+;; and the vector number to a function during its declaration.
+
+(define_insn "call_valuei_tbr_rel"
+ [(set (match_operand 0 "" "=rf")
+ (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" ""))
+ (match_operand 2 "" "")))
+ (use (reg:PSI FPSCR_REG))
+ (clobber (reg:SI PR_REG))]
+ "TARGET_SH2A && sh2a_is_function_vector_call (operands[1])"
+ "*
+{
+ unsigned HOST_WIDE_INT vect_num;
+ vect_num = sh2a_get_function_vector_number (operands[1]);
+ operands[3] = GEN_INT (vect_num * 4);
+
+ return \"jsr/n\\t@@(%O3,tbr)\";
+}"
+ [(set_attr "type" "call")
+ (set (attr "fp_mode")
+ (if_then_else (eq_attr "fpu_single" "yes")
+ (const_string "single") (const_string "double")))
+ (set_attr "needs_delay_slot" "no")
+ (set_attr "fp_set" "unknown")])
+
(define_insn "call_valuei_pcrel"
[(set (match_operand 0 "" "=rf")
(call (mem:SI (match_operand:SI 1 "arith_reg_operand" "r"))
emit_insn (gen_symGOTPLT2reg (reg, XEXP (operands[0], 0)));
XEXP (operands[0], 0) = reg;
}
+ if (!flag_pic && TARGET_SH2A
+ && GET_CODE (operands[0]) == MEM
+ && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF)
+ {
+ if (sh2a_is_function_vector_call (XEXP (operands[0], 0)))
+ {
+ emit_call_insn (gen_calli_tbr_rel (XEXP (operands[0], 0),
+ operands[1]));
+ DONE;
+ }
+ }
if (flag_pic && TARGET_SH2
&& GET_CODE (operands[0]) == MEM
&& GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF)
emit_insn (gen_symGOTPLT2reg (reg, XEXP (operands[1], 0)));
XEXP (operands[1], 0) = reg;
}
+ if (!flag_pic && TARGET_SH2A
+ && GET_CODE (operands[1]) == MEM
+ && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF)
+ {
+ if (sh2a_is_function_vector_call (XEXP (operands[1], 0)))
+ {
+ emit_call_insn (gen_call_valuei_tbr_rel (operands[0],
+ XEXP (operands[1], 0), operands[2]));
+ DONE;
+ }
+ }
if (flag_pic && TARGET_SH2
&& GET_CODE (operands[1]) == MEM
&& GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF)
&& reload_completed
&& lookup_attribute (\"trap_exit\",
DECL_ATTRIBUTES (current_function_decl)) == NULL_TREE"
- "%@ %#"
+ "*
+ {
+ if (TARGET_SH2A && (dbr_sequence_length () == 0)
+ && !current_function_interrupt)
+ return \"rts/n\";
+ else
+ return \"%@ %#\";
+ }"
[(set_attr "type" "return")
(set_attr "needs_delay_slot" "yes")])
Controlling C Dialect}.
@item function_vector
-@cindex calling functions through the function vector on H8/300, M16C, and M32C processors
+@cindex calling functions through the function vector on H8/300, M16C, M32C and SH2A processors
Use this attribute on the H8/300, H8/300H, and H8S to indicate that the specified
function should be called through the function vector. Calling a
function through the function vector will reduce code size, however;
the function vector has a limited size (maximum 128 entries on the H8/300
and 64 entries on the H8/300H and H8S) and shares space with the interrupt vector.
+In SH2A target, this attribute declares a function to be called using the
+TBR relative addressing mode. The argument to this attribute is the entry
+number of the same function in a vector table containing all the TBR
+relative addressable functions. For the successful jump, register TBR
+should contain the start address of this TBR relative vector table.
+In the startup routine of the user application, user needs to care of this
+TBR register initialization. The TBR relative vector table can have at
+max 256 function entries. The jumps to these functions will be generated
+using a SH2A specific, non delayed branch instruction JSR/N @@(disp8,TBR).
You must use GAS and GLD from GNU binutils version 2.7 or later for
this attribute to work correctly.
+Please refer the example of M16C target, to see the use of this
+attribute while declaring a function,
+
+In an application, for a function being called once, this attribute will
+save at least 8 bytes of code; and if other successive calls are being
+made to the same function, it will save 2 bytes of code per each of these
+calls.
+
On M16C/M32C targets, the @code{function_vector} attribute declares a
special page subroutine call function. Use of this attribute reduces
the code size by 2 bytes for each call generated to the
attribute is incompatible with nested functions; this is considered a
hard error.
+@item resbank
+@cindex @code{resbank} attribute
+On the SH2A target, this attribute enables the high-speed register
+saving and restoration using a register bank for @code{interrupt_handler}
+routines. Saving to the bank is performed automatcially after the CPU
+accepts an interrupt that uses a register bank.
+
+The nineteen 32-bit registers comprising general register R0 to R14,
+control register GBR, and system registers MACH, MACL, and PR and the
+vector table address offset are saved into a register bank. Register
+banks are stacked in first-in last-out (FILO) sequence. Restoration
+from the bank is executed by issuing a RESBANK instruction.
+
@item returns_twice
@cindex @code{returns_twice} attribute
The @code{returns_twice} attribute tells the compiler that a function may