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" } } */
