From patchwork Tue Apr 25 13:03:42 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Claudiu Zissulescu X-Patchwork-Id: 754818 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3wC3QJ4xnkz9s8Y for ; Tue, 25 Apr 2017 23:07:04 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="KJlwndWV"; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type; q=dns; s=default; b=qhM7jq3QPcifPOJV L98dUwX/C5kIcP4ewXC3qAgLZYRgZ2XIoh0iJ5LYNqva5TCcLVo2U/LogMrjrusL 2Yw1bYwZanijf8kdkNWGDMd+2aQcD2x7toOYxmRw51H5MFlcymFPMnBgDL9G/StA PL2UX38U1U+QD0e7dqG1nzNctgs= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type; s=default; bh=DbjibMvo0Mq+5DmT+Ii0Wh 5XuZo=; b=KJlwndWVvI2GmCL2T29AT4d/zHnxeX+sVy9BobEu5CL2uP6Iac7R0g h3asSm1ZFY5wIcuZGztiOj3YK6Zh+y7MXFazUPdBj8mYCskIo8zCvBK0YY+1wzuv XsFE2G/WNQjkrbZUyXGe0WFFfkvtlqmB+Lv18j+mJtz4BelPHN+Fg= Received: (qmail 100985 invoked by alias); 25 Apr 2017 13:06:39 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 100719 invoked by uid 89); 25 Apr 2017 13:06:38 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-23.6 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, RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy=cores, H*r:14.3.266, Hx-spam-relays-external:14.3.266.1, H*r:ip*14.3.266.1 X-HELO: smtprelay.synopsys.com Received: from smtprelay2.synopsys.com (HELO smtprelay.synopsys.com) (198.182.60.111) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 25 Apr 2017 13:06:26 +0000 Received: from mailhost.synopsys.com (mailhost2.synopsys.com [10.13.184.66]) by smtprelay.synopsys.com (Postfix) with ESMTP id 7CFE310C1315; Tue, 25 Apr 2017 06:06:27 -0700 (PDT) Received: from mailhost.synopsys.com (localhost [127.0.0.1]) by mailhost.synopsys.com (Postfix) with ESMTP id 5B6A17A8; Tue, 25 Apr 2017 06:06:27 -0700 (PDT) Received: from US01WEHTC3.internal.synopsys.com (us01wehtc3.internal.synopsys.com [10.15.84.232]) by mailhost.synopsys.com (Postfix) with ESMTP id 4D06C7A6; Tue, 25 Apr 2017 06:06:27 -0700 (PDT) Received: from IN01WEHTCB.internal.synopsys.com (10.144.199.106) by US01WEHTC3.internal.synopsys.com (10.15.84.232) with Microsoft SMTP Server (TLS) id 14.3.266.1; Tue, 25 Apr 2017 06:06:27 -0700 Received: from IN01WEHTCA.internal.synopsys.com (10.144.199.103) by IN01WEHTCB.internal.synopsys.com (10.144.199.105) with Microsoft SMTP Server (TLS) id 14.3.266.1; Tue, 25 Apr 2017 18:36:26 +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; Tue, 25 Apr 2017 18:36:25 +0530 From: Claudiu Zissulescu To: CC: , , Subject: [PATCH 1/3] [ARC] Automatic context save/restore for regular interrupts. Date: Tue, 25 Apr 2017 15:03:42 +0200 Message-ID: <1493125424-7298-2-git-send-email-claziss@synopsys.com> In-Reply-To: <1493125424-7298-1-git-send-email-claziss@synopsys.com> References: <1493125424-7298-1-git-send-email-claziss@synopsys.com> MIME-Version: 1.0 The AUX_IRQ_CTRL register controls the behavior of automated register save and restore or prologue and epilogue sequences during a non-fast interrupt entry and exit, and context save and restore instructions. A user passes to the compiler the configuration of the AUX_IRQ_CTRL register via mirq-ctrl-saved option. This option, specifies gneral-purposes registers that the processor saves/restores on interrupt entry and exit, and it is only valid for ARC EM and ARC HS cores. gcc/ 2016-10-03 Claudiu Zissulescu * config/arc/arc.c (irq_ctrl_saved): New variable. (ARC_AUTOBLINK_IRQ_P): Define. (ARC_AUTOFP_IRQ_P): Likewise. (ARC_AUTO_IRQ_P): Likewise. (irq_range): New function. (arc_must_save_register): Likewise. (arc_must_save_return_addr): Likewise. (arc_dwarf_emit_irq_save_regs): Likewise. (arc_override_options): Handle deferred options. (MUST_SAVE_REGISTER): Deleted, replaced by arc_must_save_register. (MUST_SAVE_RETURN_ADDR): Deleted, replaced by arc_must_save_return_addr. (arc_compute_frame_size): Handle automated save and restore of registers. (arc_expand_prologue): Likewise. (arc_expand_epilogue): Likewise. * config/arc/arc.md (stack_irq_dwarf): New unspec instruction. * config/arc/arc.opt (mirq-ctrl-saved): New option. * doc/invoke.texi (mirq-ctrl-saved): Document option. gcc/testsuite 2016-10-03 Claudiu Zissulescu * gcc.target/arc/interrupt-5.c: Newfile. * gcc.target/arc/interrupt-6.c: Likewise. * gcc.target/arc/interrupt-7.c: Likewise. * gcc.target/arc/interrupt-8.c: Likewise. * gcc.target/arc/interrupt-9.c: Likewise. --- gcc/config/arc/arc.c | 320 ++++++++++++++++++++++++++--- gcc/config/arc/arc.md | 8 + gcc/config/arc/arc.opt | 4 + gcc/doc/invoke.texi | 11 +- gcc/testsuite/gcc.target/arc/interrupt-5.c | 19 ++ gcc/testsuite/gcc.target/arc/interrupt-6.c | 22 ++ gcc/testsuite/gcc.target/arc/interrupt-7.c | 16 ++ gcc/testsuite/gcc.target/arc/interrupt-8.c | 27 +++ gcc/testsuite/gcc.target/arc/interrupt-9.c | 17 ++ 9 files changed, 412 insertions(+), 32 deletions(-) create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-5.c create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-6.c create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-7.c create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-8.c create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-9.c diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c index 696e4a0..35c5295 100644 --- a/gcc/config/arc/arc.c +++ b/gcc/config/arc/arc.c @@ -63,6 +63,7 @@ along with GCC; see the file COPYING3. If not see #include "builtins.h" #include "rtl-iter.h" #include "alias.h" +#include "opts.h" /* Which cpu we're compiling for (ARC600, ARC601, ARC700). */ static char arc_cpu_name[10] = ""; @@ -111,6 +112,29 @@ struct GTY (()) arc_ccfsm int target_label; }; +/* Status of the IRQ_CTRL_AUX register. */ +typedef struct irq_ctrl_saved_t +{ + short irq_save_last_reg; /* Last register number used by + IRQ_CTRL_SAVED aux_reg. */ + bool irq_save_blink; /* True if BLINK is automatically + saved. */ + bool irq_save_lpcount; /* True if LPCOUNT is automatically + saved. */ +} irq_ctrl_saved_t; +static irq_ctrl_saved_t irq_ctrl_saved; + +#define ARC_AUTOBLINK_IRQ_P(FNTYPE) \ + (ARC_INTERRUPT_P (FNTYPE) && irq_ctrl_saved.irq_save_blink) + +#define ARC_AUTOFP_IRQ_P(FNTYPE) \ + (ARC_INTERRUPT_P (FNTYPE) && (irq_ctrl_saved.irq_save_last_reg > 26)) + +#define ARC_AUTO_IRQ_P(FNTYPE) \ + (ARC_INTERRUPT_P (FNTYPE) \ + && (irq_ctrl_saved.irq_save_blink \ + || (irq_ctrl_saved.irq_save_last_reg >= 0))) + #define arc_ccfsm_current cfun->machine->ccfsm_current #define ARC_CCFSM_BRANCH_DELETED_P(STATE) \ @@ -809,11 +833,110 @@ arc_init (void) } } +/* Parse -mirq-ctrl-saved= option string. Registers may be specified + individually, or as ranges such as "r0-r3". Registers accepted are + r0 through r31 and lp_count. Registers and ranges must be + comma-separated. */ + +static void +irq_range (const char *cstr) +{ + int i, first, last, blink, lpcount, xreg; + char *str, *dash, *comma; + + i = strlen (cstr); + str = (char *) alloca (i + 1); + memcpy (str, cstr, i + 1); + blink = -1; + lpcount = -1; + + dash = strchr (str, '-'); + if (!dash) + { + warning (0, "value of -mirq-ctrl-saved must have form R0-REGx"); + return; + } + *dash = '\0'; + + comma = strchr (dash + 1, ','); + if (comma) + *comma = '\0'; + + first = decode_reg_name (str); + if (first != 0) + { + warning (0, "first register must be R0"); + return; + } + + /* At this moment we do not have the register names initialized + accordingly. */ + if (!strcmp (dash + 1, "ilink")) + last = 29; + else + last = decode_reg_name (dash + 1); + + if (last < 0) + { + warning (0, "unknown register name: %s", dash + 1); + return; + } + + if (!(last & 0x01)) + { + warning (0, "last register name %s must be an odd register", dash + 1); + return; + } + + *dash = '-'; + + if (first > last) + { + warning (0, "%s-%s is an empty range", str, dash + 1); + return; + } + + while (comma) + { + *comma = ','; + str = comma + 1; + + comma = strchr (str, ','); + if (comma) + *comma = '\0'; + + xreg = decode_reg_name (str); + switch (xreg) + { + case 31: + blink = 31; + break; + + case 60: + lpcount = 60; + break; + + default: + warning (0, "unknown register name: %s", str); + return; + } + } + + irq_ctrl_saved.irq_save_last_reg = last; + irq_ctrl_saved.irq_save_blink = (blink == 31) || (last == 31); + irq_ctrl_saved.irq_save_lpcount = (lpcount == 60); +} + /* Check ARC options, generate derived target attributes. */ static void arc_override_options (void) { + unsigned int i; + cl_deferred_option *opt; + vec *vopt + = (vec *) arc_deferred_options; + if (arc_cpu == PROCESSOR_NONE) arc_cpu = TARGET_CPU_DEFAULT; @@ -842,6 +965,28 @@ arc_override_options (void) gcc_unreachable (); } + irq_ctrl_saved.irq_save_last_reg = -1; + irq_ctrl_saved.irq_save_blink = false; + irq_ctrl_saved.irq_save_lpcount = false; + + /* Handle the deferred options. */ + if (vopt) + FOR_EACH_VEC_ELT (*vopt, i, opt) + { + switch (opt->opt_index) + { + case OPT_mirq_ctrl_saved_: + if (TARGET_V2) + irq_range (opt->arg); + else + warning (0, "option -mirq-ctrl-saved valid only for ARC v2 processors"); + break; + + default: + gcc_unreachable(); + } + } + /* Set cpu flags accordingly to architecture/selected cpu. The cpu specific flags are set in arc-common.c. The architecture forces the default hardware configurations in, regardless what command @@ -2254,15 +2399,43 @@ arc_compute_function_type (struct function *fun) code like this. The number of frames that use __builtin_eh_return is pretty low, so optimising them is not critical right now. */ -#define MUST_SAVE_REGISTER(regno, interrupt_p) \ - (((regno) != RETURN_ADDR_REGNUM && (regno) != FRAME_POINTER_REGNUM \ - && (df_regs_ever_live_p (regno) \ - && (!call_used_regs[regno] || interrupt_p))) \ - || (flag_pic && crtl->uses_pic_offset_table \ - && regno == PIC_OFFSET_TABLE_REGNUM) \ - || (crtl->calls_eh_return && (regno > 2 && regno < 27))) +static bool +arc_must_save_register (int regno, struct function *func) +{ + enum arc_function_type fn_type = arc_compute_function_type (func); + bool irq_auto_save_p = ((irq_ctrl_saved.irq_save_last_reg >= regno) + && ARC_INTERRUPT_P (fn_type)); + + if ((regno) != RETURN_ADDR_REGNUM + && (regno) != FRAME_POINTER_REGNUM + && df_regs_ever_live_p (regno) + && (!call_used_regs[regno] + || ARC_INTERRUPT_P (fn_type)) + /* Do not emit code for auto saved regs. */ + && !irq_auto_save_p) + return true; + + if (flag_pic && crtl->uses_pic_offset_table + && regno == PIC_OFFSET_TABLE_REGNUM) + return true; + + if (crtl->calls_eh_return && (regno > 2 && regno < 27)) + return true; + + return false; +} + +/* Return true if the return address must be saved in the current function, + otherwise return false. */ + +static bool +arc_must_save_return_addr (struct function *func) +{ + if (func->machine->frame_info.save_return_addr) + return true; -#define MUST_SAVE_RETURN_ADDR (cfun->machine->frame_info.save_return_addr) + return false; +} /* Helper function to wrap FRAME_POINTER_NEEDED. We do this as FRAME_POINTER_NEEDED will not be true until the IRA (Integrated @@ -2280,9 +2453,9 @@ arc_compute_function_type (struct function *fun) As the frame pointer is handled as a special case in our prologue and epilogue code it must not be saved and restored using the - MUST_SAVE_REGISTER mechanism otherwise we run into issues where GCC - believes that the function is not using a frame pointer and that - the value in the fp register is the frame pointer, while the + arc_must_save_register mechanism otherwise we run into issues where + GCC believes that the function is not using a frame pointer and + that the value in the fp register is the frame pointer, while the prologue and epilogue are busy saving and restoring the fp register. This issue is fixed in this commit too. @@ -2352,8 +2525,6 @@ arc_compute_frame_size (void) unsigned int total_size, var_size, args_size, pretend_size, extra_size; unsigned int reg_size, reg_offset; unsigned int gmask; - enum arc_function_type fn_type; - int interrupt_p; struct arc_frame_info *frame_info; int size; @@ -2378,15 +2549,13 @@ arc_compute_frame_size (void) reg_size = 0; gmask = 0; - fn_type = arc_compute_function_type (cfun); - interrupt_p = ARC_INTERRUPT_P (fn_type); for (regno = 0; regno <= 31; regno++) { - if (MUST_SAVE_REGISTER (regno, interrupt_p)) + if (arc_must_save_register (regno, cfun)) { reg_size += UNITS_PER_WORD; - gmask |= 1 << regno; + gmask |= 1L << regno; } } @@ -2419,7 +2588,7 @@ arc_compute_frame_size (void) } extra_size = 0; - if (MUST_SAVE_RETURN_ADDR) + if (arc_must_save_return_addr (cfun)) extra_size = 4; if (arc_frame_pointer_needed ()) extra_size += 4; @@ -2641,6 +2810,77 @@ arc_save_restore (rtx base_reg, int arc_return_address_regs[4] = {0, RETURN_ADDR_REGNUM, ILINK1_REGNUM, ILINK2_REGNUM}; + +/* Build dwarf information when the context is saved via AUX_IRQ_CTRL + mechanism. */ + +static void +arc_dwarf_emit_irq_save_regs (void) +{ + rtx tmp, par, insn, reg; + int i, offset, j; + + par = gen_rtx_SEQUENCE (VOIDmode, + rtvec_alloc (irq_ctrl_saved.irq_save_last_reg + 1 + + irq_ctrl_saved.irq_save_blink + + irq_ctrl_saved.irq_save_lpcount + + 1)); + + /* Build the stack adjustment note for unwind info. */ + j = 0; + offset = UNITS_PER_WORD * (irq_ctrl_saved.irq_save_last_reg + 1 + + irq_ctrl_saved.irq_save_blink + + irq_ctrl_saved.irq_save_lpcount); + tmp = plus_constant (Pmode, stack_pointer_rtx, -1 * offset); + tmp = gen_rtx_SET (stack_pointer_rtx, tmp); + RTX_FRAME_RELATED_P (tmp) = 1; + XVECEXP (par, 0, j++) = tmp; + + offset -= UNITS_PER_WORD; + + /* 1st goes LP_COUNT. */ + if (irq_ctrl_saved.irq_save_lpcount) + { + reg = gen_rtx_REG (SImode, 60); + tmp = plus_constant (Pmode, stack_pointer_rtx, offset); + tmp = gen_frame_mem (SImode, tmp); + tmp = gen_rtx_SET (tmp, reg); + RTX_FRAME_RELATED_P (tmp) = 1; + XVECEXP (par, 0, j++) = tmp; + offset -= UNITS_PER_WORD; + } + + /* 2nd goes BLINK. */ + if (irq_ctrl_saved.irq_save_blink) + { + reg = gen_rtx_REG (SImode, 31); + tmp = plus_constant (Pmode, stack_pointer_rtx, offset); + tmp = gen_frame_mem (SImode, tmp); + tmp = gen_rtx_SET (tmp, reg); + RTX_FRAME_RELATED_P (tmp) = 1; + XVECEXP (par, 0, j++) = tmp; + offset -= UNITS_PER_WORD; + } + + /* Build the parallel of the remaining registers recorded as saved + for unwind. */ + for (i = irq_ctrl_saved.irq_save_last_reg; i >= 0; i--) + { + reg = gen_rtx_REG (SImode, i); + tmp = plus_constant (Pmode, stack_pointer_rtx, offset); + tmp = gen_frame_mem (SImode, tmp); + tmp = gen_rtx_SET (tmp, reg); + RTX_FRAME_RELATED_P (tmp) = 1; + XVECEXP (par, 0, j++) = tmp; + offset -= UNITS_PER_WORD; + } + + /* Dummy insn used to anchor the dwarf info. */ + insn = emit_insn (gen_stack_irq_dwarf()); + add_reg_note (insn, REG_FRAME_RELATED_EXPR, par); + RTX_FRAME_RELATED_P (insn) = 1; +} + /* Set up the stack and frame pointer (if desired) for the function. */ void @@ -2654,6 +2894,7 @@ 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); /* Compute total frame size. */ size = arc_compute_frame_size (); @@ -2677,30 +2918,41 @@ arc_expand_prologue (void) frame_size_to_allocate -= cfun->machine->frame_info.pretend_size; } + /* IRQ using automatic save mechanism will save the register before + anything we do. */ + if (ARC_AUTO_IRQ_P (fn_type)) + { + arc_dwarf_emit_irq_save_regs (); + } + /* The home-grown ABI says link register is saved first. */ - if (MUST_SAVE_RETURN_ADDR) + if (arc_must_save_return_addr (cfun) + && !ARC_AUTOBLINK_IRQ_P (fn_type)) { rtx ra = gen_rtx_REG (SImode, RETURN_ADDR_REGNUM); - rtx mem = gen_frame_mem (Pmode, gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx)); + rtx mem = gen_frame_mem (Pmode, + gen_rtx_PRE_DEC (Pmode, + stack_pointer_rtx)); frame_move_inc (mem, ra, stack_pointer_rtx, 0); frame_size_to_allocate -= UNITS_PER_WORD; - - } /* MUST_SAVE_RETURN_ADDR */ + } /* Save any needed call-saved regs (and call-used if this is an interrupt handler) for ARCompact ISA. */ if (cfun->machine->frame_info.reg_size) { first_offset = -cfun->machine->frame_info.reg_size; + /* N.B. FRAME_POINTER_MASK and RETURN_ADDR_MASK are cleared in gmask. */ arc_save_restore (stack_pointer_rtx, gmask, 0, &first_offset); frame_size_to_allocate -= cfun->machine->frame_info.reg_size; } - - /* Save frame pointer if needed. */ - if (arc_frame_pointer_needed ()) + /* Save frame pointer if needed. First save the FP on stack, if not + autosaved. */ + if (arc_frame_pointer_needed () + && !ARC_AUTOFP_IRQ_P (fn_type)) { rtx addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (-UNITS_PER_WORD + first_offset)); @@ -2710,6 +2962,11 @@ arc_expand_prologue (void) frame_move_inc (mem, frame_pointer_rtx, stack_pointer_rtx, 0); frame_size_to_allocate -= UNITS_PER_WORD; first_offset = 0; + } + + /* Emit mov fp,sp. */ + if (arc_frame_pointer_needed ()) + { frame_move (frame_pointer_rtx, stack_pointer_rtx); } @@ -2778,7 +3035,8 @@ arc_expand_epilogue (int sibcall_p) /* Restore any saved registers. */ - if (arc_frame_pointer_needed ()) + if (arc_frame_pointer_needed () + && !ARC_AUTOFP_IRQ_P (fn_type)) { rtx addr = gen_rtx_POST_INC (Pmode, stack_pointer_rtx); @@ -2816,14 +3074,15 @@ arc_expand_epilogue (int sibcall_p) : satisfies_constraint_C2a (GEN_INT (first_offset)))) /* Also do this if we have both gprs and return address to restore, and they both would need a LIMM. */ - || (MUST_SAVE_RETURN_ADDR - && !SMALL_INT ((cfun->machine->frame_info.reg_size + first_offset) >> 2) - && cfun->machine->frame_info.gmask)) + || (arc_must_save_return_addr (cfun) + && !SMALL_INT ((cfun->machine->frame_info.reg_size + first_offset) >> 2) + && cfun->machine->frame_info.gmask)) { frame_stack_add (first_offset); first_offset = 0; } - if (MUST_SAVE_RETURN_ADDR) + if (arc_must_save_return_addr (cfun) + && !ARC_AUTOBLINK_IRQ_P (fn_type)) { rtx ra = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM); int ra_offs = cfun->machine->frame_info.reg_size + first_offset; @@ -2888,7 +3147,6 @@ arc_expand_epilogue (int sibcall_p) & ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK), 1, &first_offset); } - /* The rest of this function does the following: ARCompact : handle epilogue_delay, restore sp (phase-2), return */ diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md index 42ea9a7..0f03170 100644 --- a/gcc/config/arc/arc.md +++ b/gcc/config/arc/arc.md @@ -6208,6 +6208,14 @@ [(set (zero_extract:SI (match_dup 3) (match_dup 1) (match_dup 2)) (zero_extract:SI (match_dup 0) (match_dup 1) (match_dup 2)))]) +;; Dummy pattern used as a place holder for automatically saved +;; registers. +(define_insn "stack_irq_dwarf" + [(unspec_volatile [(const_int 1)] VUNSPEC_ARC_STACK_IRQ)] + "" + "" + [(set_attr "length" "0")]) + ;; include the arc-FPX instructions (include "fpx.md") diff --git a/gcc/config/arc/arc.opt b/gcc/config/arc/arc.opt index 6060ded..483470d 100644 --- a/gcc/config/arc/arc.opt +++ b/gcc/config/arc/arc.opt @@ -486,3 +486,7 @@ Enable use of NPS400 xld/xst extension. munaligned-access Target Report Var(unaligned_access) Init(UNALIGNED_ACCESS_DEFAULT) Enable unaligned word and halfword accesses to packed data. + +mirq-ctrl-saved= +Target RejectNegative Joined Var(arc_deferred_options) Defer +Specifies the registers that the processor saves on an interrupt entry and exit. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 0eeea7b..cebafe6 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -606,7 +606,7 @@ Objective-C and Objective-C++ Dialects}. -mnorm -mspfp -mspfp-compact -mspfp-fast -msimd -msoft-float -mswap @gol -mcrc -mdsp-packa -mdvbf -mlock -mmac-d16 -mmac-24 -mrtsc -mswape @gol -mtelephony -mxy -misize -mannotate-align -marclinux -marclinux_prof @gol --mlong-calls -mmedium-calls -msdata @gol +-mlong-calls -mmedium-calls -msdata -mirq-ctrl-saved @gol -mvolatile-cache -mtp-regno=@var{regno} @gol -malign-call -mauto-modify-reg -mbbit-peephole -mno-brcc @gol -mcase-vector-pcrel -mcompact-casesi -mno-cond-exec -mearly-cbranchsi @gol @@ -14578,6 +14578,15 @@ hardware extensions. Not available for ARC EM@. @end table +@item -mirq-ctrl-saved="REGS" +@opindex mirq-ctrl-saved +Specifies gneral-purposes registers that the processor saves/restores +on interrupt entry and exit. Permited values: r0-r29, fp, blink, and +lp_count. Registers needs to be specified as ranges such as "r0-r3". +A register range always starts with r0. Registers blink and lp_count +can be specified individually. Only valid for ARC EM and ARC HS +cores. + @end table The following options are passed through to the assembler, and also diff --git a/gcc/testsuite/gcc.target/arc/interrupt-5.c b/gcc/testsuite/gcc.target/arc/interrupt-5.c new file mode 100644 index 0000000..ee01d76 --- /dev/null +++ b/gcc/testsuite/gcc.target/arc/interrupt-5.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-skip-if "Not available for ARCv1" { arc700 || arc6xx } } */ +/* { dg-options "-O2 -mirq-ctrl-saved=r0-r3,blink" } */ + +/* Check if the registers R0-R3,blink are automatically saved. */ + +extern int bar (void *); + +void __attribute__ ((interrupt("ilink"))) +foo(void) +{ + bar (0); + __asm__ volatile ( "" : : : "r0","r1","r2","r3"); +} +/* { dg-final { scan-assembler-not "st.*r0,\\\[sp" } } */ +/* { dg-final { scan-assembler-not "st.*r1,\\\[sp" } } */ +/* { dg-final { scan-assembler-not "st.*r2,\\\[sp" } } */ +/* { dg-final { scan-assembler-not "st.*r3,\\\[sp" } } */ +/* { dg-final { scan-assembler-not "push_s blink" } } */ diff --git a/gcc/testsuite/gcc.target/arc/interrupt-6.c b/gcc/testsuite/gcc.target/arc/interrupt-6.c new file mode 100644 index 0000000..509ff30 --- /dev/null +++ b/gcc/testsuite/gcc.target/arc/interrupt-6.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-skip-if "Not available for ARCv1" { arc700 || arc6xx } } */ +/* { dg-options "-O2 -mirq-ctrl-saved=r0-ilink" } */ + +#include + +/* Check if ilink is recognized. Check how FP and BLINK are saved. + BLINK is saved last on the stack because the IRQ autosave will do + first r0-ilink. To avoid this ABI exception, one needs to autosave + always blink when using the IRQ autosave feature. */ + +extern int bar (void *); + +void __attribute__ ((interrupt("ilink"))) +foo(void) +{ + int *p = alloca (10); + bar (p); +} +/* { dg-final { scan-assembler-not ".*fp,\\\[sp" } } */ +/* { dg-final { scan-assembler "ld.*blink,\\\[sp\\\]" } } */ +/* { dg-final { scan-assembler "push_s.*blink" } } */ diff --git a/gcc/testsuite/gcc.target/arc/interrupt-7.c b/gcc/testsuite/gcc.target/arc/interrupt-7.c new file mode 100644 index 0000000..547dfd3 --- /dev/null +++ b/gcc/testsuite/gcc.target/arc/interrupt-7.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-skip-if "Not available for ARCv1" { arc700 || arc6xx } } */ +/* { dg-options "-O2 -mirq-ctrl-saved=r0-r17,blink" } */ + +/* Check if the registers R0-R17,blink are automatically saved. */ + +void __attribute__ ((interrupt("ilink"))) +foo(void) +{ + __asm__ volatile ( "" : : : "r13","r14","r15","r16"); +} +/* { dg-final { scan-assembler-not "st.*r13,\\\[sp" } } */ +/* { dg-final { scan-assembler-not "st.*r14,\\\[sp" } } */ +/* { dg-final { scan-assembler-not "st.*r15,\\\[sp" } } */ +/* { dg-final { scan-assembler-not "st.*r16,\\\[sp" } } */ +/* { dg-final { scan-assembler-not "push_s blink" } } */ diff --git a/gcc/testsuite/gcc.target/arc/interrupt-8.c b/gcc/testsuite/gcc.target/arc/interrupt-8.c new file mode 100644 index 0000000..60fd87b --- /dev/null +++ b/gcc/testsuite/gcc.target/arc/interrupt-8.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-skip-if "Not available for ARCv1" { arc700 || arc6xx } } */ +/* { dg-options "-O2 -mirq-ctrl-saved=r0-r17" } */ + +/* Check if the registers R0-R17 are automatically saved. GP is saved + by the compiler. */ + +int a; + +void __attribute__ ((interrupt("ilink"))) +foo(void) +{ + __asm__ volatile ( "" : : : "r0","r1","r2","r3"); + __asm__ volatile ( "" : : : "r13","r14","r15","r16"); + a++; +} +/* { dg-final { scan-assembler-not "st.*r13,\\\[sp" } } */ +/* { dg-final { scan-assembler-not "st.*r14,\\\[sp" } } */ +/* { dg-final { scan-assembler-not "st.*r15,\\\[sp" } } */ +/* { dg-final { scan-assembler-not "st.*r16,\\\[sp" } } */ +/* { dg-final { scan-assembler "st.*gp,\\\[sp,-4\\\]" } } */ +/* { dg-final { scan-assembler "ld.*gp,\\\[sp\\\]" } } */ +/* { dg-final { scan-assembler-not "st.*r0,\\\[sp" } } */ +/* { dg-final { scan-assembler-not "st.*r1,\\\[sp" } } */ +/* { dg-final { scan-assembler-not "st.*r2,\\\[sp" } } */ +/* { dg-final { scan-assembler-not "st.*r3,\\\[sp" } } */ +/* { dg-final { scan-assembler "rtie" } } */ diff --git a/gcc/testsuite/gcc.target/arc/interrupt-9.c b/gcc/testsuite/gcc.target/arc/interrupt-9.c new file mode 100644 index 0000000..4547fef --- /dev/null +++ b/gcc/testsuite/gcc.target/arc/interrupt-9.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target archs }*/ +/* { dg-options "-O0 -mirq-ctrl-saved=r0-fp" } */ + +/* Check if we get the move operation between fp and sp. */ + +void __attribute__ ((interrupt("ilink"))) +handler1 (void) +{ + asm ("" + : + : + : "r0", "r1", "r2", "r3", "r4", + "r5", "r6", "r7", "r8", "r9"); +} +/* { dg-final { scan-assembler "mov.*fp,sp" } } */ +/* { dg-final { scan-assembler-not ".*fp,\\\[sp" } } */