diff mbox

[2/3,ARC] Fast interrupts support.

Message ID 1493125424-7298-3-git-send-email-claziss@synopsys.com
State New
Headers show

Commit Message

Claudiu Zissulescu April 25, 2017, 1:03 p.m. UTC
When a processor enters a fast interrupts handler, and duplicate
register banks are configured, the processor saves the user context by
saving the registers in the main register bank to these additional
registers in the duplicate register bank.  In this fast interrupt
context, when you specify the rgf_banked_regs option,the compiler does
not save the registers duplicated in the additional register bank are
not saved.

gcc/
2016-10-04  Claudiu Zissulescu  <claziss@synopsys.com>
	    Andrew Burgess  <andrew.burgess@embecosm.com>

	* config/arc/arc.c (ARC_AUTOBLINK_IRQ_P): Consider fast interrupts
	case also.
	(ARC_AUTOFP_IRQ_P): Likewise.
	(ARC_AUTO_IRQ_P): Likewise.
	(rgf_banked_register_count): New variable.
	(parse_mrgf_banked_regs_option): New function.
	(arc_override_options): Handle rgf_banked_regs option.
	(arc_handle_interrupt_attribute): Add firq option.
	(arc_compute_function_type): Return fast irq type when required.
	(arc_must_save_register): Handle fast interrupts.
	(arc_expand_prologue): Do not emit dwarf info for fast interrupts.
	(arc_return_address_regs): Update.
	* config/arc/arc.h (arc_return_address_regs): Update.
	(arc_function_type): Add fast interrupt type.
	(ARC_INTERRUPT_P): Update.
	(RC_FAST_INTERRUPT_P): Define.
	* config/arc/arc.md (simple_return): Update for fast interrupts.
	(p_return_i): Likewise.
	* config/arc/arc.opt (mrgf-banked-regs): New option.
	* doc/invoke.texi (mrgf-banked-regs): Document.

gcc/testsuite:
2016-10-04  Claudiu Zissulescu  <claziss@synopsys.com>
	    Andrew Burgess  <andrew.burgess@embecosm.com>

	* gcc.target/arc/firq-1.c: New file.
	* gcc.target/arc/firq-2.c: Likewise.
	* gcc.target/arc/firq-3.c: Likewise.
	* gcc.target/arc/firq-4.c: Likewise.
	* gcc.target/arc/firq-5.c: Likewise.
	* gcc.target/arc/firq-6.c: Likewise.
---
 gcc/config/arc/arc.c                  | 106 +++++++++++++++++++++++++++-------
 gcc/config/arc/arc.h                  |  13 +++--
 gcc/config/arc/arc.md                 |   9 ++-
 gcc/config/arc/arc.opt                |   4 ++
 gcc/doc/invoke.texi                   |  15 ++++-
 gcc/testsuite/gcc.target/arc/firq-1.c |  27 +++++++++
 gcc/testsuite/gcc.target/arc/firq-2.c |  31 ++++++++++
 gcc/testsuite/gcc.target/arc/firq-3.c |  40 +++++++++++++
 gcc/testsuite/gcc.target/arc/firq-4.c |  31 ++++++++++
 gcc/testsuite/gcc.target/arc/firq-5.c |  15 +++++
 gcc/testsuite/gcc.target/arc/firq-6.c |  21 +++++++
 11 files changed, 281 insertions(+), 31 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/arc/firq-1.c
 create mode 100644 gcc/testsuite/gcc.target/arc/firq-2.c
 create mode 100644 gcc/testsuite/gcc.target/arc/firq-3.c
 create mode 100644 gcc/testsuite/gcc.target/arc/firq-4.c
 create mode 100644 gcc/testsuite/gcc.target/arc/firq-5.c
 create mode 100644 gcc/testsuite/gcc.target/arc/firq-6.c

Comments

