diff options
author | Claudiu Zissulescu <claziss@synopsys.com> | 2017-05-09 16:19:35 +0200 |
---|---|---|
committer | Claudiu Zissulescu <claziss@gcc.gnu.org> | 2017-05-09 16:19:35 +0200 |
commit | c7314bc17b9dde51f1eac83dc399d411f5fdd4a0 (patch) | |
tree | 936ddafec5b9117a5b74e1054e23cab049a0bc25 /gcc/config/arc/arc.c | |
parent | 4145318390da5670b2e571593ccfe7779863b93c (diff) | |
download | gcc-c7314bc17b9dde51f1eac83dc399d411f5fdd4a0.zip gcc-c7314bc17b9dde51f1eac83dc399d411f5fdd4a0.tar.gz gcc-c7314bc17b9dde51f1eac83dc399d411f5fdd4a0.tar.bz2 |
[ARC]Fast interrupts support.
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/
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 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/
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.
Co-Authored-By: Andrew Burgess <andrew.burgess@embecosm.com>
From-SVN: r247796
Diffstat (limited to 'gcc/config/arc/arc.c')
-rw-r--r-- | gcc/config/arc/arc.c | 106 |
1 files changed, 85 insertions, 21 deletions
diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c index c754d82..46ad31e 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. |