From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 21902 invoked by alias); 19 Jun 2017 09:55:37 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 20981 invoked by uid 89); 19 Jun 2017 09:55:36 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-23.9 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_LAZY_DOMAIN_SECURITY,RCVD_IN_DNSWL_NONE,T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy=H*RU:sk:smtprel, Hx-spam-relays-external:sk:smtprel, HX-HELO:sk:smtprel, j* X-HELO: smtprelay.synopsys.com Received: from us01smtprelay-2.synopsys.com (HELO smtprelay.synopsys.com) (198.182.47.9) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 19 Jun 2017 09:55:33 +0000 Received: from mailhost.synopsys.com (mailhost2.synopsys.com [10.13.184.66]) by smtprelay.synopsys.com (Postfix) with ESMTP id D2CED24E107E; Mon, 19 Jun 2017 02:55:35 -0700 (PDT) Received: from mailhost.synopsys.com (localhost [127.0.0.1]) by mailhost.synopsys.com (Postfix) with ESMTP id 688FE178; Mon, 19 Jun 2017 02:55:35 -0700 (PDT) Received: from us01wehtc1.internal.synopsys.com (us01wehtc1.internal.synopsys.com [10.12.239.235]) by mailhost.synopsys.com (Postfix) with ESMTP id 45010177; Mon, 19 Jun 2017 02:55:35 -0700 (PDT) Received: from IN01WEHTCB.internal.synopsys.com (10.144.199.106) by us01wehtc1.internal.synopsys.com (10.12.239.231) with Microsoft SMTP Server (TLS) id 14.3.266.1; Mon, 19 Jun 2017 02:55:34 -0700 Received: from IN01WEHTCA.internal.synopsys.com (10.144.199.104) by IN01WEHTCB.internal.synopsys.com (10.144.199.105) with Microsoft SMTP Server (TLS) id 14.3.266.1; Mon, 19 Jun 2017 15:25:31 +0530 Received: from nl20droid1.internal.synopsys.com (10.100.24.228) by IN01WEHTCA.internal.synopsys.com (10.144.199.243) with Microsoft SMTP Server (TLS) id 14.3.266.1; Mon, 19 Jun 2017 15:25:31 +0530 From: Claudiu Zissulescu To: CC: , , Subject: [PATCH][ARC] Add support for naked functions. Date: Mon, 19 Jun 2017 09:55:00 -0000 Message-ID: <1497865951-23070-1-git-send-email-claziss@synopsys.com> In-Reply-To: <20170616193628.GD7683@embecosm.com> References: <20170616193628.GD7683@embecosm.com> MIME-Version: 1.0 Content-Type: text/plain X-SW-Source: 2017-06/txt/msg01282.txt.bz2 From: claziss Hi Andrew, Apologizes for the disconfort, please find the patch that works on the head. Thanks, Claudiu gcc/ 2016-12-13 Claudiu Zissulescu Andrew Burgess * 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 Andrew Burgess * gcc.target/arc/naked-1.c: New file. * gcc.target/arc/naked-2.c: Likewise. --- 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