+2017-05-09 Claudiu Zissulescu <claziss@synopsys.com>
+ Andrew Burgess <andrew.burgess@embecosm.com>
+
+ * config/arc/arc.c (ARC_AUTOBLINK_IRQ_P): Consider fast interrupts
+ case.
+ (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.
+
2017-05-09 Claudiu Zissulescu <claziss@synopsys.com>
* config/arc/arc.c (irq_ctrl_saved): New variable.
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) \
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
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)
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();
}
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\"",
*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;
}
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;
{
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
&& (!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
}
} /* 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. */
/* 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 ();
}
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.
/* 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. */
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;
= 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\";
}
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")))
(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];
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.
-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
@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
+2017-05-09 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.
+
2017-05-09 Claudiu Zissulescu <claziss@synopsys.com>
* gcc.target/arc/interrupt-5.c: Newfile.
--- /dev/null
+/* { 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" } } */
--- /dev/null
+/* { 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" } } */
--- /dev/null
+/* { 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" } } */
--- /dev/null
+/* { 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" } } */
--- /dev/null
+/* { 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" } } */
--- /dev/null
+/* { 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" } } */