Sandra Loosemore April 25, 2017, 3:43 p.m. UTC | #1
On 04/25/2017 07:03 AM, Claudiu Zissulescu wrote:
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index cebafe6..aa5cd27 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -606,7 +606,8 @@ 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 -mirq-ctrl-saved @gol
> +-mlong-calls  -mmedium-calls  -msdata -mirq-ctrl-saved
> +-mrgf-banked-regs @gol

Please don't remove @gol at the end of the line.  It's easier to 
maintain these option lists in the docs if the line breaks in the source 
reflect where they're being inserted in the output.

>   -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
> @@ -14587,6 +14588,18 @@ 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.
>
> +@item -mrgf-banked-regs="NUMBER"

Please use @var markup here.  Don't use quotes unless they're a literal 
part of the syntax.

> +@opindex mrgf-banked-regs
> +Specifies the number of registers replicated in second register bank
> +on entry to fast interrupt.  Fast interrupts are interrupts with the
> +highest priority level P0.  These interrupts save only PC and STATUS32
> +registers to avoid memory transactions during interrupt entry and exit
> +sequences.  Use this option when you are using fast interrupts in an
> +ARC V2 family processor.
> +
> +Permitted values are 4, 8, 16, 32 and specify the number of registers
> +that are covered by the second register bank.
> +
>   @end table
>
>   The following options are passed through to the assembler, and also

-Sandra
Claudiu Zissulescu April 26, 2017, 12:58 p.m. UTC | #2
Thank you for your review, I'll include your points into the a new revised patch.
//Claudiu

> -----Original Message-----
> From: Sandra Loosemore [mailto:sandra@codesourcery.com]
> Sent: Tuesday, April 25, 2017 5:43 PM
> To: Claudiu Zissulescu <Claudiu.Zissulescu@synopsys.com>; gcc-
> patches@gcc.gnu.org
> Cc: Francois.Bedard@synopsys.com; andrew.burgess@embecosm.com
> Subject: Re: [PATCH 2/3] [ARC] Fast interrupts support.
> 
> On 04/25/2017 07:03 AM, Claudiu Zissulescu wrote:
> > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> > index cebafe6..aa5cd27 100644
> > --- a/gcc/doc/invoke.texi
> > +++ b/gcc/doc/invoke.texi
> > @@ -606,7 +606,8 @@ 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 -mirq-ctrl-saved @gol
> > +-mlong-calls  -mmedium-calls  -msdata -mirq-ctrl-saved
> > +-mrgf-banked-regs @gol
> 
> Please don't remove @gol at the end of the line.  It's easier to
> maintain these option lists in the docs if the line breaks in the source
> reflect where they're being inserted in the output.
> 
> >   -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
> > @@ -14587,6 +14588,18 @@ 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.
> >
> > +@item -mrgf-banked-regs="NUMBER"
> 
> Please use @var markup here.  Don't use quotes unless they're a literal
> part of the syntax.
> 
> > +@opindex mrgf-banked-regs
> > +Specifies the number of registers replicated in second register bank
> > +on entry to fast interrupt.  Fast interrupts are interrupts with the
> > +highest priority level P0.  These interrupts save only PC and STATUS32
> > +registers to avoid memory transactions during interrupt entry and exit
> > +sequences.  Use this option when you are using fast interrupts in an
> > +ARC V2 family processor.
> > +
> > +Permitted values are 4, 8, 16, 32 and specify the number of registers
> > +that are covered by the second register bank.
> > +
> >   @end table
> >
> >   The following options are passed through to the assembler, and also
> 
> -Sandra
>
diff mbox

Patch

diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
index 35c5295..170b8dd 100644
--- a/gcc/config/arc/arc.c
+++ b/gcc/config/arc/arc.c
@@ -125,16 +125,25 @@  typedef struct 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			\
+  ((ARC_INTERRUPT_P (FNTYPE)					\
+    && irq_ctrl_saved.irq_save_blink)				\
+   || (ARC_FAST_INTERRUPT_P (FNTYPE)				\
+       && rgf_banked_register_count > 8))
+
+#define ARC_AUTOFP_IRQ_P(FNTYPE)				\
+  ((ARC_INTERRUPT_P (FNTYPE)					\
+    && (irq_ctrl_saved.irq_save_last_reg > 26))			\
+  || (ARC_FAST_INTERRUPT_P (FNTYPE)				\
+      && rgf_banked_register_count > 8))
+
+#define ARC_AUTO_IRQ_P(FNTYPE)					\
+  (ARC_INTERRUPT_P (FNTYPE) && !ARC_FAST_INTERRUPT_P (FNTYPE)	\
+   && (irq_ctrl_saved.irq_save_blink				\
        || (irq_ctrl_saved.irq_save_last_reg >= 0)))
 
+/* Number of registers in second bank for FIRQ support.  */
+static int rgf_banked_register_count;
+
 #define arc_ccfsm_current cfun->machine->ccfsm_current
 
 #define ARC_CCFSM_BRANCH_DELETED_P(STATE) \
@@ -927,6 +936,27 @@  irq_range (const char *cstr)
   irq_ctrl_saved.irq_save_lpcount  = (lpcount == 60);
 }
 
+/* Parse -mrgf-banked-regs=NUM option string.  Valid values for NUM are 4,
+   8, 16, or 32.  */
+
+static void
+parse_mrgf_banked_regs_option (const char *arg)
+{
+  long int val;
+  char *end_ptr;
+
+  errno = 0;
+  val = strtol (arg, &end_ptr, 10);
+  if (errno != 0 || *arg == '\0' || *end_ptr != '\0'
+      || (val != 0 && val != 4 && val != 8 && val != 16 && val != 32))
+    {
+      error ("invalid number in -mrgf-banked-regs=%s "
+	     "valid values are 0, 4, 8, 16, or 32", arg);
+      return;
+    }
+  rgf_banked_register_count = (int) val;
+}
+
 /* Check ARC options, generate derived target attributes.  */
 
 static void
@@ -969,6 +999,8 @@  arc_override_options (void)
   irq_ctrl_saved.irq_save_blink    = false;
   irq_ctrl_saved.irq_save_lpcount  = false;
 
+  rgf_banked_register_count = 0;
+
   /* Handle the deferred options.  */
   if (vopt)
     FOR_EACH_VEC_ELT (*vopt, i, opt)
@@ -982,6 +1014,13 @@  arc_override_options (void)
 	      warning (0, "option -mirq-ctrl-saved valid only for ARC v2 processors");
 	    break;
 
+	  case OPT_mrgf_banked_regs_:
+	    if (TARGET_V2)
+	      parse_mrgf_banked_regs_option (opt->arg);
+	    else
+	      warning (0, "option -mrgf-banked-regs valid only for ARC v2 processors");
+	    break;
+
 	  default:
 	    gcc_unreachable();
 	  }
@@ -1790,9 +1829,9 @@  arc_handle_interrupt_attribute (tree *, tree name, tree args, int,
 	       name);
       *no_add_attrs = true;
     }
