This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH 2/2] Fast interrupts support.
- From: Andrew Burgess <andrew dot burgess at embecosm dot com>
- To: Claudiu Zissulescu <Claudiu dot Zissulescu at synopsys dot com>
- Cc: gcc-patches at gcc dot gnu dot org, Francois dot Bedard at synopsys dot com, sandra at codesourcery dot com
- Date: Mon, 8 May 2017 15:50:39 +0100
- Subject: Re: [PATCH 2/2] Fast interrupts support.
- Authentication-results: sourceware.org; auth=none
- References: <58FF6D3F.7020707@codesourcery.com> <1493982164-29760-1-git-send-email-claziss@synopsys.com> <1493982164-29760-3-git-send-email-claziss@synopsys.com>
* Claudiu Zissulescu <Claudiu.Zissulescu@synopsys.com> [2017-05-05 13:02:44 +0200]:
> 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.
> * testsuite/gcc.target/arc/firq-1.c: New file.
> * testsuite/gcc.target/arc/firq-2.c: Likewise.
> * testsuite/gcc.target/arc/firq-3.c: Likewise.
> * testsuite/gcc.target/arc/firq-4.c: Likewise.
> * testsuite/gcc.target/arc/firq-5.c: Likewise.
> * testsuite/gcc.target/arc/firq-6.c: Likewise.
Looks fine to me,
Thanks,
Andrew
> ---
> 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 | 10 ++++
> 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, 277 insertions(+), 30 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
>
> diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
> index a61faef..a0cd597 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) \
> @@ -924,6 +933,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
> @@ -966,6 +996,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)
> @@ -979,6 +1011,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();
> }
> @@ -1787,9 +1826,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\"",
> @@ -1797,10 +1836,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;
> }
> @@ -2360,6 +2400,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;
> @@ -2386,7 +2428,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
> @@ -2394,7 +2458,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
> @@ -2723,11 +2788,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. */
>
> @@ -2841,7 +2901,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 ();
> }
> @@ -9700,6 +9761,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 5491130..52f121f 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. */
>
> @@ -1501,10 +1501,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 2221fb5..5c3766c 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 bd3b339..35c97f0 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -607,6 +607,7 @@ Objective-C and Objective-C++ Dialects}.
> -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
> +-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
> @@ -14554,6 +14555,15 @@ always starts with @code{r0}, the upper limit is @code{fp} register.
> @var{blink} and @var{lp_count} are optional. This option is only
> valid for ARC EM and ARC HS cores.
>
> +@item -mrgf-banked-regs=@var{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, and 32.
> +
> @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" } } */
> --
> 1.9.1
>