+2017-07-17 Claudiu Zissulescu <claziss@synopsys.com>
+ Andrew Burgess <andrew.burgess@embecosm.com>
+
+ * config/arc/arc-protos.h (arc_compute_function_type): Change prototype.
+ (arc_return_address_register): New function.
+ * config/arc/arc.c (arc_handle_fndecl_attribute): New function.
+ (arc_handle_fndecl_attribute): Add naked attribute.
+ (TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS): Define.
+ (TARGET_WARN_FUNC_RETURN): Likewise.
+ (arc_allocate_stack_slots_for_args): New function.
+ (arc_warn_func_return): Likewise.
+ (machine_function): Change type fn_type.
+ (arc_compute_function_type): Consider new naked function type,
+ change function return type.
+ (arc_must_save_register): Adapt to handle new
+ arc_compute_function_type's return type.
+ (arc_expand_prologue): Likewise.
+ (arc_expand_epilogue): Likewise.
+ (arc_return_address_regs): Delete.
+ (arc_return_address_register): New function.
+ (arc_epilogue_uses): Use above function.
+ * config/arc/arc.h (arc_return_address_regs): Delete prototype.
+ (arc_function_type): Change encoding, add naked type.
+ (ARC_INTERRUPT_P): Change to handle the new encoding.
+ (ARC_FAST_INTERRUPT_P): Likewise.
+ (ARC_NORMAL_P): Define.
+ (ARC_NAKED_P): Likewise.
+ (arc_compute_function_type): Delete prototype.
+ * config/arc/arc.md (in_ret_delay_slot): Use
+ arc_return_address_register function.
+ (simple_return): Likewise.
+ (p_return_i): Likewise.
+
2017-07-17 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/81428
static int get_arc_condition_code (rtx);
static tree arc_handle_interrupt_attribute (tree *, tree, tree, int, bool *);
+static tree arc_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
/* Initialized arc_attribute_table to NULL since arc doesnot have any
machine specific supported attributes. */
/* And these functions are always known to reside within the 21 bit
addressing range of blcc. */
{ "short_call", 0, 0, false, true, true, NULL, false },
+ /* Function which are not having the prologue and epilogue generated
+ by the compiler. */
+ { "naked", 0, 0, true, false, false, arc_handle_fndecl_attribute, false },
{ NULL, 0, 0, false, false, false, NULL, false }
};
static int arc_comp_type_attributes (const_tree, const_tree);
#define TARGET_DIFFERENT_ADDR_DISPLACEMENT_P hook_bool_void_true
#define TARGET_SPILL_CLASS arc_spill_class
+#undef TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS
+#define TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS arc_allocate_stack_slots_for_args
+
+#undef TARGET_WARN_FUNC_RETURN
+#define TARGET_WARN_FUNC_RETURN arc_warn_func_return
+
#include "target-def.h"
#undef TARGET_ASM_ALIGNED_HI_OP
return NULL_TREE;
}
+static tree
+arc_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 (OPT_Wattributes, "%qE attribute only applies to functions",
+ name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Implement `TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS' */
+
+static bool
+arc_allocate_stack_slots_for_args (void)
+{
+ /* Naked functions should not allocate stack slots for arguments. */
+ unsigned int fn_type = arc_compute_function_type (cfun);
+
+ return !ARC_NAKED_P(fn_type);
+}
+
+/* Implement `TARGET_WARN_FUNC_RETURN'. */
+
+static bool
+arc_warn_func_return (tree decl)
+{
+ struct function *func = DECL_STRUCT_FUNCTION (decl);
+ unsigned int fn_type = arc_compute_function_type (func);
+
+ return !ARC_NAKED_P (fn_type);
+}
+
/* Return zero if TYPE1 and TYPE are incompatible, one if they are compatible,
and two if they are nearly compatible (which causes a warning to be
generated). */
typedef struct GTY (()) machine_function
{
- enum arc_function_type fn_type;
+ unsigned int fn_type;
struct arc_frame_info frame_info;
/* To keep track of unalignment caused by short insns. */
int unalign;
The result is cached. To reset the cache at the end of a function,
call with DECL = NULL_TREE. */
-enum arc_function_type
+unsigned int
arc_compute_function_type (struct function *fun)
{
- tree decl = fun->decl;
- tree a;
- enum arc_function_type fn_type = fun->machine->fn_type;
+ tree attr, decl = fun->decl;
+ unsigned int fn_type = fun->machine->fn_type;
if (fn_type != ARC_FUNCTION_UNKNOWN)
return fn_type;
- /* Assume we have a normal function (not an interrupt handler). */
- fn_type = ARC_FUNCTION_NORMAL;
+ /* Check if it is a naked function. */
+ if (lookup_attribute ("naked", DECL_ATTRIBUTES (decl)) != NULL_TREE)
+ fn_type |= ARC_FUNCTION_NAKED;
+ else
+ fn_type |= ARC_FUNCTION_NORMAL;
/* Now see if this is an interrupt handler. */
- for (a = DECL_ATTRIBUTES (decl);
- a;
- a = TREE_CHAIN (a))
- {
- tree name = TREE_PURPOSE (a), args = TREE_VALUE (a);
-
- if (name == get_identifier ("interrupt")
- && list_length (args) == 1
- && TREE_CODE (TREE_VALUE (args)) == STRING_CST)
- {
- tree value = TREE_VALUE (args);
-
- if (!strcmp (TREE_STRING_POINTER (value), "ilink1")
- || !strcmp (TREE_STRING_POINTER (value), "ilink"))
- fn_type = ARC_FUNCTION_ILINK1;
- else if (!strcmp (TREE_STRING_POINTER (value), "ilink2"))
- fn_type = ARC_FUNCTION_ILINK2;
- else if (!strcmp (TREE_STRING_POINTER (value), "firq"))
- fn_type = ARC_FUNCTION_FIRQ;
- else
- gcc_unreachable ();
- break;
- }
+ attr = lookup_attribute ("interrupt", DECL_ATTRIBUTES (decl));
+ if (attr != NULL_TREE)
+ {
+ tree value, args = TREE_VALUE (attr);
+
+ gcc_assert (list_length (args) == 1);
+ value = TREE_VALUE (args);
+ gcc_assert (TREE_CODE (value) == STRING_CST);
+
+ if (!strcmp (TREE_STRING_POINTER (value), "ilink1")
+ || !strcmp (TREE_STRING_POINTER (value), "ilink"))
+ fn_type |= ARC_FUNCTION_ILINK1;
+ else if (!strcmp (TREE_STRING_POINTER (value), "ilink2"))
+ fn_type |= ARC_FUNCTION_ILINK2;
+ else if (!strcmp (TREE_STRING_POINTER (value), "firq"))
+ fn_type |= ARC_FUNCTION_FIRQ;
+ else
+ gcc_unreachable ();
}
return fun->machine->fn_type = fn_type;
static bool
arc_must_save_register (int regno, struct function *func)
{
- enum arc_function_type fn_type = arc_compute_function_type (func);
+ unsigned int fn_type = arc_compute_function_type (func);
bool irq_auto_save_p = ((irq_ctrl_saved.irq_save_last_reg >= regno)
&& ARC_AUTO_IRQ_P (fn_type));
bool firq_auto_save_p = ARC_FAST_INTERRUPT_P (fn_type);
Change the stack layout so that we rather store a high register with the
PRE_MODIFY, thus enabling more short insn generation.) */
int first_offset = 0;
- enum arc_function_type fn_type = arc_compute_function_type (cfun);
+ unsigned int fn_type = arc_compute_function_type (cfun);
+
+ /* Naked functions don't have prologue. */
+ if (ARC_NAKED_P (fn_type))
+ return;
size = ARC_STACK_ALIGN (size);
arc_expand_epilogue (int sibcall_p)
{
int size = get_frame_size ();
- enum arc_function_type fn_type = arc_compute_function_type (cfun);
+ unsigned int fn_type = arc_compute_function_type (cfun);
size = ARC_STACK_ALIGN (size);
size = (!cfun->machine->frame_info.initialized
int millicode_p = cfun->machine->frame_info.millicode_end_reg > 0;
rtx insn;
+ /* Naked functions don't have epilogue. */
+ if (ARC_NAKED_P (fn_type))
+ return;
+
size_to_deallocate = size;
frame_size = size - (pretend_size +
return true;
}
-int arc_return_address_regs[5] =
- {0, RETURN_ADDR_REGNUM, ILINK1_REGNUM, ILINK2_REGNUM, ILINK1_REGNUM};
+/* Return the register number of the register holding the return address
+ for a function of type TYPE. */
+
+int
+arc_return_address_register (unsigned int fn_type)
+{
+ int regno = 0;
+
+ if (ARC_INTERRUPT_P (fn_type))
+ {
+ if (((fn_type & ARC_FUNCTION_ILINK1) | ARC_FUNCTION_FIRQ) != 0)
+ regno = ILINK1_REGNUM;
+ else if ((fn_type & ARC_FUNCTION_ILINK2) != 0)
+ regno = ILINK2_REGNUM;
+ else
+ gcc_unreachable ();
+ }
+ else if (ARC_NORMAL_P (fn_type) || ARC_NAKED_P (fn_type))
+ regno = RETURN_ADDR_REGNUM;
+
+ gcc_assert (regno != 0);
+ return regno;
+}
-/* Implement EPILOGUE__USES.
+/* Implement EPILOGUE_USES.
Return true if REGNO should be added to the deemed uses of the epilogue.
- We use the return address
- arc_return_address_regs[arc_compute_function_type (cfun)]. But
- also, we have to make sure all the register restore instructions
- are known to be live in interrupt functions, plus the blink
- register if it is clobbered by the isr. */
+ We have to make sure all the register restore instructions are
+ known to be live in interrupt functions, plus the blink register if
+ it is clobbered by the isr. */
bool
arc_epilogue_uses (int regno)
{
+ unsigned int fn_type;
+
if (regno == arc_tp_regno)
return true;
+
+ fn_type = arc_compute_function_type (cfun);
if (reload_completed)
{
if (ARC_INTERRUPT_P (cfun->machine->fn_type))
{
if (!fixed_regs[regno])
return true;
- return ((regno == arc_return_address_regs[cfun->machine->fn_type])
+ return ((regno == arc_return_address_register (fn_type))
|| (regno == RETURN_ADDR_REGNUM));
}
else
return regno == RETURN_ADDR_REGNUM;
}
else
- return regno == arc_return_address_regs[arc_compute_function_type (cfun)];
+ return regno == arc_return_address_register (fn_type);
}
/* Helper for EH_USES macro. */
#define ASM_OUTPUT_ALIGNED_DECL_LOCAL(STREAM, DECL, NAME, SIZE, ALIGNMENT) \
arc_asm_output_aligned_decl_local (STREAM, DECL, NAME, SIZE, ALIGNMENT, 0)
-/* To translate the return value of arc_function_type into a register number
- to jump through for function return. */
-extern int arc_return_address_regs[5];
-
/* Debugging information. */
/* Generate DBX and DWARF debugging information. */
/* ARC function types. */
enum arc_function_type {
- ARC_FUNCTION_UNKNOWN, ARC_FUNCTION_NORMAL,
+ /* No function should have the unknown type. This value is used to
+ indicate the that function type has not yet been computed. */
+ ARC_FUNCTION_UNKNOWN = 0,
+
+ /* The normal function type indicates that the function has the
+ standard prologue and epilogue. */
+ ARC_FUNCTION_NORMAL = 1 << 0,
/* These are interrupt handlers. The name corresponds to the register
name that contains the return address. */
- ARC_FUNCTION_ILINK1, ARC_FUNCTION_ILINK2,
+ ARC_FUNCTION_ILINK1 = 1 << 1,
+ ARC_FUNCTION_ILINK2 = 1 << 2,
/* Fast interrupt is only available on ARCv2 processors. */
- ARC_FUNCTION_FIRQ
+ ARC_FUNCTION_FIRQ = 1 << 3,
+ /* The naked function type indicates that the function does not have
+ prologue or epilogue, and that no stack frame is available. */
+ ARC_FUNCTION_NAKED = 1 << 4
};
-#define ARC_INTERRUPT_P(TYPE) \
- (((TYPE) == ARC_FUNCTION_ILINK1) || ((TYPE) == ARC_FUNCTION_ILINK2) \
- || ((TYPE) == ARC_FUNCTION_FIRQ))
-#define ARC_FAST_INTERRUPT_P(TYPE) ((TYPE) == ARC_FUNCTION_FIRQ)
+/* Check if a function is an interrupt function. */
+#define ARC_INTERRUPT_P(TYPE) \
+ (((TYPE) & (ARC_FUNCTION_ILINK1 | ARC_FUNCTION_ILINK2 \
+ | ARC_FUNCTION_FIRQ)) != 0)
+
+/* Check if a function is a fast interrupt function. */
+#define ARC_FAST_INTERRUPT_P(TYPE) (((TYPE) & ARC_FUNCTION_FIRQ) != 0)
+
+/* Check if a function is normal, that is, has standard prologue and
+ epilogue. */
+#define ARC_NORMAL_P(TYPE) (((TYPE) & ARC_FUNCTION_NORMAL) != 0)
-/* Compute the type of a function from its DECL. Needed for EPILOGUE_USES. */
-struct function;
-extern enum arc_function_type arc_compute_function_type (struct function *);
+/* Check if a function is naked. */
+#define ARC_NAKED_P(TYPE) (((TYPE) & ARC_FUNCTION_NAKED) != 0)
/* Called by crtstuff.c to make calls to function FUNCTION that are defined in
SECTION_OP, and then to switch back to text section. */