-  else if (strcmp (TREE_STRING_POINTER (value), "ilink1")
-	   && strcmp (TREE_STRING_POINTER (value), "ilink2")
-	   && !TARGET_V2)
+  else if (!TARGET_V2
+	   && strcmp (TREE_STRING_POINTER (value), "ilink1")
+	   && strcmp (TREE_STRING_POINTER (value), "ilink2"))
     {
       warning (OPT_Wattributes,
 	       "argument of %qE attribute is not \"ilink1\" or \"ilink2\"",
@@ -1800,10 +1839,11 @@  arc_handle_interrupt_attribute (tree *, tree name, tree args, int,
       *no_add_attrs = true;
     }
   else if (TARGET_V2
-	   && strcmp (TREE_STRING_POINTER (value), "ilink"))
+	   && strcmp (TREE_STRING_POINTER (value), "ilink")
+	   && strcmp (TREE_STRING_POINTER (value), "firq"))
     {
       warning (OPT_Wattributes,
-	       "argument of %qE attribute is not \"ilink\"",
+	       "argument of %qE attribute is not \"ilink\" or \"firq\"",
 	       name);
       *no_add_attrs = true;
     }
@@ -2363,6 +2403,8 @@  arc_compute_function_type (struct function *fun)
 	    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;
@@ -2404,7 +2446,29 @@  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));
+			  && ARC_AUTO_IRQ_P (fn_type));
+  bool firq_auto_save_p = ARC_FAST_INTERRUPT_P (fn_type);
+
+  switch (rgf_banked_register_count)
+    {
+    case 4:
+      firq_auto_save_p &= (regno < 4);
+      break;
+    case 8:
+      firq_auto_save_p &= ((regno < 4) || ((regno > 11) && (regno < 16)));
+      break;
+    case 16:
+      firq_auto_save_p &= ((regno < 4) || ((regno > 9) && (regno < 16))
+			   || ((regno > 25) && (regno < 29))
+			   || ((regno > 29) && (regno < 32)));
+      break;
+    case 32:
+      firq_auto_save_p &= (regno != 29) && (regno < 32);
+      break;
+    default:
+      firq_auto_save_p = false;
+      break;
+    }
 
   if ((regno) != RETURN_ADDR_REGNUM
       && (regno) != FRAME_POINTER_REGNUM
@@ -2412,7 +2476,8 @@  arc_must_save_register (int regno, struct function *func)
       && (!call_used_regs[regno]
 	  || ARC_INTERRUPT_P (fn_type))
       /* Do not emit code for auto saved regs.  */
-      && !irq_auto_save_p)
+      && !irq_auto_save_p
+      && !firq_auto_save_p)
     return true;
 
   if (flag_pic && crtl->uses_pic_offset_table
@@ -2806,11 +2871,6 @@  arc_save_restore (rtx base_reg,
     }
 } /* arc_save_restore */
 
-
-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.  */
 
@@ -2920,7 +2980,8 @@  arc_expand_prologue (void)
 
   /* IRQ using automatic save mechanism will save the register before
      anything we do.  */
-  if (ARC_AUTO_IRQ_P (fn_type))
+  if (ARC_AUTO_IRQ_P (fn_type)
+      && !ARC_FAST_INTERRUPT_P (fn_type))
     {
       arc_dwarf_emit_irq_save_regs ();
     }
@@ -9823,6 +9884,9 @@  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};
+
 /* Implement EPILOGUE__USES.
    Return true if REGNO should be added to the deemed uses of the epilogue.
 
diff --git a/gcc/config/arc/arc.h b/gcc/config/arc/arc.h
index 9f6a272..0a4c745 100644
--- a/gcc/config/arc/arc.h
+++ b/gcc/config/arc/arc.h
@@ -1364,7 +1364,7 @@  do { \
 
 /* 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[4];
+extern int arc_return_address_regs[5];
 
 /* Debugging information.  */
 
@@ -1504,10 +1504,15 @@  enum arc_function_type {
   ARC_FUNCTION_UNKNOWN, ARC_FUNCTION_NORMAL,
   /* 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, ARC_FUNCTION_ILINK2,
+  /* Fast interrupt is only available on ARCv2 processors.  */
+  ARC_FUNCTION_FIRQ
 };
-#define ARC_INTERRUPT_P(TYPE) \
-((TYPE) == ARC_FUNCTION_ILINK1 || (TYPE) == ARC_FUNCTION_ILINK2)
+#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)
 
 /* Compute the type of a function from its DECL.  Needed for EPILOGUE_USES.  */
 struct function;
diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md
index 0f03170..ffab390 100644
--- a/gcc/config/arc/arc.md
+++ b/gcc/config/arc/arc.md
@@ -4740,8 +4740,8 @@ 
     = gen_rtx_REG (Pmode,
 		   arc_return_address_regs[arc_compute_function_type (cfun)]);
 
