* Claudiu Zissulescu <claudiu.zissule...@synopsys.com> [2017-06-19 11:52:31 +0200]:
> From: claziss <claz...@synopsys.com> > > Hi Andrew, > > Apologizes for the disconfort, please find the patch that works on the head. > > Thanks, > Claudiu > > gcc/ > 2016-12-13 Claudiu Zissulescu <claz...@synopsys.com> > Andrew Burgess <andrew.burg...@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. > > gcc/testsuite > 2016-12-13 Claudiu Zissulescu <claz...@synopsys.com> > Andrew Burgess <andrew.burg...@embecosm.com> > > * gcc.target/arc/naked-1.c: New file. > * gcc.target/arc/naked-2.c: Likewise. This all looks fine, Thanks, Andrew > --- > gcc/config/arc/arc-protos.h | 7 +- > gcc/config/arc/arc.c | 160 > ++++++++++++++++++++++++--------- > gcc/config/arc/arc.h | 40 ++++++--- > gcc/config/arc/arc.md | 10 ++- > gcc/testsuite/gcc.target/arc/naked-1.c | 18 ++++ > gcc/testsuite/gcc.target/arc/naked-2.c | 26 ++++++ > 6 files changed, 195 insertions(+), 66 deletions(-) > create mode 100644 gcc/testsuite/gcc.target/arc/naked-1.c > create mode 100644 gcc/testsuite/gcc.target/arc/naked-2.c > > diff --git a/gcc/config/arc/arc-protos.h b/gcc/config/arc/arc-protos.h > index 93a64cf..f6bf14e 100644 > --- a/gcc/config/arc/arc-protos.h > +++ b/gcc/config/arc/arc-protos.h > @@ -45,13 +45,10 @@ extern void arc_expand_atomic_op (enum rtx_code, rtx, > rtx, rtx, rtx, rtx); > extern void arc_split_compare_and_swap (rtx *); > extern void arc_expand_compare_and_swap (rtx *); > extern bool compact_memory_operand_p (rtx, machine_mode, bool, bool); > +extern int arc_return_address_register (unsigned int); > +extern unsigned int arc_compute_function_type (struct function *); > #endif /* RTX_CODE */ > > -#ifdef TREE_CODE > -extern enum arc_function_type arc_compute_function_type (struct function *); > -#endif /* TREE_CODE */ > - > - > extern unsigned int arc_compute_frame_size (int); > extern bool arc_ccfsm_branch_deleted_p (void); > extern void arc_ccfsm_record_branch_deleted (void); > diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c > index d9ad139..4ccd304 100644 > --- a/gcc/config/arc/arc.c > +++ b/gcc/config/arc/arc.c > @@ -211,6 +211,7 @@ static int rgf_banked_register_count; > 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. */ > @@ -229,6 +230,9 @@ const struct attribute_spec arc_attribute_table[] = > /* 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); > @@ -513,6 +517,12 @@ static void arc_finalize_pic (void); > #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 > @@ -1856,6 +1866,42 @@ arc_handle_interrupt_attribute (tree *, tree name, > tree args, int, > 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). */ > @@ -2359,7 +2405,7 @@ struct GTY (()) arc_frame_info > > 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; > @@ -2377,43 +2423,40 @@ typedef struct GTY (()) machine_function > 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; > @@ -2434,7 +2477,7 @@ arc_compute_function_type (struct function *fun) > 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); > @@ -2879,7 +2922,11 @@ arc_expand_prologue (void) > 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); > > @@ -2990,7 +3037,7 @@ void > 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 > @@ -3006,6 +3053,10 @@ arc_expand_epilogue (int sibcall_p) > 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 + > @@ -9789,37 +9840,60 @@ arc_can_follow_jump (const rtx_insn *follower, const > rtx_insn *followee) > 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. */ > diff --git a/gcc/config/arc/arc.h b/gcc/config/arc/arc.h > index 5627eb4..149e876 100644 > --- a/gcc/config/arc/arc.h > +++ b/gcc/config/arc/arc.h > @@ -1363,10 +1363,6 @@ do { \ > #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. */ > @@ -1499,22 +1495,38 @@ extern struct rtx_def *arc_compare_op0, > *arc_compare_op1; > > /* 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. */ > diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md > index 9aa9cd7..0d14085 100644 > --- a/gcc/config/arc/arc.md > +++ b/gcc/config/arc/arc.md > @@ -505,8 +505,8 @@ > (cond [(eq_attr "in_delay_slot" "false") > (const_string "no") > (match_test "regno_clobbered_p > - (arc_return_address_regs > - [arc_compute_function_type (cfun)], > + (arc_return_address_register > + (arc_compute_function_type (cfun)), > insn, SImode, 1)") > (const_string "no")] > (const_string "yes"))) > @@ -4859,7 +4859,8 @@ > { > rtx reg > = gen_rtx_REG (Pmode, > - arc_return_address_regs[arc_compute_function_type (cfun)]); > + arc_return_address_register (arc_compute_function_type > + (cfun))); > > if (TARGET_V2 > && ARC_INTERRUPT_P (arc_compute_function_type (cfun))) > @@ -4908,7 +4909,8 @@ > xop[0] = operands[0]; > xop[1] > = gen_rtx_REG (Pmode, > - arc_return_address_regs[arc_compute_function_type (cfun)]); > + arc_return_address_register (arc_compute_function_type > + (cfun))); > > if (TARGET_PAD_RETURN) > arc_pad_return (); > diff --git a/gcc/testsuite/gcc.target/arc/naked-1.c > b/gcc/testsuite/gcc.target/arc/naked-1.c > new file mode 100644 > index 0000000..e45f433f > --- /dev/null > +++ b/gcc/testsuite/gcc.target/arc/naked-1.c > @@ -0,0 +1,18 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O0" } */ > +/* Check that naked functions don't place arguments on the stack at > + optimisation level '-O0'. */ > +extern void bar (int); > + > +void __attribute__((naked)) > +foo (int n, int m) > +{ > + bar (n + m); > +} > +/* { dg-final { scan-assembler "\tbl @bar" } } */ > + > +/* Look for things that would appear in a non-naked function, but which > + should not appear in a naked function. */ > +/* { dg-final { scan-assembler-not "\tj.* \\\[blink\\\]" } } */ > +/* { dg-final { scan-assembler-not "\tst.* " } } */ > +/* { dg-final { scan-assembler-not "\tmov fp,sp" } } */ > diff --git a/gcc/testsuite/gcc.target/arc/naked-2.c > b/gcc/testsuite/gcc.target/arc/naked-2.c > new file mode 100644 > index 0000000..7b7262f > --- /dev/null > +++ b/gcc/testsuite/gcc.target/arc/naked-2.c > @@ -0,0 +1,26 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O0" } */ > +/* Check that naked functions don't place arguments on the stack at > + optimisation level '-O0'. */ > + > +#if defined(__HS__) || defined(__EM__) > +# define ILINK "ilink" > +#else > +# define ILINK "ilink1" > +#endif > + > +extern void bar (int); > + > +void __attribute__((naked, interrupt(ILINK))) > +foo (int n, int m) > +{ > + bar (n + m); > +} > +/* { dg-final { scan-assembler "\tbl @bar" } } */ > + > +/* Look for things that would appear in a non-naked function, but which > + should not appear in a naked function. */ > +/* { dg-final { scan-assembler-not "\trtie" } } */ > +/* { dg-final { scan-assembler-not "j.*\[ilink1\]" } } */ > +/* { dg-final { scan-assembler-not "\tst.* " } } */ > +/* { dg-final { scan-assembler-not "\tmov fp,sp" } } */ > -- > 1.9.1 >