-  if (arc_compute_function_type (cfun) == ARC_FUNCTION_ILINK1
-      && TARGET_V2)
+  if (TARGET_V2
+      && ARC_INTERRUPT_P (arc_compute_function_type (cfun)))
   {
     return \"rtie\";
   }
@@ -4751,8 +4751,7 @@ 
   return \"\";
 }
   [(set (attr "type")
-	(cond [(and (eq (symbol_ref "arc_compute_function_type (cfun)")
-			(symbol_ref "ARC_FUNCTION_ILINK1"))
+	(cond [(and (match_test "ARC_INTERRUPT_P (arc_compute_function_type (cfun))")
 		    (match_test "TARGET_V2"))
 	       (const_string "brcc_no_delay_slot")]
 	      (const_string "return")))
@@ -4782,7 +4781,7 @@ 
 		      (simple_return) (pc)))]
   "reload_completed
    && !(TARGET_V2
-     && arc_compute_function_type (cfun) == ARC_FUNCTION_ILINK1)"
+     && ARC_INTERRUPT_P (arc_compute_function_type (cfun)))"
 {
   rtx xop[2];
   xop[0] = operands[0];
diff --git a/gcc/config/arc/arc.opt b/gcc/config/arc/arc.opt
index 483470d..f01a2ff 100644
--- a/gcc/config/arc/arc.opt
+++ b/gcc/config/arc/arc.opt
@@ -490,3 +490,7 @@  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.
+
+mrgf-banked-regs=
+Target RejectNegative Joined Var(arc_deferred_options) Defer
+Specifies the number of registers replicated in second register bank on entry to fast interrupt.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index cebafe6..aa5cd27 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -606,7 +606,8 @@  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 -mirq-ctrl-saved @gol
+-mlong-calls  -mmedium-calls  -msdata -mirq-ctrl-saved
+-mrgf-banked-regs @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
@@ -14587,6 +14588,18 @@  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.
 
+@item -mrgf-banked-regs="NUMBER"
+@opindex mrgf-banked-regs
+Specifies the number of registers replicated in second register bank
+on entry to fast interrupt.  Fast interrupts are interrupts with the
+highest priority level P0.  These interrupts save only PC and STATUS32
+registers to avoid memory transactions during interrupt entry and exit
+sequences.  Use this option when you are using fast interrupts in an
+ARC V2 family processor.
+
+Permitted values are 4, 8, 16, 32 and specify the number of registers
+that are covered by the second register bank.
+
 @end table
 
 The following options are passed through to the assembler, and also
diff --git a/gcc/testsuite/gcc.target/arc/firq-1.c b/gcc/testsuite/gcc.target/arc/firq-1.c
new file mode 100644
index 0000000..87f4087
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/firq-1.c
@@ -0,0 +1,27 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target archs }*/
+/* { dg-options "-O0 -mll64 -mirq-ctrl-saved=r0-r9" } */
+
+/* Check that on archs the 'firq' interrupt function type is
+   available, these are the fast interrupts.  For fast interrupts,
+   despite the use of 'irq-ctrl-saved', no registers are automatically
+   saved on entry to the function, and so, in the following register
+   r0 to r9 should all be saved to the stack.
+
+   We also take the opportunity to check the use of the 'rtie'
+   instruction at the end of the interrupt function.  */
+
+void __attribute__ ((interrupt("firq")))
+handler1 (void)
+{
+  asm (""
+       :
+       :
+       : "r0", "r1", "r2", "r3", "r4",
+	 "r5", "r6", "r7", "r8", "r9");
+}
+/* { dg-final { scan-assembler-times "r2,\\\[sp,\[0-9\]+\\\]" 2 } } */
+/* { dg-final { scan-assembler-times "r4,\\\[sp,\[0-9\]+\\\]" 2 } } */
+/* { dg-final { scan-assembler-times "r6,\\\[sp,\[0-9\]+\\\]" 2 } } */
+/* { dg-final { scan-assembler-times "r8,\\\[sp,\[0-9\]+\\\]" 2 } } */
+/* { dg-final { scan-assembler "rtie" } } */
diff --git a/gcc/testsuite/gcc.target/arc/firq-2.c b/gcc/testsuite/gcc.target/arc/firq-2.c
new file mode 100644
index 0000000..dc7dafc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/firq-2.c
@@ -0,0 +1,31 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target archs }*/
+/* { dg-options "-O0 -mll64 -mirq-ctrl-saved=r0-r9 -mrgf-banked-regs=4" } */
+
+/* Check that on archs the 'firq' interrupt function type is
+   available, these are the fast interrupts.  For fast interrupts,
+   despite the use of 'irq-ctrl-saved', no registers are automatically
+   saved on stack on entry to the function.  However, the cpu save via
+   bank switch R0-R3.
+
+   We also take the opportunity to check the use of the 'rtie' instruction
+   at the end of the interrupt function.  */
+
+void __attribute__ ((interrupt("firq")))
+handler1 (void)
+{
+  asm (""
+       :
+       :
+       : "r0", "r1", "r2", "r3", "r4",
+         "r5", "r6", "r7", "r8", "r9");
+}
+/* { dg-final { scan-assembler-not "r0,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "push.*r0" } } */
+/* { dg-final { scan-assembler-not "r1,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "r2,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "r3,\\\[sp" } } */
+/* { dg-final { scan-assembler "st.*r4,\\\[sp" } } */
+/* { dg-final { scan-assembler "st.*r6,\\\[sp,\[0-9\]+\\\]" } } */
+/* { dg-final { scan-assembler "st.*r8,\\\[sp,\[0-9\]+\\\]" } } */
+/* { dg-final { scan-assembler "rtie" } } */
diff --git a/gcc/testsuite/gcc.target/arc/firq-3.c b/gcc/testsuite/gcc.target/arc/firq-3.c
new file mode 100644
index 0000000..a1d604d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/firq-3.c
@@ -0,0 +1,40 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target archs }*/
+/* { dg-options "-O2 -mll64 -mrgf-banked-regs=8" } */
+
+/* Check if R4 to R11 and R16-R27 are correctly saved on stack.  */
+
+void __attribute__ ((interrupt("firq")))
+handler1 (void)
+{
+  asm volatile (""
+		:
+		:
+		: "r0", "r1", "r2", "r3", "r4",
+		  "r5", "r6", "r7", "r8", "r9",
+		  "r10", "r11", "r12", "r13", "r14",
+		  "r15", "r16", "r17", "r18", "r19",
+		  "r20", "r21", "r22", "r23", "r24",
+		  "r25", "fp");
+}
+/* { dg-final { scan-assembler-not "r0,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "push.*r0" } } */
+/* { dg-final { scan-assembler-not "r1,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "r2,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "r3,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "r12,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "r13,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "r14,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "r15,\\\[sp" } } */
+
+/* { dg-final { scan-assembler-times "r4,\\\[sp" 2 } } */
+/* { dg-final { scan-assembler-times "r6,\\\[sp,\[0-9\]+\\\]" 2 } } */
+/* { dg-final { scan-assembler-times "r8,\\\[sp,\[0-9\]+\\\]" 2 } } */
+/* { dg-final { scan-assembler-times "r10,\\\[sp,\[0-9\]+\\\]" 2 } } */
+/* { dg-final { scan-assembler-times "r16,\\\[sp,\[0-9\]+\\\]" 2 } } */
+/* { dg-final { scan-assembler-times "r18,\\\[sp,\[0-9\]+\\\]" 2 } } */
+/* { dg-final { scan-assembler-times "r20,\\\[sp,\[0-9\]+\\\]" 2 } } */
+/* { dg-final { scan-assembler-times "r24,\\\[sp,\[0-9\]+\\\]" 2 } } */
+/* { dg-final { scan-assembler-times "fp,\\\[sp," 2 } } */
+
+/* { dg-final { scan-assembler "rtie" } } */
diff --git a/gcc/testsuite/gcc.target/arc/firq-4.c b/gcc/testsuite/gcc.target/arc/firq-4.c
new file mode 100644
index 0000000..03d3746
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/firq-4.c
@@ -0,0 +1,31 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target archs }*/
+/* { dg-options "-O2 -mll64 -mrgf-banked-regs=16" } */
+
+/* Check if R4-R9 and R16-R25 are correctly saved on stack.  */
+
+void __attribute__ ((interrupt("firq")))
+handler1 (void)
+{
+  asm volatile (""
+		:
+		:
+		: "r0", "r1", "r2", "r3", "r4",
+		  "r5", "r6", "r7", "r8", "r9",
+		  "r10", "r11", "r12", "r13", "r14",
+		  "r15", "r16", "r17", "r18", "r19",
+		  "r20", "r21", "r22", "r23", "r24",
+		  "r25", "fp");
+}
+/* { dg-final { scan-assembler-times "r4,\\\[sp" 2 } } */
+/* { dg-final { scan-assembler-times "r6,\\\[sp,\[0-9\]+\\\]" 2 } } */
+/* { dg-final { scan-assembler-times "r8,\\\[sp,\[0-9\]+\\\]" 2 } } */
+
+/* { dg-final { scan-assembler-times "r16,\\\[sp,\[0-9\]+\\\]" 2 } } */
+/* { dg-final { scan-assembler-times "r18,\\\[sp,\[0-9\]+\\\]" 2 } } */
+/* { dg-final { scan-assembler-times "r20,\\\[sp,\[0-9\]+\\\]" 2 } } */
+/* { dg-final { scan-assembler-times "r24,\\\[sp,\[0-9\]+\\\]" 2 } } */
+
+/* { dg-final { scan-assembler-not "fp,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "push.*fp" } } */
+/* { dg-final { scan-assembler "mov_s.*fp,sp" } } */
diff --git a/gcc/testsuite/gcc.target/arc/firq-5.c b/gcc/testsuite/gcc.target/arc/firq-5.c
new file mode 100644
index 0000000..29f17a3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/firq-5.c
@@ -0,0 +1,15 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target archs }*/
+/* { dg-options "-O2 -mrgf-banked-regs=16" } */
+
+/* Check if blink is pushed on the stack or not.   */
+
+extern void bar (void);
+
+void __attribute__ ((interrupt("firq")))
+handler1 (void)
+{
+  bar ();
+}
+/* { dg-final { scan-assembler-not "push.*blink" } } */
+/* { dg-final { scan-assembler-not "pop.*blink" } } */
diff --git a/gcc/testsuite/gcc.target/arc/firq-6.c b/gcc/testsuite/gcc.target/arc/firq-6.c
new file mode 100644
index 0000000..9421200
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/firq-6.c
@@ -0,0 +1,21 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target archs }*/
+/* { dg-options "-O2 -mll64 -mrgf-banked-regs=32" } */
+
+/* Check if we have any register saved on stack.  */
+
+void __attribute__ ((interrupt("firq")))
+handler1 (void)
+{
+  asm volatile (""
+		:
+		:
+		: "r0", "r1", "r2", "r3", "r4",
+		  "r5", "r6", "r7", "r8", "r9",
+		  "r10", "r11", "r12", "r13", "r14",
+		  "r15", "r16", "r17", "r18", "r19",
+		  "r20", "r21", "r22", "r23", "r24",
+		  "r25", "fp");
+}
+/* { dg-final { scan-assembler-not "(s|l)(t|d)d.*r\[0-9\]+,\\\[sp,\[0-9\]+\\\]" } } */
+/* { dg-final { scan-assembler "mov_s.*fp,sp" } } */