public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 0/3] [ARC] New features
@ 2017-04-25 13:06 Claudiu Zissulescu
  2017-04-25 13:21 ` [PATCH 3/3] [ARC] Add support for advanced mpy/mac instructions Claudiu Zissulescu
                   ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: Claudiu Zissulescu @ 2017-04-25 13:06 UTC (permalink / raw)
  To: gcc-patches; +Cc: Claudiu.Zissulescu, Francois.Bedard, andrew.burgess

From: claziss <claziss@synopsys.com>

Hi,

This is a set of new features introduced to ARC. First patch is adding
support for automatic context save/restore for regular interrupts. It
is done using an hardware available machinery, thus, saving/restoring
registers by the compiler is not needed in these cases.

Second patch is adding support for fast interrupts, which are making
use of register bank switching for fast serving interrupt routines.

Last patch is introducing multiply-and-accumulate and 64-bit result
multiplication operations. These ops are available in selected new ARC
v2 cores.

Ok to apply?
Claudiu


Claudiu Zissulescu (3):
  [ARC] Automatic context save/restore for regular interrupts.
  [ARC] Fast interrupts support.
  [ARC] Add support for advanced mpy/mac instructions.

 gcc/config/arc/arc.c                       | 403 ++++++++++++++++++++++++++---
 gcc/config/arc/arc.h                       |  13 +-
 gcc/config/arc/arc.md                      | 283 +++++++++++++++++++-
 gcc/config/arc/arc.opt                     |   8 +
 gcc/config/arc/predicates.md               |   5 +
 gcc/doc/invoke.texi                        |  24 +-
 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 ++
 gcc/testsuite/gcc.target/arc/interrupt-5.c |  19 ++
 gcc/testsuite/gcc.target/arc/interrupt-6.c |  22 ++
 gcc/testsuite/gcc.target/arc/interrupt-7.c |  16 ++
 gcc/testsuite/gcc.target/arc/interrupt-8.c |  27 ++
 gcc/testsuite/gcc.target/arc/interrupt-9.c |  17 ++
 17 files changed, 950 insertions(+), 52 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
 create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-5.c
 create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-6.c
 create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-7.c
 create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-8.c
 create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-9.c

-- 
1.9.1

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 3/3] [ARC] Add support for advanced mpy/mac instructions.
  2017-04-25 13:06 [PATCH 0/3] [ARC] New features Claudiu Zissulescu
@ 2017-04-25 13:21 ` Claudiu Zissulescu
  2017-05-08 15:10   ` Andrew Burgess
  2017-04-25 13:27 ` [PATCH 2/3] [ARC] Fast interrupts support Claudiu Zissulescu
  2017-04-25 13:29 ` [PATCH 1/3] [ARC] Automatic context save/restore for regular interrupts Claudiu Zissulescu
  2 siblings, 1 reply; 17+ messages in thread
From: Claudiu Zissulescu @ 2017-04-25 13:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: Claudiu.Zissulescu, Francois.Bedard, andrew.burgess

Add support for MAC and DMPY instructions. ARCv2 Only.

gcc/
2016-12-08  Claudiu Zissulescu  <claziss@synopsys.com>

	* config/arc/arc.c (arc_conditional_register_usage): Handle ACCL,
	ACCH registers.
	* config/arc/arc.md (mulsidi3): Use advanced mpy instructions when
	available.
	(umulsidi3): Likewise.
	(mulsidi3_700): Disable this pattern when we have advanced mpy
	instructions.
	(umulsidi3_700): Likewise.
	(maddsidi4): New pattern.
	(macd, mac, mac_r, umaddsidi4, macdu, macu, macu_r): Likewise.
	(mpyd_arcv2hs, mpyd_imm_arcv2hs, mpydu_arcv2hs): Likewise.
	(mpydu_imm_arcv2hs): Likewise.
	* config/arc/predicates.md (accl_operand): New predicate.
---
 gcc/config/arc/arc.c         |   5 +-
 gcc/config/arc/arc.md        | 266 ++++++++++++++++++++++++++++++++++++++++++-
 gcc/config/arc/predicates.md |   5 +
 3 files changed, 272 insertions(+), 4 deletions(-)

diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
index 170b8dd..238244b 100644
--- a/gcc/config/arc/arc.c
+++ b/gcc/config/arc/arc.c
@@ -1789,8 +1789,9 @@ arc_conditional_register_usage (void)
   arc_regno_reg_class[PROGRAM_COUNTER_REGNO] = GENERAL_REGS;
 
   /*ARCV2 Accumulator.  */
-  if (TARGET_V2
-      && (TARGET_FP_DP_FUSED || TARGET_FP_SP_FUSED))
+  if ((TARGET_V2
+       && (TARGET_FP_DP_FUSED || TARGET_FP_SP_FUSED))
+      || TARGET_PLUS_DMPY)
   {
     arc_regno_reg_class[ACCL_REGNO] = WRITABLE_CORE_REGS;
     arc_regno_reg_class[ACCH_REGNO] = WRITABLE_CORE_REGS;
diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md
index ffab390..db5867c 100644
--- a/gcc/config/arc/arc.md
+++ b/gcc/config/arc/arc.md
@@ -2157,6 +2157,18 @@
   "TARGET_ANY_MPY"
 "
 {
+  if (TARGET_PLUS_MACD)
+    {
+     if (CONST_INT_P (operands[2]))
+       {
+	emit_insn (gen_mpyd_imm_arcv2hs (operands[0], operands[1], operands[2]));
+       }
+     else
+       {
+	emit_insn (gen_mpyd_arcv2hs (operands[0], operands[1], operands[2]));
+       }
+     DONE;
+    }
   if (TARGET_MPY)
     {
       operands[2] = force_reg (SImode, operands[2]);
@@ -2237,7 +2249,7 @@
   [(set (match_operand:DI 0 "register_operand" "=&r")
 	(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%c"))
 		 (sign_extend:DI (match_operand:SI 2 "extend_operand" "cL"))))]
-  "TARGET_MPY"
+  "TARGET_MPY && !TARGET_PLUS_MACD"
   "#"
   "&& reload_completed"
   [(const_int 0)]
@@ -2390,6 +2402,18 @@
 		 (zero_extend:DI (match_operand:SI 2 "nonmemory_operand" ""))))]
   ""
 {
+  if (TARGET_PLUS_MACD)
+    {
+     if (CONST_INT_P (operands[2]))
+       {
+	emit_insn (gen_mpydu_imm_arcv2hs (operands[0], operands[1], operands[2]));
+       }
+     else
+       {
+	emit_insn (gen_mpydu_arcv2hs (operands[0], operands[1], operands[2]));
+       }
+     DONE;
+    }
   if (TARGET_MPY)
     {
       operands[2] = force_reg (SImode, operands[2]);
@@ -2480,7 +2504,7 @@
   [(set (match_operand:DI 0 "dest_reg_operand" "=&r")
 	(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%c"))
 		 (zero_extend:DI (match_operand:SI 2 "extend_operand" "cL"))))]
-  "TARGET_MPY"
+  "TARGET_MPY && !TARGET_PLUS_MACD"
   "#"
   "reload_completed"
   [(const_int 0)]
@@ -6215,6 +6239,244 @@
   ""
   [(set_attr "length" "0")])
 
+;; MAC and DMPY instructions
+(define_insn_and_split "maddsidi4"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(plus:DI
+	 (mult:DI
+	  (sign_extend:DI (match_operand:SI 1 "register_operand" "%r"))
+	  (sign_extend:DI (match_operand:SI 2 "extend_operand" "ri")))
+	 (match_operand:DI 3 "register_operand" "r")))]
+  "TARGET_PLUS_DMPY"
+  "#"
+  "TARGET_PLUS_DMPY && reload_completed"
+  [(const_int 0)]
+  "{
+   rtx acc_reg = gen_rtx_REG (DImode, ACC_REG_FIRST);
+   emit_move_insn (acc_reg, operands[3]);
+   if (TARGET_PLUS_MACD)
+     emit_insn (gen_macd (operands[0], operands[1], operands[2]));
+   else
+     {
+      emit_insn (gen_mac (operands[1], operands[2]));
+      emit_move_insn (operands[0], acc_reg);
+     }
+   DONE;
+   }"
+  [(set_attr "type" "multi")
+   (set_attr "length" "36")])
+
+(define_insn "macd"
+  [(set (match_operand:DI 0 "even_register_operand"	       "=Rcr,r,r")
+	(plus:DI
+	 (mult:DI
+	  (sign_extend:DI (match_operand:SI 1 "register_operand" "%0,c,c"))
+	  (sign_extend:DI (match_operand:SI 2 "extend_operand" " c,cI,Cal")))
+	 (reg:DI ARCV2_ACC)))
+   (set (reg:DI ARCV2_ACC)
+	(plus:DI
+	 (mult:DI (sign_extend:DI (match_dup 1))
+		  (sign_extend:DI (match_dup 2)))
+	 (reg:DI ARCV2_ACC)))]
+ "TARGET_PLUS_MACD"
+ "macd %0,%1,%2"
+  [(set_attr "length" "4,4,8")
+   (set_attr "type" "multi")
+   (set_attr "predicable" "yes,no,no")
+   (set_attr "cond" "canuse,nocond,nocond")])
+
+(define_insn "mac"
+  [(set (reg:DI ARCV2_ACC)
+	(plus:DI
+	 (mult:DI (sign_extend:DI (match_operand:SI 0 "register_operand" "%r,r"))
+		  (sign_extend:DI (match_operand:SI 1 "extend_operand" "rI,i")))
+	 (reg:DI ARCV2_ACC)))]
+ "TARGET_PLUS_DMPY"
+ "mac 0,%0,%1"
+  [(set_attr "length" "4,8")
+   (set_attr "type" "multi")
+   (set_attr "predicable" "no")
+   (set_attr "cond" "nocond")])
+
+(define_peephole2
+  [(set (reg:DI ARCV2_ACC)
+	(plus:DI
+	 (mult:DI (sign_extend:DI (match_operand:SI 0 "register_operand" ""))
+		  (sign_extend:DI (match_operand:SI 1 "extend_operand" "")))
+	 (reg:DI ARCV2_ACC)))
+   (set (match_operand:SI 2 "register_operand" "")
+	(match_operand:SI 3 "accl_operand" ""))]
+ "TARGET_PLUS_DMPY"
+ [(const_int 0)]
+ {
+  emit_insn (gen_mac_r (operands[2], operands[0], operands[1]));
+  DONE;
+ })
+
+(define_insn "mac_r"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+	(truncate:SI
+	 (plus:DI
+	  (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%r,r"))
+		   (sign_extend:DI (match_operand:SI 2 "extend_operand" "rI,i")))
+	  (reg:DI ARCV2_ACC))))
+   (clobber (reg:DI ARCV2_ACC))]
+ "TARGET_PLUS_DMPY"
+ "mac %0,%1,%2"
+  [(set_attr "length" "4,8")
+   (set_attr "type" "multi")
+   (set_attr "predicable" "no")
+   (set_attr "cond" "nocond")])
+
+(define_insn_and_split "umaddsidi4"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(plus:DI
+	 (mult:DI
+	  (zero_extend:DI (match_operand:SI 1 "register_operand" "%r"))
+	  (zero_extend:DI (match_operand:SI 2 "extend_operand" "ri")))
+	 (match_operand:DI 3 "register_operand" "r")))]
+  "TARGET_PLUS_DMPY"
+  "#"
+  "TARGET_PLUS_DMPY && reload_completed"
+  [(const_int 0)]
+  "{
+   rtx acc_reg = gen_rtx_REG (DImode, ACC_REG_FIRST);
+   emit_move_insn (acc_reg, operands[3]);
+   if (TARGET_PLUS_MACD)
+     emit_insn (gen_macdu (operands[0], operands[1], operands[2]));
+   else
+     {
+      emit_insn (gen_macu (operands[1], operands[2]));
+      emit_move_insn (operands[0], acc_reg);
+     }
+   DONE;
+   }"
+  [(set_attr "type" "multi")
+   (set_attr "length" "36")])
+
+(define_insn "macdu"
+  [(set (match_operand:DI 0 "even_register_operand"	       "=Rcr,r,r")
+	(plus:DI
+	 (mult:DI
+	  (zero_extend:DI (match_operand:SI 1 "register_operand" "%0,c,c"))
+	  (zero_extend:DI (match_operand:SI 2 "extend_operand" " c,cI,i")))
+	 (reg:DI ARCV2_ACC)))
+   (set (reg:DI ARCV2_ACC)
+	(plus:DI
+	 (mult:DI (zero_extend:DI (match_dup 1))
+		  (zero_extend:DI (match_dup 2)))
+	 (reg:DI ARCV2_ACC)))]
+ "TARGET_PLUS_MACD"
+ "macdu %0,%1,%2"
+  [(set_attr "length" "4,4,8")
+   (set_attr "type" "multi")
+   (set_attr "predicable" "yes,no,no")
+   (set_attr "cond" "canuse,nocond,nocond")])
+
+(define_insn "macu"
+  [(set (reg:DI ARCV2_ACC)
+	(plus:DI
+	 (mult:DI (zero_extend:DI (match_operand:SI 0 "register_operand" "%r,r"))
+		  (zero_extend:DI (match_operand:SI 1 "extend_operand" "rI,i")))
+	 (reg:DI ARCV2_ACC)))]
+ "TARGET_PLUS_DMPY"
+ "macu 0,%0,%1"
+  [(set_attr "length" "4,8")
+   (set_attr "type" "multi")
+   (set_attr "predicable" "no")
+   (set_attr "cond" "nocond")])
+
+(define_peephole2
+  [(set (reg:DI ARCV2_ACC)
+	(plus:DI
+	 (mult:DI (zero_extend:DI (match_operand:SI 0 "register_operand" ""))
+		  (zero_extend:DI (match_operand:SI 1 "extend_operand" "")))
+	 (reg:DI ARCV2_ACC)))
+   (set (match_operand:SI 2 "register_operand" "")
+	(match_operand:SI 3 "accl_operand" ""))]
+ "TARGET_PLUS_DMPY"
+ [(const_int 0)]
+ {
+  emit_insn (gen_macu_r (operands[2], operands[0], operands[1]));
+  DONE;
+ })
+
+(define_insn "macu_r"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+	(truncate:SI
+	 (plus:DI
+	  (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%r,r"))
+		   (zero_extend:DI (match_operand:SI 2 "extend_operand" "rI,i")))
+	  (reg:DI ARCV2_ACC))))
+   (clobber (reg:DI ARCV2_ACC))]
+ "TARGET_PLUS_DMPY"
+ "macu %0,%1,%2"
+  [(set_attr "length" "4,8")
+   (set_attr "type" "multi")
+   (set_attr "predicable" "no")
+   (set_attr "cond" "nocond")])
+
+(define_insn "mpyd_arcv2hs"
+  [(set (match_operand:DI 0 "even_register_operand"			"=Rcr, r")
+	(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand"	 "  0, c"))
+		 (sign_extend:DI (match_operand:SI 2 "register_operand"	 "  c, c"))))
+   (set (reg:DI ARCV2_ACC)
+	(mult:DI
+	  (sign_extend:DI (match_dup 1))
+	  (sign_extend:DI (match_dup 2))))]
+  "TARGET_PLUS_MACD"
+  "mpyd%? %0,%1,%2"
+  [(set_attr "length" "4,4")
+  (set_attr "iscompact" "false")
+  (set_attr "type" "multi")
+  (set_attr "predicable" "yes,no")
+  (set_attr "cond" "canuse,nocond")])
+
+(define_insn "mpyd_imm_arcv2hs"
+  [(set (match_operand:DI 0 "even_register_operand"			"=Rcr, r,r,Rcr,	 r")
+	(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand"	 "  0, c,0,  0,	 c"))
+		 (match_operand 2		    "immediate_operand"	 "  L, L,I,Cal,Cal")))
+   (set (reg:DI ARCV2_ACC)
+	(mult:DI (sign_extend:DI (match_dup 1))
+		 (match_dup 2)))]
+  "TARGET_PLUS_MACD"
+  "mpyd%? %0,%1,%2"
+  [(set_attr "length" "4,4,4,8,8")
+  (set_attr "iscompact" "false")
+  (set_attr "type" "multi")
+  (set_attr "predicable" "yes,no,no,yes,no")
+  (set_attr "cond" "canuse,nocond,nocond,canuse_limm,nocond")])
+
+(define_insn "mpydu_arcv2hs"
+  [(set (match_operand:DI 0 "even_register_operand"			"=Rcr, r")
+	(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand"	 "  0, c"))
+		 (zero_extend:DI (match_operand:SI 2 "register_operand" "   c, c"))))
+   (set (reg:DI ARCV2_ACC)
+	(mult:DI (zero_extend:DI (match_dup 1))
+		 (zero_extend:DI (match_dup 2))))]
+  "TARGET_PLUS_MACD"
+  "mpydu%? %0,%1,%2"
+  [(set_attr "length" "4,4")
+  (set_attr "iscompact" "false")
+  (set_attr "type" "multi")
+  (set_attr "predicable" "yes,no")
+  (set_attr "cond" "canuse,nocond")])
+
+(define_insn "mpydu_imm_arcv2hs"
+  [(set (match_operand:DI 0 "even_register_operand"			"=Rcr, r,r,Rcr,	 r")
+	(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand"	 "  0, c,0,  0,	 c"))
+		 (match_operand 2		    "immediate_operand"	 "  L, L,I,Cal,Cal")))
+   (set (reg:DI ARCV2_ACC)
+	(mult:DI (zero_extend:DI (match_dup 1))
+		 (match_dup 2)))]
+  "TARGET_PLUS_MACD"
+  "mpydu%? %0,%1,%2"
+  [(set_attr "length" "4,4,4,8,8")
+  (set_attr "iscompact" "false")
+  (set_attr "type" "multi")
+  (set_attr "predicable" "yes,no,no,yes,no")
+  (set_attr "cond" "canuse,nocond,nocond,canuse_limm,nocond")])
+
 ;; include the arc-FPX instructions
 (include "fpx.md")
 
diff --git a/gcc/config/arc/predicates.md b/gcc/config/arc/predicates.md
index f4c2a80..7ddec91 100644
--- a/gcc/config/arc/predicates.md
+++ b/gcc/config/arc/predicates.md
@@ -697,6 +697,11 @@
   (and (match_code "reg")
        (match_test "REGNO (op) == (TARGET_BIG_ENDIAN ? 58 : 59)")))
 
+(define_predicate "accl_operand"
+  (and (match_code "reg")
+       (match_test "REGNO (op) == (TARGET_BIG_ENDIAN ? 59 : 58)")
+       (match_test "TARGET_V2")))
+
 ; Unfortunately, we can not allow a const_int_operand before reload, because
 ; reload needs a non-void mode to guide it how to reload the inside of a
 ; {sign_}extend.
-- 
1.9.1

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 2/3] [ARC] Fast interrupts support.
  2017-04-25 13:06 [PATCH 0/3] [ARC] New features Claudiu Zissulescu
  2017-04-25 13:21 ` [PATCH 3/3] [ARC] Add support for advanced mpy/mac instructions Claudiu Zissulescu
@ 2017-04-25 13:27 ` Claudiu Zissulescu
  2017-04-25 15:54   ` Sandra Loosemore
  2017-04-25 13:29 ` [PATCH 1/3] [ARC] Automatic context save/restore for regular interrupts Claudiu Zissulescu
  2 siblings, 1 reply; 17+ messages in thread
From: Claudiu Zissulescu @ 2017-04-25 13:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: Claudiu.Zissulescu, Francois.Bedard, andrew.burgess

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

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

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/3] [ARC] Automatic context save/restore for regular interrupts.
  2017-04-25 13:06 [PATCH 0/3] [ARC] New features Claudiu Zissulescu
  2017-04-25 13:21 ` [PATCH 3/3] [ARC] Add support for advanced mpy/mac instructions Claudiu Zissulescu
  2017-04-25 13:27 ` [PATCH 2/3] [ARC] Fast interrupts support Claudiu Zissulescu
@ 2017-04-25 13:29 ` Claudiu Zissulescu
  2017-04-25 15:46   ` Sandra Loosemore
  2 siblings, 1 reply; 17+ messages in thread
From: Claudiu Zissulescu @ 2017-04-25 13:29 UTC (permalink / raw)
  To: gcc-patches; +Cc: Claudiu.Zissulescu, Francois.Bedard, andrew.burgess

The AUX_IRQ_CTRL register controls the behavior of automated register
save and restore or prologue and epilogue sequences during a non-fast
interrupt entry and exit, and context save and restore instructions.

A user passes to the compiler the configuration of the AUX_IRQ_CTRL
register via mirq-ctrl-saved option.  This option, specifies
gneral-purposes registers that the processor saves/restores on
interrupt entry and exit, and it is only valid for ARC EM and ARC HS
cores.

gcc/
2016-10-03  Claudiu Zissulescu  <claziss@synopsys.com>

	* config/arc/arc.c (irq_ctrl_saved): New variable.
	(ARC_AUTOBLINK_IRQ_P): Define.
	(ARC_AUTOFP_IRQ_P): Likewise.
	(ARC_AUTO_IRQ_P): Likewise.
	(irq_range): New function.
	(arc_must_save_register): Likewise.
	(arc_must_save_return_addr): Likewise.
	(arc_dwarf_emit_irq_save_regs): Likewise.
	(arc_override_options): Handle deferred options.
	(MUST_SAVE_REGISTER): Deleted, replaced by arc_must_save_register.
	(MUST_SAVE_RETURN_ADDR): Deleted, replaced by
	arc_must_save_return_addr.
	(arc_compute_frame_size): Handle automated save and restore of
	registers.
	(arc_expand_prologue): Likewise.
	(arc_expand_epilogue): Likewise.
	* config/arc/arc.md (stack_irq_dwarf): New unspec instruction.
	* config/arc/arc.opt (mirq-ctrl-saved): New option.
	* doc/invoke.texi (mirq-ctrl-saved): Document option.

gcc/testsuite
2016-10-03  Claudiu Zissulescu  <claziss@synopsys.com>

	* gcc.target/arc/interrupt-5.c: Newfile.
	* gcc.target/arc/interrupt-6.c: Likewise.
	* gcc.target/arc/interrupt-7.c: Likewise.
	* gcc.target/arc/interrupt-8.c: Likewise.
	* gcc.target/arc/interrupt-9.c: Likewise.
---
 gcc/config/arc/arc.c                       | 320 ++++++++++++++++++++++++++---
 gcc/config/arc/arc.md                      |   8 +
 gcc/config/arc/arc.opt                     |   4 +
 gcc/doc/invoke.texi                        |  11 +-
 gcc/testsuite/gcc.target/arc/interrupt-5.c |  19 ++
 gcc/testsuite/gcc.target/arc/interrupt-6.c |  22 ++
 gcc/testsuite/gcc.target/arc/interrupt-7.c |  16 ++
 gcc/testsuite/gcc.target/arc/interrupt-8.c |  27 +++
 gcc/testsuite/gcc.target/arc/interrupt-9.c |  17 ++
 9 files changed, 412 insertions(+), 32 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-5.c
 create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-6.c
 create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-7.c
 create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-8.c
 create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-9.c

diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
index 696e4a0..35c5295 100644
--- a/gcc/config/arc/arc.c
+++ b/gcc/config/arc/arc.c
@@ -63,6 +63,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "rtl-iter.h"
 #include "alias.h"
+#include "opts.h"
 
 /* Which cpu we're compiling for (ARC600, ARC601, ARC700).  */
 static char arc_cpu_name[10] = "";
@@ -111,6 +112,29 @@ struct GTY (()) arc_ccfsm
   int target_label;
 };
 
+/* Status of the IRQ_CTRL_AUX register.  */
+typedef struct irq_ctrl_saved_t
+{
+  short irq_save_last_reg;      /* Last register number used by
+				   IRQ_CTRL_SAVED aux_reg.  */
+  bool  irq_save_blink;         /* True if BLINK is automatically
+				   saved.  */
+  bool  irq_save_lpcount;       /* True if LPCOUNT is automatically
+				   saved.  */
+} 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			\
+       || (irq_ctrl_saved.irq_save_last_reg >= 0)))
+
 #define arc_ccfsm_current cfun->machine->ccfsm_current
 
 #define ARC_CCFSM_BRANCH_DELETED_P(STATE) \
@@ -809,11 +833,110 @@ arc_init (void)
     }
 }
 
+/* Parse -mirq-ctrl-saved= option string.  Registers may be specified
+   individually, or as ranges such as "r0-r3".  Registers accepted are
+   r0 through r31 and lp_count.  Registers and ranges must be
+   comma-separated.  */
+
+static void
+irq_range (const char *cstr)
+{
+  int i, first, last, blink, lpcount, xreg;
+  char *str, *dash, *comma;
+
+  i = strlen (cstr);
+  str = (char *) alloca (i + 1);
+  memcpy (str, cstr, i + 1);
+  blink = -1;
+  lpcount = -1;
+
+  dash = strchr (str, '-');
+  if (!dash)
+    {
+      warning (0, "value of -mirq-ctrl-saved must have form R0-REGx");
+      return;
+    }
+  *dash = '\0';
+
+  comma = strchr (dash + 1, ',');
+  if (comma)
+    *comma = '\0';
+
+  first = decode_reg_name (str);
+  if (first != 0)
+    {
+      warning (0, "first register must be R0");
+      return;
+    }
+
+  /* At this moment we do not have the register names initialized
+     accordingly.  */
+  if (!strcmp (dash + 1, "ilink"))
+    last = 29;
+  else
+    last = decode_reg_name (dash + 1);
+
+  if (last < 0)
+    {
+      warning (0, "unknown register name: %s", dash + 1);
+      return;
+    }
+
+  if (!(last & 0x01))
+    {
+      warning (0, "last register name %s must be an odd register", dash + 1);
+      return;
+    }
+
+  *dash = '-';
+
+  if (first > last)
+    {
+      warning (0, "%s-%s is an empty range", str, dash + 1);
+      return;
+    }
+
+  while (comma)
+    {
+      *comma = ',';
+      str = comma + 1;
+
+      comma = strchr (str, ',');
+      if (comma)
+	*comma = '\0';
+
+      xreg = decode_reg_name (str);
+      switch (xreg)
+	{
+	case 31:
+	  blink = 31;
+	  break;
+
+	case 60:
+	  lpcount = 60;
+	  break;
+
+	default:
+	  warning (0, "unknown register name: %s", str);
+	  return;
+	}
+    }
+
+  irq_ctrl_saved.irq_save_last_reg = last;
+  irq_ctrl_saved.irq_save_blink    = (blink == 31) || (last == 31);
+  irq_ctrl_saved.irq_save_lpcount  = (lpcount == 60);
+}
+
 /* Check ARC options, generate derived target attributes.  */
 
 static void
 arc_override_options (void)
 {
+  unsigned int i;
+  cl_deferred_option *opt;
+  vec<cl_deferred_option> *vopt
+    = (vec<cl_deferred_option> *) arc_deferred_options;
+
   if (arc_cpu == PROCESSOR_NONE)
     arc_cpu = TARGET_CPU_DEFAULT;
 
@@ -842,6 +965,28 @@ arc_override_options (void)
       gcc_unreachable ();
     }
 
+  irq_ctrl_saved.irq_save_last_reg = -1;
+  irq_ctrl_saved.irq_save_blink    = false;
+  irq_ctrl_saved.irq_save_lpcount  = false;
+
+  /* Handle the deferred options.  */
+  if (vopt)
+    FOR_EACH_VEC_ELT (*vopt, i, opt)
+      {
+	switch (opt->opt_index)
+	  {
+	  case OPT_mirq_ctrl_saved_:
+	    if (TARGET_V2)
+	      irq_range (opt->arg);
+	    else
+	      warning (0, "option -mirq-ctrl-saved valid only for ARC v2 processors");
+	    break;
+
+	  default:
+	    gcc_unreachable();
+	  }
+      }
+
   /* Set cpu flags accordingly to architecture/selected cpu.  The cpu
      specific flags are set in arc-common.c.  The architecture forces
      the default hardware configurations in, regardless what command
@@ -2254,15 +2399,43 @@ arc_compute_function_type (struct function *fun)
    code like this.  The number of frames that use __builtin_eh_return
    is pretty low, so optimising them is not critical right now.  */
 
-#define MUST_SAVE_REGISTER(regno, interrupt_p)				\
-  (((regno) != RETURN_ADDR_REGNUM && (regno) != FRAME_POINTER_REGNUM	\
-    && (df_regs_ever_live_p (regno)					\
-	&& (!call_used_regs[regno] || interrupt_p)))			\
-   || (flag_pic && crtl->uses_pic_offset_table				\
-       && regno == PIC_OFFSET_TABLE_REGNUM)				\
-   || (crtl->calls_eh_return && (regno > 2 && regno < 27)))
+static bool
+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));
+
+  if ((regno) != RETURN_ADDR_REGNUM
+      && (regno) != FRAME_POINTER_REGNUM
+      && df_regs_ever_live_p (regno)
+      && (!call_used_regs[regno]
+	  || ARC_INTERRUPT_P (fn_type))
+      /* Do not emit code for auto saved regs.  */
+      && !irq_auto_save_p)
+    return true;
+
+  if (flag_pic && crtl->uses_pic_offset_table
+      && regno == PIC_OFFSET_TABLE_REGNUM)
+    return true;
+
+  if (crtl->calls_eh_return && (regno > 2 && regno < 27))
+    return true;
+
+  return false;
+}
+
+/* Return true if the return address must be saved in the current function,
+   otherwise return false.  */
+
+static bool
+arc_must_save_return_addr (struct function *func)
+{
+  if (func->machine->frame_info.save_return_addr)
+    return true;
 
-#define MUST_SAVE_RETURN_ADDR	(cfun->machine->frame_info.save_return_addr)
+  return false;
+}
 
 /* Helper function to wrap FRAME_POINTER_NEEDED.  We do this as
    FRAME_POINTER_NEEDED will not be true until the IRA (Integrated
@@ -2280,9 +2453,9 @@ arc_compute_function_type (struct function *fun)
 
    As the frame pointer is handled as a special case in our prologue
    and epilogue code it must not be saved and restored using the
-   MUST_SAVE_REGISTER mechanism otherwise we run into issues where GCC
-   believes that the function is not using a frame pointer and that
-   the value in the fp register is the frame pointer, while the
+   arc_must_save_register mechanism otherwise we run into issues where
+   GCC believes that the function is not using a frame pointer and
+   that the value in the fp register is the frame pointer, while the
    prologue and epilogue are busy saving and restoring the fp
    register.  This issue is fixed in this commit too.
 
@@ -2352,8 +2525,6 @@ arc_compute_frame_size (void)
   unsigned int total_size, var_size, args_size, pretend_size, extra_size;
   unsigned int reg_size, reg_offset;
   unsigned int gmask;
-  enum arc_function_type fn_type;
-  int interrupt_p;
   struct arc_frame_info *frame_info;
   int size;
 
@@ -2378,15 +2549,13 @@ arc_compute_frame_size (void)
 
   reg_size = 0;
   gmask = 0;
-  fn_type = arc_compute_function_type (cfun);
-  interrupt_p = ARC_INTERRUPT_P (fn_type);
 
   for (regno = 0; regno <= 31; regno++)
     {
-      if (MUST_SAVE_REGISTER (regno, interrupt_p))
+      if (arc_must_save_register (regno, cfun))
 	{
 	  reg_size += UNITS_PER_WORD;
-	  gmask |= 1 << regno;
+	  gmask |= 1L << regno;
 	}
     }
 
@@ -2419,7 +2588,7 @@ arc_compute_frame_size (void)
     }
 
   extra_size = 0;
-  if (MUST_SAVE_RETURN_ADDR)
+  if (arc_must_save_return_addr (cfun))
     extra_size = 4;
   if (arc_frame_pointer_needed ())
     extra_size += 4;
@@ -2641,6 +2810,77 @@ arc_save_restore (rtx base_reg,
 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.  */
+
+static void
+arc_dwarf_emit_irq_save_regs (void)
+{
+  rtx tmp, par, insn, reg;
+  int i, offset, j;
+
+  par = gen_rtx_SEQUENCE (VOIDmode,
+			  rtvec_alloc (irq_ctrl_saved.irq_save_last_reg + 1
+				       + irq_ctrl_saved.irq_save_blink
+				       + irq_ctrl_saved.irq_save_lpcount
+				       + 1));
+
+  /* Build the stack adjustment note for unwind info.  */
+  j = 0;
+  offset = UNITS_PER_WORD * (irq_ctrl_saved.irq_save_last_reg + 1
+			     + irq_ctrl_saved.irq_save_blink
+			     + irq_ctrl_saved.irq_save_lpcount);
+  tmp = plus_constant (Pmode, stack_pointer_rtx, -1 * offset);
+  tmp = gen_rtx_SET (stack_pointer_rtx, tmp);
+  RTX_FRAME_RELATED_P (tmp) = 1;
+  XVECEXP (par, 0, j++) = tmp;
+
+  offset -= UNITS_PER_WORD;
+
+  /* 1st goes LP_COUNT.  */
+  if (irq_ctrl_saved.irq_save_lpcount)
+    {
+      reg = gen_rtx_REG (SImode, 60);
+      tmp = plus_constant (Pmode, stack_pointer_rtx, offset);
+      tmp = gen_frame_mem (SImode, tmp);
+      tmp = gen_rtx_SET (tmp, reg);
+      RTX_FRAME_RELATED_P (tmp) = 1;
+      XVECEXP (par, 0, j++) = tmp;
+      offset -= UNITS_PER_WORD;
+    }
+
+  /* 2nd goes BLINK.  */
+  if (irq_ctrl_saved.irq_save_blink)
+    {
+      reg = gen_rtx_REG (SImode, 31);
+      tmp = plus_constant (Pmode, stack_pointer_rtx, offset);
+      tmp = gen_frame_mem (SImode, tmp);
+      tmp = gen_rtx_SET (tmp, reg);
+      RTX_FRAME_RELATED_P (tmp) = 1;
+      XVECEXP (par, 0, j++) = tmp;
+      offset -= UNITS_PER_WORD;
+    }
+
+  /* Build the parallel of the remaining registers recorded as saved
+     for unwind.  */
+  for (i = irq_ctrl_saved.irq_save_last_reg; i >= 0; i--)
+    {
+      reg = gen_rtx_REG (SImode, i);
+      tmp = plus_constant (Pmode, stack_pointer_rtx, offset);
+      tmp = gen_frame_mem (SImode, tmp);
+      tmp = gen_rtx_SET (tmp, reg);
+      RTX_FRAME_RELATED_P (tmp) = 1;
+      XVECEXP (par, 0, j++) = tmp;
+      offset -= UNITS_PER_WORD;
+    }
+
+  /* Dummy insn used to anchor the dwarf info.  */
+  insn = emit_insn (gen_stack_irq_dwarf());
+  add_reg_note (insn, REG_FRAME_RELATED_EXPR, par);
+  RTX_FRAME_RELATED_P (insn) = 1;
+}
+
 /* Set up the stack and frame pointer (if desired) for the function.  */
 
 void
@@ -2654,6 +2894,7 @@ arc_expand_prologue (void)
      Change the stack layout so that we rather store a high register with the
      PRE_MODIFY, thus enabling more short insn generation.)  */
   int first_offset = 0;
+  enum arc_function_type fn_type = arc_compute_function_type (cfun);
 
   /* Compute total frame size.  */
   size = arc_compute_frame_size ();
@@ -2677,30 +2918,41 @@ arc_expand_prologue (void)
       frame_size_to_allocate -= cfun->machine->frame_info.pretend_size;
     }
 
+  /* IRQ using automatic save mechanism will save the register before
+     anything we do.  */
+  if (ARC_AUTO_IRQ_P (fn_type))
+    {
+      arc_dwarf_emit_irq_save_regs ();
+    }
+
   /* The home-grown ABI says link register is saved first.  */
-  if (MUST_SAVE_RETURN_ADDR)
+  if (arc_must_save_return_addr (cfun)
+      && !ARC_AUTOBLINK_IRQ_P (fn_type))
     {
       rtx ra = gen_rtx_REG (SImode, RETURN_ADDR_REGNUM);
-      rtx mem = gen_frame_mem (Pmode, gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx));
+      rtx mem = gen_frame_mem (Pmode,
+			       gen_rtx_PRE_DEC (Pmode,
+						stack_pointer_rtx));
 
       frame_move_inc (mem, ra, stack_pointer_rtx, 0);
       frame_size_to_allocate -= UNITS_PER_WORD;
-
-    } /* MUST_SAVE_RETURN_ADDR */
+    }
 
   /* Save any needed call-saved regs (and call-used if this is an
      interrupt handler) for ARCompact ISA.  */
   if (cfun->machine->frame_info.reg_size)
     {
       first_offset = -cfun->machine->frame_info.reg_size;
+
       /* N.B. FRAME_POINTER_MASK and RETURN_ADDR_MASK are cleared in gmask.  */
       arc_save_restore (stack_pointer_rtx, gmask, 0, &first_offset);
       frame_size_to_allocate -= cfun->machine->frame_info.reg_size;
     }
 
-
-  /* Save frame pointer if needed.  */
-  if (arc_frame_pointer_needed ())
+  /* Save frame pointer if needed.  First save the FP on stack, if not
+     autosaved.  */
+  if (arc_frame_pointer_needed ()
+      && !ARC_AUTOFP_IRQ_P (fn_type))
     {
       rtx addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
 			       GEN_INT (-UNITS_PER_WORD + first_offset));
@@ -2710,6 +2962,11 @@ arc_expand_prologue (void)
       frame_move_inc (mem, frame_pointer_rtx, stack_pointer_rtx, 0);
       frame_size_to_allocate -= UNITS_PER_WORD;
       first_offset = 0;
+    }
+
+  /* Emit mov fp,sp.  */
+  if (arc_frame_pointer_needed ())
+    {
       frame_move (frame_pointer_rtx, stack_pointer_rtx);
     }
 
@@ -2778,7 +3035,8 @@ arc_expand_epilogue (int sibcall_p)
 
 
   /* Restore any saved registers.  */
-  if (arc_frame_pointer_needed ())
+  if (arc_frame_pointer_needed ()
+      && !ARC_AUTOFP_IRQ_P (fn_type))
     {
       rtx addr = gen_rtx_POST_INC (Pmode, stack_pointer_rtx);
 
@@ -2816,14 +3074,15 @@ arc_expand_epilogue (int sibcall_p)
 	    : satisfies_constraint_C2a (GEN_INT (first_offset))))
        /* Also do this if we have both gprs and return
 	  address to restore, and they both would need a LIMM.  */
-       || (MUST_SAVE_RETURN_ADDR
-	   && !SMALL_INT ((cfun->machine->frame_info.reg_size + first_offset) >> 2)
-	   && cfun->machine->frame_info.gmask))
+      || (arc_must_save_return_addr (cfun)
+	  && !SMALL_INT ((cfun->machine->frame_info.reg_size + first_offset) >> 2)
+	  && cfun->machine->frame_info.gmask))
     {
       frame_stack_add (first_offset);
       first_offset = 0;
     }
-  if (MUST_SAVE_RETURN_ADDR)
+  if (arc_must_save_return_addr (cfun)
+      && !ARC_AUTOBLINK_IRQ_P (fn_type))
     {
       rtx ra = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
       int ra_offs = cfun->machine->frame_info.reg_size + first_offset;
@@ -2888,7 +3147,6 @@ arc_expand_epilogue (int sibcall_p)
 			   & ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK), 1, &first_offset);
     }
 
-
   /* The rest of this function does the following:
      ARCompact    : handle epilogue_delay, restore sp (phase-2), return
   */
diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md
index 42ea9a7..0f03170 100644
--- a/gcc/config/arc/arc.md
+++ b/gcc/config/arc/arc.md
@@ -6208,6 +6208,14 @@
   [(set (zero_extract:SI (match_dup 3) (match_dup 1) (match_dup 2))
 	(zero_extract:SI (match_dup 0) (match_dup 1) (match_dup 2)))])
 
+;; Dummy pattern used as a place holder for automatically saved
+;; registers.
+(define_insn "stack_irq_dwarf"
+  [(unspec_volatile [(const_int 1)] VUNSPEC_ARC_STACK_IRQ)]
+  ""
+  ""
+  [(set_attr "length" "0")])
+
 ;; include the arc-FPX instructions
 (include "fpx.md")
 
diff --git a/gcc/config/arc/arc.opt b/gcc/config/arc/arc.opt
index 6060ded..483470d 100644
--- a/gcc/config/arc/arc.opt
+++ b/gcc/config/arc/arc.opt
@@ -486,3 +486,7 @@ Enable use of NPS400 xld/xst extension.
 munaligned-access
 Target Report Var(unaligned_access) Init(UNALIGNED_ACCESS_DEFAULT)
 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.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 0eeea7b..cebafe6 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -606,7 +606,7 @@ 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 @gol
+-mlong-calls  -mmedium-calls  -msdata -mirq-ctrl-saved @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
@@ -14578,6 +14578,15 @@ hardware extensions.  Not available for ARC EM@.
 
 @end table
 
+@item -mirq-ctrl-saved="REGS"
+@opindex mirq-ctrl-saved
+Specifies gneral-purposes registers that the processor saves/restores
+on interrupt entry and exit.  Permited values: r0-r29, fp, blink, and
+lp_count.  Registers needs to be specified as ranges such as "r0-r3".
+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.
+
 @end table
 
 The following options are passed through to the assembler, and also
diff --git a/gcc/testsuite/gcc.target/arc/interrupt-5.c b/gcc/testsuite/gcc.target/arc/interrupt-5.c
new file mode 100644
index 0000000..ee01d76
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/interrupt-5.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-skip-if "Not available for ARCv1" { arc700 ||  arc6xx } } */
+/* { dg-options "-O2 -mirq-ctrl-saved=r0-r3,blink" } */
+
+/* Check if the registers R0-R3,blink are automatically saved. */
+
+extern int bar (void *);
+
+void  __attribute__ ((interrupt("ilink")))
+foo(void)
+{
+  bar (0);
+  __asm__ volatile ( "" : : : "r0","r1","r2","r3");
+}
+/* { dg-final { scan-assembler-not "st.*r0,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r1,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r2,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r3,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "push_s blink" } } */
diff --git a/gcc/testsuite/gcc.target/arc/interrupt-6.c b/gcc/testsuite/gcc.target/arc/interrupt-6.c
new file mode 100644
index 0000000..509ff30
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/interrupt-6.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-skip-if "Not available for ARCv1" { arc700 || arc6xx } } */
+/* { dg-options "-O2 -mirq-ctrl-saved=r0-ilink" } */
+
+#include <alloca.h>
+
+/* Check if ilink is recognized. Check how FP and BLINK are saved.
+   BLINK is saved last on the stack because the IRQ autosave will do
+   first r0-ilink.  To avoid this ABI exception, one needs to autosave
+   always blink when using the IRQ autosave feature.  */
+
+extern int bar (void *);
+
+void  __attribute__ ((interrupt("ilink")))
+foo(void)
+{
+  int *p = alloca (10);
+  bar (p);
+}
+/* { dg-final { scan-assembler-not ".*fp,\\\[sp" } } */
+/* { dg-final { scan-assembler "ld.*blink,\\\[sp\\\]" } } */
+/* { dg-final { scan-assembler "push_s.*blink" } } */
diff --git a/gcc/testsuite/gcc.target/arc/interrupt-7.c b/gcc/testsuite/gcc.target/arc/interrupt-7.c
new file mode 100644
index 0000000..547dfd3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/interrupt-7.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-skip-if "Not available for ARCv1" { arc700 ||  arc6xx } } */
+/* { dg-options "-O2 -mirq-ctrl-saved=r0-r17,blink" } */
+
+/* Check if the registers R0-R17,blink are automatically saved. */
+
+void  __attribute__ ((interrupt("ilink")))
+foo(void)
+{
+  __asm__ volatile ( "" : : : "r13","r14","r15","r16");
+}
+/* { dg-final { scan-assembler-not "st.*r13,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r14,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r15,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r16,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "push_s blink" } } */
diff --git a/gcc/testsuite/gcc.target/arc/interrupt-8.c b/gcc/testsuite/gcc.target/arc/interrupt-8.c
new file mode 100644
index 0000000..60fd87b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/interrupt-8.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-skip-if "Not available for ARCv1" { arc700 || arc6xx } } */
+/* { dg-options "-O2 -mirq-ctrl-saved=r0-r17" } */
+
+/* Check if the registers R0-R17 are automatically saved.  GP is saved
+   by the compiler.  */
+
+int a;
+
+void  __attribute__ ((interrupt("ilink")))
+foo(void)
+{
+  __asm__ volatile ( "" : : : "r0","r1","r2","r3");
+  __asm__ volatile ( "" : : : "r13","r14","r15","r16");
+  a++;
+}
+/* { dg-final { scan-assembler-not "st.*r13,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r14,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r15,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r16,\\\[sp" } } */
+/* { dg-final { scan-assembler "st.*gp,\\\[sp,-4\\\]" } } */
+/* { dg-final { scan-assembler "ld.*gp,\\\[sp\\\]" } } */
+/* { dg-final { scan-assembler-not "st.*r0,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r1,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r2,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r3,\\\[sp" } } */
+/* { dg-final { scan-assembler "rtie" } } */
diff --git a/gcc/testsuite/gcc.target/arc/interrupt-9.c b/gcc/testsuite/gcc.target/arc/interrupt-9.c
new file mode 100644
index 0000000..4547fef
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/interrupt-9.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target archs }*/
+/* { dg-options "-O0 -mirq-ctrl-saved=r0-fp" } */
+
+/* Check if we get the move operation between fp and sp.  */
+
+void __attribute__ ((interrupt("ilink")))
+handler1 (void)
+{
+  asm (""
+       :
+       :
+       : "r0", "r1", "r2", "r3", "r4",
+         "r5", "r6", "r7", "r8", "r9");
+}
+/* { dg-final { scan-assembler "mov.*fp,sp" } } */
+/* { dg-final { scan-assembler-not ".*fp,\\\[sp" } } */
-- 
1.9.1

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 1/3] [ARC] Automatic context save/restore for regular interrupts.
  2017-04-25 13:29 ` [PATCH 1/3] [ARC] Automatic context save/restore for regular interrupts Claudiu Zissulescu
@ 2017-04-25 15:46   ` Sandra Loosemore
  2017-04-26 13:15     ` Claudiu Zissulescu
  2017-05-05 11:05     ` [PATCH 0/2] [ARC] New features (updated) Claudiu Zissulescu
  0 siblings, 2 replies; 17+ messages in thread
From: Sandra Loosemore @ 2017-04-25 15:46 UTC (permalink / raw)
  To: Claudiu Zissulescu, gcc-patches; +Cc: Francois.Bedard, andrew.burgess

On 04/25/2017 07:03 AM, Claudiu Zissulescu wrote:
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 0eeea7b..cebafe6 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -606,7 +606,7 @@ 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 @gol
> +-mlong-calls  -mmedium-calls  -msdata -mirq-ctrl-saved @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
> @@ -14578,6 +14578,15 @@ hardware extensions.  Not available for ARC EM@.
>
>   @end table
>
> +@item -mirq-ctrl-saved="REGS"

Use @var{regs} instead of REGS.  I assume the quotes are part of the 
literal syntax?

> +@opindex mirq-ctrl-saved
> +Specifies gneral-purposes registers that the processor saves/restores

s/gneral-purposes/general-purpose/

> +on interrupt entry and exit.  Permited values: r0-r29, fp, blink, and

s/Permited/Permissible/

I think literal strings that are part of the option syntax should have 
@samp markup.

> +lp_count.  Registers needs to be specified as ranges such as "r0-r3".
> +A register range always starts with r0.  Registers blink and lp_count
> +can be specified individually.

You're contradicting yourself here:  you say that registers need to be 
specified as ranges, and then you say that some registers can be 
specified individually.  Can you come up with a better explanation of 
the syntax?  E.g., is it possible to specify multiple registers without 
using a range?  Or do you specify the option multiple times in that case?

> +Only valid for ARC EM and ARC HS
> +cores.
> +

I suggest a paragraph break here, or at least specify "This option is 
only valid...." so it's clear what the subject of this sentence is.

-Sandra

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/3] [ARC] Fast interrupts support.
  2017-04-25 13:27 ` [PATCH 2/3] [ARC] Fast interrupts support Claudiu Zissulescu
@ 2017-04-25 15:54   ` Sandra Loosemore
  2017-04-26 13:14     ` Claudiu Zissulescu
  0 siblings, 1 reply; 17+ messages in thread
From: Sandra Loosemore @ 2017-04-25 15:54 UTC (permalink / raw)
  To: Claudiu Zissulescu, gcc-patches; +Cc: Francois.Bedard, andrew.burgess

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


^ permalink raw reply	[flat|nested] 17+ messages in thread

* RE: [PATCH 2/3] [ARC] Fast interrupts support.
  2017-04-25 15:54   ` Sandra Loosemore
@ 2017-04-26 13:14     ` Claudiu Zissulescu
  0 siblings, 0 replies; 17+ messages in thread
From: Claudiu Zissulescu @ 2017-04-26 13:14 UTC (permalink / raw)
  To: Sandra Loosemore, gcc-patches; +Cc: Francois.Bedard, andrew.burgess

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
> 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* RE: [PATCH 1/3] [ARC] Automatic context save/restore for regular interrupts.
  2017-04-25 15:46   ` Sandra Loosemore
@ 2017-04-26 13:15     ` Claudiu Zissulescu
  2017-05-05 11:05     ` [PATCH 0/2] [ARC] New features (updated) Claudiu Zissulescu
  1 sibling, 0 replies; 17+ messages in thread
From: Claudiu Zissulescu @ 2017-04-26 13:15 UTC (permalink / raw)
  To: Sandra Loosemore, gcc-patches; +Cc: Francois.Bedard, andrew.burgess

> > +@item -mirq-ctrl-saved="REGS"
> 
> Use @var{regs} instead of REGS.  I assume the quotes are part of the
> literal syntax?

In fact here we should have a register range (e.g., -mirq-ctrl-saved=r0-r9).

> > +lp_count.  Registers needs to be specified as ranges such as "r0-r3".
> > +A register range always starts with r0.  Registers blink and lp_count
> > +can be specified individually.
> 
> You're contradicting yourself here:  you say that registers need to be
> specified as ranges, and then you say that some registers can be
> specified individually.  Can you come up with a better explanation of
> the syntax?  E.g., is it possible to specify multiple registers without
> using a range?  Or do you specify the option multiple times in that case?
> 

Blink (r31) and lp_count (r60) are special registers. The range can go from r0 up to r29.  Thus, the option is a sequence made of a register range starting with r0 to r29, and optional two individual registers: blink (r31) and lp_count (r60). Hence, such an option looks like this:
	-mirq-ctrl-saved=r0-r29,blink,lp_count


Thanks,
Claudiu

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/2] Automatic context save/restore for regular interrupts.
  2017-05-05 11:05     ` [PATCH 0/2] [ARC] New features (updated) Claudiu Zissulescu
@ 2017-05-05 11:05       ` Claudiu Zissulescu
  2017-05-08 14:50         ` Andrew Burgess
  2017-05-05 11:23       ` [PATCH 2/2] Fast interrupts support Claudiu Zissulescu
  1 sibling, 1 reply; 17+ messages in thread
From: Claudiu Zissulescu @ 2017-05-05 11:05 UTC (permalink / raw)
  To: gcc-patches; +Cc: Claudiu.Zissulescu, Francois.Bedard, andrew.burgess, sandra

The AUX_IRQ_CTRL register controls the behavior of automated register
save and restore or prologue and epilogue sequences during a non-fast
interrupt entry and exit, and context save and restore instructions.

A user passes to the compiler the configuration of the AUX_IRQ_CTRL
register via mirq-ctrl-saved option.  This option, specifies
gneral-purposes registers that the processor saves/restores on
interrupt entry and exit, and it is only valid for ARC EM and ARC HS
cores.

gcc/
2017-05-05  Claudiu Zissulescu  <claziss@synopsys.com>

	* config/arc/arc.c (irq_ctrl_saved): New variable.
	(ARC_AUTOBLINK_IRQ_P): Define.
	(ARC_AUTOFP_IRQ_P): Likewise.
	(ARC_AUTO_IRQ_P): Likewise.
	(irq_range): New function.
	(arc_must_save_register): Likewise.
	(arc_must_save_return_addr): Likewise.
	(arc_dwarf_emit_irq_save_regs): Likewise.
	(arc_override_options): Handle deferred options.
	(MUST_SAVE_REGISTER): Deleted, replaced by arc_must_save_register.
	(MUST_SAVE_RETURN_ADDR): Deleted, replaced by
	arc_must_save_return_addr.
	(arc_compute_frame_size): Handle automated save and restore of
	registers.
	(arc_expand_prologue): Likewise.
	(arc_expand_epilogue): Likewise.
	* config/arc/arc.md (stack_irq_dwarf): New unspec instruction.
	* config/arc/arc.opt (mirq-ctrl-saved): New option.
	* doc/invoke.texi (mirq-ctrl-saved): Document option.
	* testsuite/gcc.target/arc/interrupt-5.c: Newfile.
	* testsuite/gcc.target/arc/interrupt-6.c: Likewise.
	* testsuite/gcc.target/arc/interrupt-7.c: Likewise.
	* testsuite/gcc.target/arc/interrupt-8.c: Likewise.
	* testsuite/gcc.target/arc/interrupt-9.c: Likewise.
---
 gcc/config/arc/arc.c                       | 329 ++++++++++++++++++++++++++---
 gcc/config/arc/arc.md                      |   8 +
 gcc/config/arc/arc.opt                     |   4 +
 gcc/doc/invoke.texi                        |  11 +-
 gcc/testsuite/gcc.target/arc/interrupt-5.c |  19 ++
 gcc/testsuite/gcc.target/arc/interrupt-6.c |  22 ++
 gcc/testsuite/gcc.target/arc/interrupt-7.c |  16 ++
 gcc/testsuite/gcc.target/arc/interrupt-8.c |  27 +++
 gcc/testsuite/gcc.target/arc/interrupt-9.c |  17 ++
 9 files changed, 421 insertions(+), 32 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-5.c
 create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-6.c
 create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-7.c
 create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-8.c
 create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-9.c

diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
index 4574481..a61faef 100644
--- a/gcc/config/arc/arc.c
+++ b/gcc/config/arc/arc.c
@@ -63,6 +63,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "rtl-iter.h"
 #include "alias.h"
+#include "opts.h"
 
 /* Which cpu we're compiling for (ARC600, ARC601, ARC700).  */
 static char arc_cpu_name[10] = "";
@@ -111,6 +112,29 @@ struct GTY (()) arc_ccfsm
   int target_label;
 };
 
+/* Status of the IRQ_CTRL_AUX register.  */
+typedef struct irq_ctrl_saved_t
+{
+  short irq_save_last_reg;      /* Last register number used by
+				   IRQ_CTRL_SAVED aux_reg.  */
+  bool  irq_save_blink;         /* True if BLINK is automatically
+				   saved.  */
+  bool  irq_save_lpcount;       /* True if LPCOUNT is automatically
+				   saved.  */
+} 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			\
+       || (irq_ctrl_saved.irq_save_last_reg >= 0)))
+
 #define arc_ccfsm_current cfun->machine->ccfsm_current
 
 #define ARC_CCFSM_BRANCH_DELETED_P(STATE) \
@@ -806,11 +830,110 @@ arc_init (void)
     }
 }
 
+/* Parse -mirq-ctrl-saved= option string.  Registers may be specified
+   individually, or as ranges such as "r0-r3".  Registers accepted are
+   r0 through r31 and lp_count.  Registers and ranges must be
+   comma-separated.  */
+
+static void
+irq_range (const char *cstr)
+{
+  int i, first, last, blink, lpcount, xreg;
+  char *str, *dash, *comma;
+
+  i = strlen (cstr);
+  str = (char *) alloca (i + 1);
+  memcpy (str, cstr, i + 1);
+  blink = -1;
+  lpcount = -1;
+
+  dash = strchr (str, '-');
+  if (!dash)
+    {
+      warning (0, "value of -mirq-ctrl-saved must have form R0-REGx");
+      return;
+    }
+  *dash = '\0';
+
+  comma = strchr (dash + 1, ',');
+  if (comma)
+    *comma = '\0';
+
+  first = decode_reg_name (str);
+  if (first != 0)
+    {
+      warning (0, "first register must be R0");
+      return;
+    }
+
+  /* At this moment we do not have the register names initialized
+     accordingly.  */
+  if (!strcmp (dash + 1, "ilink"))
+    last = 29;
+  else
+    last = decode_reg_name (dash + 1);
+
+  if (last < 0)
+    {
+      warning (0, "unknown register name: %s", dash + 1);
+      return;
+    }
+
+  if (!(last & 0x01))
+    {
+      warning (0, "last register name %s must be an odd register", dash + 1);
+      return;
+    }
+
+  *dash = '-';
+
+  if (first > last)
+    {
+      warning (0, "%s-%s is an empty range", str, dash + 1);
+      return;
+    }
+
+  while (comma)
+    {
+      *comma = ',';
+      str = comma + 1;
+
+      comma = strchr (str, ',');
+      if (comma)
+	*comma = '\0';
+
+      xreg = decode_reg_name (str);
+      switch (xreg)
+	{
+	case 31:
+	  blink = 31;
+	  break;
+
+	case 60:
+	  lpcount = 60;
+	  break;
+
+	default:
+	  warning (0, "unknown register name: %s", str);
+	  return;
+	}
+    }
+
+  irq_ctrl_saved.irq_save_last_reg = last;
+  irq_ctrl_saved.irq_save_blink    = (blink == 31) || (last == 31);
+  irq_ctrl_saved.irq_save_lpcount  = (lpcount == 60);
+}
+
 /* Check ARC options, generate derived target attributes.  */
 
 static void
 arc_override_options (void)
 {
+  unsigned int i;
+  cl_deferred_option *opt;
+  vec<cl_deferred_option> *vopt
+    = (vec<cl_deferred_option> *) arc_deferred_options;
+
   if (arc_cpu == PROCESSOR_NONE)
     arc_cpu = TARGET_CPU_DEFAULT;
 
@@ -839,6 +962,28 @@ arc_override_options (void)
       gcc_unreachable ();
     }
 
+  irq_ctrl_saved.irq_save_last_reg = -1;
+  irq_ctrl_saved.irq_save_blink    = false;
+  irq_ctrl_saved.irq_save_lpcount  = false;
+
+  /* Handle the deferred options.  */
+  if (vopt)
+    FOR_EACH_VEC_ELT (*vopt, i, opt)
+      {
+	switch (opt->opt_index)
+	  {
+	  case OPT_mirq_ctrl_saved_:
+	    if (TARGET_V2)
+	      irq_range (opt->arg);
+	    else
+	      warning (0, "option -mirq-ctrl-saved valid only for ARC v2 processors");
+	    break;
+
+	  default:
+	    gcc_unreachable();
+	  }
+      }
+
   /* Set cpu flags accordingly to architecture/selected cpu.  The cpu
      specific flags are set in arc-common.c.  The architecture forces
      the default hardware configurations in, regardless what command
@@ -2235,14 +2380,52 @@ arc_compute_function_type (struct function *fun)
    FIXME: This will not be needed if we used some arbitrary register
    instead of r26.
 */
-#define MUST_SAVE_REGISTER(regno, interrupt_p) \
-(((regno) != RETURN_ADDR_REGNUM && (regno) != FRAME_POINTER_REGNUM \
-  && (df_regs_ever_live_p (regno) && (!call_used_regs[regno] || interrupt_p))) \
- || (flag_pic && crtl->uses_pic_offset_table \
-     && regno == PIC_OFFSET_TABLE_REGNUM) )
 
-#define MUST_SAVE_RETURN_ADDR \
-  (cfun->machine->frame_info.save_return_addr)
+static bool
+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));
+
+  if ((regno) != RETURN_ADDR_REGNUM
+      && (regno) != FRAME_POINTER_REGNUM
+      && df_regs_ever_live_p (regno)
+      && (!call_used_regs[regno]
+	  || ARC_INTERRUPT_P (fn_type))
+      /* Do not emit code for auto saved regs.  */
+      && !irq_auto_save_p)
+    return true;
+
+  if (flag_pic && crtl->uses_pic_offset_table
+      && regno == PIC_OFFSET_TABLE_REGNUM)
+    return true;
+
+  return false;
+}
+
+/* Return true if the return address must be saved in the current function,
+   otherwise return false.  */
+
+static bool
+arc_must_save_return_addr (struct function *func)
+{
+  if (func->machine->frame_info.save_return_addr)
+    return true;
+
+  return false;
+}
+
+/* Helper function to wrap FRAME_POINTER_NEEDED.  We do this as
+   FRAME_POINTER_NEEDED will not be true until the IRA (Integrated
+   Register Allocator) pass, while we want to get the frame size
+   correct earlier than the IRA pass.  */
+static bool
+arc_frame_pointer_needed (void)
+{
+  return (frame_pointer_needed);
+}
+
 
 /* Return non-zero if there are registers to be saved or loaded using
    millicode thunks.  We can only use consecutive sequences starting
@@ -2286,8 +2469,6 @@ arc_compute_frame_size (int size)	/* size = # of var. bytes allocated.  */
   unsigned int total_size, var_size, args_size, pretend_size, extra_size;
   unsigned int reg_size, reg_offset;
   unsigned int gmask;
-  enum arc_function_type fn_type;
-  int interrupt_p;
   struct arc_frame_info *frame_info = &cfun->machine->frame_info;
 
   size = ARC_STACK_ALIGN (size);
@@ -2306,15 +2487,13 @@ arc_compute_frame_size (int size)	/* size = # of var. bytes allocated.  */
 
   reg_size = 0;
   gmask = 0;
-  fn_type = arc_compute_function_type (cfun);
-  interrupt_p = ARC_INTERRUPT_P (fn_type);
 
   for (regno = 0; regno <= 31; regno++)
     {
-      if (MUST_SAVE_REGISTER (regno, interrupt_p))
+      if (arc_must_save_register (regno, cfun))
 	{
 	  reg_size += UNITS_PER_WORD;
-	  gmask |= 1 << regno;
+	  gmask |= 1L << regno;
 	}
     }
 
@@ -2330,9 +2509,9 @@ arc_compute_frame_size (int size)	/* size = # of var. bytes allocated.  */
     }
 
   extra_size = 0;
-  if (MUST_SAVE_RETURN_ADDR)
+  if (arc_must_save_return_addr (cfun))
     extra_size = 4;
-  if (frame_pointer_needed)
+  if (arc_frame_pointer_needed ())
     extra_size += 4;
 
   /* 5) Space for variable arguments passed in registers */
@@ -2357,7 +2536,7 @@ arc_compute_frame_size (int size)	/* size = # of var. bytes allocated.  */
      Frame: pretend_size <blink> reg_size <fp> var_size args_size <--sp
   */
   reg_offset = (total_size - (pretend_size + reg_size + extra_size)
-		+ (frame_pointer_needed ? 4 : 0));
+		+ (arc_frame_pointer_needed () ? 4 : 0));
 
   /* Save computed information.  */
   frame_info->total_size   = total_size;
@@ -2548,6 +2727,77 @@ arc_save_restore (rtx base_reg,
 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.  */
+
+static void
+arc_dwarf_emit_irq_save_regs (void)
+{
+  rtx tmp, par, insn, reg;
+  int i, offset, j;
+
+  par = gen_rtx_SEQUENCE (VOIDmode,
+			  rtvec_alloc (irq_ctrl_saved.irq_save_last_reg + 1
+				       + irq_ctrl_saved.irq_save_blink
+				       + irq_ctrl_saved.irq_save_lpcount
+				       + 1));
+
+  /* Build the stack adjustment note for unwind info.  */
+  j = 0;
+  offset = UNITS_PER_WORD * (irq_ctrl_saved.irq_save_last_reg + 1
+			     + irq_ctrl_saved.irq_save_blink
+			     + irq_ctrl_saved.irq_save_lpcount);
+  tmp = plus_constant (Pmode, stack_pointer_rtx, -1 * offset);
+  tmp = gen_rtx_SET (stack_pointer_rtx, tmp);
+  RTX_FRAME_RELATED_P (tmp) = 1;
+  XVECEXP (par, 0, j++) = tmp;
+
+  offset -= UNITS_PER_WORD;
+
+  /* 1st goes LP_COUNT.  */
+  if (irq_ctrl_saved.irq_save_lpcount)
+    {
+      reg = gen_rtx_REG (SImode, 60);
+      tmp = plus_constant (Pmode, stack_pointer_rtx, offset);
+      tmp = gen_frame_mem (SImode, tmp);
+      tmp = gen_rtx_SET (tmp, reg);
+      RTX_FRAME_RELATED_P (tmp) = 1;
+      XVECEXP (par, 0, j++) = tmp;
+      offset -= UNITS_PER_WORD;
+    }
+
+  /* 2nd goes BLINK.  */
+  if (irq_ctrl_saved.irq_save_blink)
+    {
+      reg = gen_rtx_REG (SImode, 31);
+      tmp = plus_constant (Pmode, stack_pointer_rtx, offset);
+      tmp = gen_frame_mem (SImode, tmp);
+      tmp = gen_rtx_SET (tmp, reg);
+      RTX_FRAME_RELATED_P (tmp) = 1;
+      XVECEXP (par, 0, j++) = tmp;
+      offset -= UNITS_PER_WORD;
+    }
+
+  /* Build the parallel of the remaining registers recorded as saved
+     for unwind.  */
+  for (i = irq_ctrl_saved.irq_save_last_reg; i >= 0; i--)
+    {
+      reg = gen_rtx_REG (SImode, i);
+      tmp = plus_constant (Pmode, stack_pointer_rtx, offset);
+      tmp = gen_frame_mem (SImode, tmp);
+      tmp = gen_rtx_SET (tmp, reg);
+      RTX_FRAME_RELATED_P (tmp) = 1;
+      XVECEXP (par, 0, j++) = tmp;
+      offset -= UNITS_PER_WORD;
+    }
+
+  /* Dummy insn used to anchor the dwarf info.  */
+  insn = emit_insn (gen_stack_irq_dwarf());
+  add_reg_note (insn, REG_FRAME_RELATED_EXPR, par);
+  RTX_FRAME_RELATED_P (insn) = 1;
+}
+
 /* Set up the stack and frame pointer (if desired) for the function.  */
 
 void
@@ -2561,6 +2811,7 @@ arc_expand_prologue (void)
      Change the stack layout so that we rather store a high register with the
      PRE_MODIFY, thus enabling more short insn generation.)  */
   int first_offset = 0;
+  enum arc_function_type fn_type = arc_compute_function_type (cfun);
 
   size = ARC_STACK_ALIGN (size);
 
@@ -2588,16 +2839,25 @@ arc_expand_prologue (void)
       frame_size_to_allocate -= cfun->machine->frame_info.pretend_size;
     }
 
+  /* IRQ using automatic save mechanism will save the register before
+     anything we do.  */
+  if (ARC_AUTO_IRQ_P (fn_type))
+    {
+      arc_dwarf_emit_irq_save_regs ();
+    }
+
   /* The home-grown ABI says link register is saved first.  */
-  if (MUST_SAVE_RETURN_ADDR)
+  if (arc_must_save_return_addr (cfun)
+      && !ARC_AUTOBLINK_IRQ_P (fn_type))
     {
       rtx ra = gen_rtx_REG (SImode, RETURN_ADDR_REGNUM);
-      rtx mem = gen_frame_mem (Pmode, gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx));
+      rtx mem = gen_frame_mem (Pmode,
+			       gen_rtx_PRE_DEC (Pmode,
+						stack_pointer_rtx));
 
       frame_move_inc (mem, ra, stack_pointer_rtx, 0);
       frame_size_to_allocate -= UNITS_PER_WORD;
-
-    } /* MUST_SAVE_RETURN_ADDR */
+    }
 
   /* Save any needed call-saved regs (and call-used if this is an
      interrupt handler) for ARCompact ISA.  */
@@ -2609,9 +2869,10 @@ arc_expand_prologue (void)
       frame_size_to_allocate -= cfun->machine->frame_info.reg_size;
     }
 
-
-  /* Save frame pointer if needed.  */
-  if (frame_pointer_needed)
+  /* Save frame pointer if needed.  First save the FP on stack, if not
+     autosaved.  */
+  if (arc_frame_pointer_needed ()
+      && !ARC_AUTOFP_IRQ_P (fn_type))
     {
       rtx addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
 			       GEN_INT (-UNITS_PER_WORD + first_offset));
@@ -2621,6 +2882,11 @@ arc_expand_prologue (void)
       frame_move_inc (mem, frame_pointer_rtx, stack_pointer_rtx, 0);
       frame_size_to_allocate -= UNITS_PER_WORD;
       first_offset = 0;
+    }
+
+  /* Emit mov fp,sp.  */
+  if (arc_frame_pointer_needed ())
+    {
       frame_move (frame_pointer_rtx, stack_pointer_rtx);
     }
 
@@ -2675,13 +2941,13 @@ arc_expand_epilogue (int sibcall_p)
      sp, but don't restore sp if we don't have to.  */
 
   if (!can_trust_sp_p)
-    gcc_assert (frame_pointer_needed);
+    gcc_assert (arc_frame_pointer_needed ());
 
   /* Restore stack pointer to the beginning of saved register area for
      ARCompact ISA.  */
   if (frame_size)
     {
-      if (frame_pointer_needed)
+      if (arc_frame_pointer_needed ())
 	frame_move (stack_pointer_rtx, frame_pointer_rtx);
       else
 	first_offset = frame_size;
@@ -2692,7 +2958,8 @@ arc_expand_epilogue (int sibcall_p)
 
 
   /* Restore any saved registers.  */
-  if (frame_pointer_needed)
+  if (arc_frame_pointer_needed ()
+      && !ARC_AUTOFP_IRQ_P (fn_type))
     {
       rtx addr = gen_rtx_POST_INC (Pmode, stack_pointer_rtx);
 
@@ -2730,14 +2997,15 @@ arc_expand_epilogue (int sibcall_p)
 	    : satisfies_constraint_C2a (GEN_INT (first_offset))))
        /* Also do this if we have both gprs and return
 	  address to restore, and they both would need a LIMM.  */
-       || (MUST_SAVE_RETURN_ADDR
-	   && !SMALL_INT ((cfun->machine->frame_info.reg_size + first_offset) >> 2)
-	   && cfun->machine->frame_info.gmask))
+      || (arc_must_save_return_addr (cfun)
+	  && !SMALL_INT ((cfun->machine->frame_info.reg_size + first_offset) >> 2)
+	  && cfun->machine->frame_info.gmask))
     {
       frame_stack_add (first_offset);
       first_offset = 0;
     }
-  if (MUST_SAVE_RETURN_ADDR)
+  if (arc_must_save_return_addr (cfun)
+      && !ARC_AUTOBLINK_IRQ_P (fn_type))
     {
       rtx ra = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
       int ra_offs = cfun->machine->frame_info.reg_size + first_offset;
@@ -2802,7 +3070,6 @@ arc_expand_epilogue (int sibcall_p)
 			   & ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK), 1, &first_offset);
     }
 
-
   /* The rest of this function does the following:
      ARCompact    : handle epilogue_delay, restore sp (phase-2), return
   */
diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md
index 802c3e9..2221fb5 100644
--- a/gcc/config/arc/arc.md
+++ b/gcc/config/arc/arc.md
@@ -6241,6 +6241,14 @@
   [(set (zero_extract:SI (match_dup 3) (match_dup 1) (match_dup 2))
 	(zero_extract:SI (match_dup 0) (match_dup 1) (match_dup 2)))])
 
+;; Dummy pattern used as a place holder for automatically saved
+;; registers.
+(define_insn "stack_irq_dwarf"
+  [(unspec_volatile [(const_int 1)] VUNSPEC_ARC_STACK_IRQ)]
+  ""
+  ""
+  [(set_attr "length" "0")])
+
 ;; include the arc-FPX instructions
 (include "fpx.md")
 
diff --git a/gcc/config/arc/arc.opt b/gcc/config/arc/arc.opt
index 6060ded..483470d 100644
--- a/gcc/config/arc/arc.opt
+++ b/gcc/config/arc/arc.opt
@@ -486,3 +486,7 @@ Enable use of NPS400 xld/xst extension.
 munaligned-access
 Target Report Var(unaligned_access) Init(UNALIGNED_ACCESS_DEFAULT)
 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.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 68a558e..bd3b339 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -606,7 +606,7 @@ 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 @gol
+-mlong-calls  -mmedium-calls  -msdata -mirq-ctrl-saved @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
@@ -14545,6 +14545,15 @@ hardware extensions.  Not available for ARC EM@.
 
 @end table
 
+@item -mirq-ctrl-saved=@var{register-range}, @var{blink}, @var{lp_count}
+@opindex mirq-ctrl-saved
+Specifies general-purposes registers that the processor automatically
+saves/restores on interrupt entry and exit.  @var{register-range} is
+specified as two registers separated by a dash.  The register range
+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.
+
 @end table
 
 The following options are passed through to the assembler, and also
diff --git a/gcc/testsuite/gcc.target/arc/interrupt-5.c b/gcc/testsuite/gcc.target/arc/interrupt-5.c
new file mode 100644
index 0000000..ee01d76
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/interrupt-5.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-skip-if "Not available for ARCv1" { arc700 ||  arc6xx } } */
+/* { dg-options "-O2 -mirq-ctrl-saved=r0-r3,blink" } */
+
+/* Check if the registers R0-R3,blink are automatically saved. */
+
+extern int bar (void *);
+
+void  __attribute__ ((interrupt("ilink")))
+foo(void)
+{
+  bar (0);
+  __asm__ volatile ( "" : : : "r0","r1","r2","r3");
+}
+/* { dg-final { scan-assembler-not "st.*r0,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r1,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r2,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r3,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "push_s blink" } } */
diff --git a/gcc/testsuite/gcc.target/arc/interrupt-6.c b/gcc/testsuite/gcc.target/arc/interrupt-6.c
new file mode 100644
index 0000000..509ff30
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/interrupt-6.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-skip-if "Not available for ARCv1" { arc700 || arc6xx } } */
+/* { dg-options "-O2 -mirq-ctrl-saved=r0-ilink" } */
+
+#include <alloca.h>
+
+/* Check if ilink is recognized. Check how FP and BLINK are saved.
+   BLINK is saved last on the stack because the IRQ autosave will do
+   first r0-ilink.  To avoid this ABI exception, one needs to autosave
+   always blink when using the IRQ autosave feature.  */
+
+extern int bar (void *);
+
+void  __attribute__ ((interrupt("ilink")))
+foo(void)
+{
+  int *p = alloca (10);
+  bar (p);
+}
+/* { dg-final { scan-assembler-not ".*fp,\\\[sp" } } */
+/* { dg-final { scan-assembler "ld.*blink,\\\[sp\\\]" } } */
+/* { dg-final { scan-assembler "push_s.*blink" } } */
diff --git a/gcc/testsuite/gcc.target/arc/interrupt-7.c b/gcc/testsuite/gcc.target/arc/interrupt-7.c
new file mode 100644
index 0000000..547dfd3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/interrupt-7.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-skip-if "Not available for ARCv1" { arc700 ||  arc6xx } } */
+/* { dg-options "-O2 -mirq-ctrl-saved=r0-r17,blink" } */
+
+/* Check if the registers R0-R17,blink are automatically saved. */
+
+void  __attribute__ ((interrupt("ilink")))
+foo(void)
+{
+  __asm__ volatile ( "" : : : "r13","r14","r15","r16");
+}
+/* { dg-final { scan-assembler-not "st.*r13,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r14,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r15,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r16,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "push_s blink" } } */
diff --git a/gcc/testsuite/gcc.target/arc/interrupt-8.c b/gcc/testsuite/gcc.target/arc/interrupt-8.c
new file mode 100644
index 0000000..60fd87b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/interrupt-8.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-skip-if "Not available for ARCv1" { arc700 || arc6xx } } */
+/* { dg-options "-O2 -mirq-ctrl-saved=r0-r17" } */
+
+/* Check if the registers R0-R17 are automatically saved.  GP is saved
+   by the compiler.  */
+
+int a;
+
+void  __attribute__ ((interrupt("ilink")))
+foo(void)
+{
+  __asm__ volatile ( "" : : : "r0","r1","r2","r3");
+  __asm__ volatile ( "" : : : "r13","r14","r15","r16");
+  a++;
+}
+/* { dg-final { scan-assembler-not "st.*r13,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r14,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r15,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r16,\\\[sp" } } */
+/* { dg-final { scan-assembler "st.*gp,\\\[sp,-4\\\]" } } */
+/* { dg-final { scan-assembler "ld.*gp,\\\[sp\\\]" } } */
+/* { dg-final { scan-assembler-not "st.*r0,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r1,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r2,\\\[sp" } } */
+/* { dg-final { scan-assembler-not "st.*r3,\\\[sp" } } */
+/* { dg-final { scan-assembler "rtie" } } */
diff --git a/gcc/testsuite/gcc.target/arc/interrupt-9.c b/gcc/testsuite/gcc.target/arc/interrupt-9.c
new file mode 100644
index 0000000..4547fef
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/interrupt-9.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target archs }*/
+/* { dg-options "-O0 -mirq-ctrl-saved=r0-fp" } */
+
+/* Check if we get the move operation between fp and sp.  */
+
+void __attribute__ ((interrupt("ilink")))
+handler1 (void)
+{
+  asm (""
+       :
+       :
+       : "r0", "r1", "r2", "r3", "r4",
+         "r5", "r6", "r7", "r8", "r9");
+}
+/* { dg-final { scan-assembler "mov.*fp,sp" } } */
+/* { dg-final { scan-assembler-not ".*fp,\\\[sp" } } */
-- 
1.9.1

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 0/2] [ARC] New features (updated)
  2017-04-25 15:46   ` Sandra Loosemore
  2017-04-26 13:15     ` Claudiu Zissulescu
@ 2017-05-05 11:05     ` Claudiu Zissulescu
  2017-05-05 11:05       ` [PATCH 1/2] Automatic context save/restore for regular interrupts Claudiu Zissulescu
  2017-05-05 11:23       ` [PATCH 2/2] Fast interrupts support Claudiu Zissulescu
  1 sibling, 2 replies; 17+ messages in thread
From: Claudiu Zissulescu @ 2017-05-05 11:05 UTC (permalink / raw)
  To: gcc-patches; +Cc: Claudiu.Zissulescu, Francois.Bedard, andrew.burgess, sandra

From: claziss <claziss@synopsys.com>

Hi,

I've updated the two patches (out of three) as indicated by Sandra.

Ok to apply?
Claudiu

Claudiu Zissulescu (2):
  Automatic context save/restore for regular interrupts.
  Fast interrupts support.

 gcc/config/arc/arc.c                       | 407 ++++++++++++++++++++++++++---
 gcc/config/arc/arc.h                       |  13 +-
 gcc/config/arc/arc.md                      |  17 +-
 gcc/config/arc/arc.opt                     |   8 +
 gcc/doc/invoke.texi                        |  21 +-
 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 ++
 gcc/testsuite/gcc.target/arc/interrupt-5.c |  19 ++
 gcc/testsuite/gcc.target/arc/interrupt-6.c |  22 ++
 gcc/testsuite/gcc.target/arc/interrupt-7.c |  16 ++
 gcc/testsuite/gcc.target/arc/interrupt-8.c |  27 ++
 gcc/testsuite/gcc.target/arc/interrupt-9.c |  17 ++
 16 files changed, 684 insertions(+), 48 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
 create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-5.c
 create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-6.c
 create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-7.c
 create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-8.c
 create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-9.c

-- 
1.9.1

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 2/2] Fast interrupts support.
  2017-05-05 11:05     ` [PATCH 0/2] [ARC] New features (updated) Claudiu Zissulescu
  2017-05-05 11:05       ` [PATCH 1/2] Automatic context save/restore for regular interrupts Claudiu Zissulescu
@ 2017-05-05 11:23       ` Claudiu Zissulescu
  2017-05-08 14:54         ` Andrew Burgess
  1 sibling, 1 reply; 17+ messages in thread
From: Claudiu Zissulescu @ 2017-05-05 11:23 UTC (permalink / raw)
  To: gcc-patches; +Cc: Claudiu.Zissulescu, Francois.Bedard, andrew.burgess, sandra

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.
---
 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

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 1/2] Automatic context save/restore for regular interrupts.
  2017-05-05 11:05       ` [PATCH 1/2] Automatic context save/restore for regular interrupts Claudiu Zissulescu
@ 2017-05-08 14:50         ` Andrew Burgess
  2017-05-09 14:24           ` Claudiu Zissulescu
  0 siblings, 1 reply; 17+ messages in thread
From: Andrew Burgess @ 2017-05-08 14:50 UTC (permalink / raw)
  To: Claudiu Zissulescu; +Cc: gcc-patches, Francois.Bedard, sandra

* Claudiu Zissulescu <Claudiu.Zissulescu@synopsys.com> [2017-05-05 13:02:43 +0200]:

> The AUX_IRQ_CTRL register controls the behavior of automated register
> save and restore or prologue and epilogue sequences during a non-fast
> interrupt entry and exit, and context save and restore instructions.
> 
> A user passes to the compiler the configuration of the AUX_IRQ_CTRL
> register via mirq-ctrl-saved option.  This option, specifies
> gneral-purposes registers that the processor saves/restores on
> interrupt entry and exit, and it is only valid for ARC EM and ARC HS
> cores.
> 
> gcc/
> 2017-05-05  Claudiu Zissulescu  <claziss@synopsys.com>
> 
> 	* config/arc/arc.c (irq_ctrl_saved): New variable.
> 	(ARC_AUTOBLINK_IRQ_P): Define.
> 	(ARC_AUTOFP_IRQ_P): Likewise.
> 	(ARC_AUTO_IRQ_P): Likewise.
> 	(irq_range): New function.
> 	(arc_must_save_register): Likewise.
> 	(arc_must_save_return_addr): Likewise.
> 	(arc_dwarf_emit_irq_save_regs): Likewise.
> 	(arc_override_options): Handle deferred options.
> 	(MUST_SAVE_REGISTER): Deleted, replaced by arc_must_save_register.
> 	(MUST_SAVE_RETURN_ADDR): Deleted, replaced by
> 	arc_must_save_return_addr.
> 	(arc_compute_frame_size): Handle automated save and restore of
> 	registers.
> 	(arc_expand_prologue): Likewise.
> 	(arc_expand_epilogue): Likewise.
> 	* config/arc/arc.md (stack_irq_dwarf): New unspec instruction.
> 	* config/arc/arc.opt (mirq-ctrl-saved): New option.
> 	* doc/invoke.texi (mirq-ctrl-saved): Document option.
> 	* testsuite/gcc.target/arc/interrupt-5.c: Newfile.
> 	* testsuite/gcc.target/arc/interrupt-6.c: Likewise.
> 	* testsuite/gcc.target/arc/interrupt-7.c: Likewise.
> 	* testsuite/gcc.target/arc/interrupt-8.c: Likewise.
> 	* testsuite/gcc.target/arc/interrupt-9.c: Likewise.
> ---
>  gcc/config/arc/arc.c                       | 329 ++++++++++++++++++++++++++---
>  gcc/config/arc/arc.md                      |   8 +
>  gcc/config/arc/arc.opt                     |   4 +
>  gcc/doc/invoke.texi                        |  11 +-
>  gcc/testsuite/gcc.target/arc/interrupt-5.c |  19 ++
>  gcc/testsuite/gcc.target/arc/interrupt-6.c |  22 ++
>  gcc/testsuite/gcc.target/arc/interrupt-7.c |  16 ++
>  gcc/testsuite/gcc.target/arc/interrupt-8.c |  27 +++
>  gcc/testsuite/gcc.target/arc/interrupt-9.c |  17 ++
>  9 files changed, 421 insertions(+), 32 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-5.c
>  create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-6.c
>  create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-7.c
>  create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-8.c
>  create mode 100644 gcc/testsuite/gcc.target/arc/interrupt-9.c
> 
> diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
> index 4574481..a61faef 100644
> --- a/gcc/config/arc/arc.c
> +++ b/gcc/config/arc/arc.c
> @@ -63,6 +63,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "builtins.h"
>  #include "rtl-iter.h"
>  #include "alias.h"
> +#include "opts.h"
>  
>  /* Which cpu we're compiling for (ARC600, ARC601, ARC700).  */
>  static char arc_cpu_name[10] = "";
> @@ -111,6 +112,29 @@ struct GTY (()) arc_ccfsm
>    int target_label;
>  };
>  
> +/* Status of the IRQ_CTRL_AUX register.  */
> +typedef struct irq_ctrl_saved_t
> +{
> +  short irq_save_last_reg;      /* Last register number used by
> +				   IRQ_CTRL_SAVED aux_reg.  */
> +  bool  irq_save_blink;         /* True if BLINK is automatically
> +				   saved.  */
> +  bool  irq_save_lpcount;       /* True if LPCOUNT is automatically
> +				   saved.  */
> +} irq_ctrl_saved_t;

I'm pretty sure GNU style is to put the comments above each entry in
the struct, such as:

     /* Last register number used by IRQ_CTRL_SAVED aux_reg.  */
     short irq_save_last_reg;

I did have a quick look though GCC and couldn't see many examples of
comments to the right.

> +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			\
> +       || (irq_ctrl_saved.irq_save_last_reg >= 0)))
> +
>  #define arc_ccfsm_current cfun->machine->ccfsm_current
>  
>  #define ARC_CCFSM_BRANCH_DELETED_P(STATE) \
> @@ -806,11 +830,110 @@ arc_init (void)
>      }
>  }
>  
> +/* Parse -mirq-ctrl-saved= option string.  Registers may be specified
> +   individually, or as ranges such as "r0-r3".  Registers accepted are
> +   r0 through r31 and lp_count.  Registers and ranges must be
> +   comma-separated.  */

The comment seems to be out of line with both the documentation and
the actual functionality of the function.

Everything else looks fine to me,

Thanks,
Andrew






> +
> +static void
> +irq_range (const char *cstr)
> +{
> +  int i, first, last, blink, lpcount, xreg;
> +  char *str, *dash, *comma;
> +
> +  i = strlen (cstr);
> +  str = (char *) alloca (i + 1);
> +  memcpy (str, cstr, i + 1);
> +  blink = -1;
> +  lpcount = -1;
> +
> +  dash = strchr (str, '-');
> +  if (!dash)
> +    {
> +      warning (0, "value of -mirq-ctrl-saved must have form R0-REGx");
> +      return;
> +    }
> +  *dash = '\0';
> +
> +  comma = strchr (dash + 1, ',');
> +  if (comma)
> +    *comma = '\0';
> +
> +  first = decode_reg_name (str);
> +  if (first != 0)
> +    {
> +      warning (0, "first register must be R0");
> +      return;
> +    }
> +
> +  /* At this moment we do not have the register names initialized
> +     accordingly.  */
> +  if (!strcmp (dash + 1, "ilink"))
> +    last = 29;
> +  else
> +    last = decode_reg_name (dash + 1);
> +
> +  if (last < 0)
> +    {
> +      warning (0, "unknown register name: %s", dash + 1);
> +      return;
> +    }
> +
> +  if (!(last & 0x01))
> +    {
> +      warning (0, "last register name %s must be an odd register", dash + 1);
> +      return;
> +    }
> +
> +  *dash = '-';
> +
> +  if (first > last)
> +    {
> +      warning (0, "%s-%s is an empty range", str, dash + 1);
> +      return;
> +    }
> +
> +  while (comma)
> +    {
> +      *comma = ',';
> +      str = comma + 1;
> +
> +      comma = strchr (str, ',');
> +      if (comma)
> +	*comma = '\0';
> +
> +      xreg = decode_reg_name (str);
> +      switch (xreg)
> +	{
> +	case 31:
> +	  blink = 31;
> +	  break;
> +
> +	case 60:
> +	  lpcount = 60;
> +	  break;
> +
> +	default:
> +	  warning (0, "unknown register name: %s", str);
> +	  return;
> +	}
> +    }
> +
> +  irq_ctrl_saved.irq_save_last_reg = last;
> +  irq_ctrl_saved.irq_save_blink    = (blink == 31) || (last == 31);
> +  irq_ctrl_saved.irq_save_lpcount  = (lpcount == 60);
> +}
> +
>  /* Check ARC options, generate derived target attributes.  */
>  
>  static void
>  arc_override_options (void)
>  {
> +  unsigned int i;
> +  cl_deferred_option *opt;
> +  vec<cl_deferred_option> *vopt
> +    = (vec<cl_deferred_option> *) arc_deferred_options;
> +
>    if (arc_cpu == PROCESSOR_NONE)
>      arc_cpu = TARGET_CPU_DEFAULT;
>  
> @@ -839,6 +962,28 @@ arc_override_options (void)
>        gcc_unreachable ();
>      }
>  
> +  irq_ctrl_saved.irq_save_last_reg = -1;
> +  irq_ctrl_saved.irq_save_blink    = false;
> +  irq_ctrl_saved.irq_save_lpcount  = false;
> +
> +  /* Handle the deferred options.  */
> +  if (vopt)
> +    FOR_EACH_VEC_ELT (*vopt, i, opt)
> +      {
> +	switch (opt->opt_index)
> +	  {
> +	  case OPT_mirq_ctrl_saved_:
> +	    if (TARGET_V2)
> +	      irq_range (opt->arg);
> +	    else
> +	      warning (0, "option -mirq-ctrl-saved valid only for ARC v2 processors");
> +	    break;
> +
> +	  default:
> +	    gcc_unreachable();
> +	  }
> +      }
> +
>    /* Set cpu flags accordingly to architecture/selected cpu.  The cpu
>       specific flags are set in arc-common.c.  The architecture forces
>       the default hardware configurations in, regardless what command
> @@ -2235,14 +2380,52 @@ arc_compute_function_type (struct function *fun)
>     FIXME: This will not be needed if we used some arbitrary register
>     instead of r26.
>  */
> -#define MUST_SAVE_REGISTER(regno, interrupt_p) \
> -(((regno) != RETURN_ADDR_REGNUM && (regno) != FRAME_POINTER_REGNUM \
> -  && (df_regs_ever_live_p (regno) && (!call_used_regs[regno] || interrupt_p))) \
> - || (flag_pic && crtl->uses_pic_offset_table \
> -     && regno == PIC_OFFSET_TABLE_REGNUM) )
>  
> -#define MUST_SAVE_RETURN_ADDR \
> -  (cfun->machine->frame_info.save_return_addr)
> +static bool
> +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));
> +
> +  if ((regno) != RETURN_ADDR_REGNUM
> +      && (regno) != FRAME_POINTER_REGNUM
> +      && df_regs_ever_live_p (regno)
> +      && (!call_used_regs[regno]
> +	  || ARC_INTERRUPT_P (fn_type))
> +      /* Do not emit code for auto saved regs.  */
> +      && !irq_auto_save_p)
> +    return true;
> +
> +  if (flag_pic && crtl->uses_pic_offset_table
> +      && regno == PIC_OFFSET_TABLE_REGNUM)
> +    return true;
> +
> +  return false;
> +}
> +
> +/* Return true if the return address must be saved in the current function,
> +   otherwise return false.  */
> +
> +static bool
> +arc_must_save_return_addr (struct function *func)
> +{
> +  if (func->machine->frame_info.save_return_addr)
> +    return true;
> +
> +  return false;
> +}
> +
> +/* Helper function to wrap FRAME_POINTER_NEEDED.  We do this as
> +   FRAME_POINTER_NEEDED will not be true until the IRA (Integrated
> +   Register Allocator) pass, while we want to get the frame size
> +   correct earlier than the IRA pass.  */
> +static bool
> +arc_frame_pointer_needed (void)
> +{
> +  return (frame_pointer_needed);
> +}
> +
>  
>  /* Return non-zero if there are registers to be saved or loaded using
>     millicode thunks.  We can only use consecutive sequences starting
> @@ -2286,8 +2469,6 @@ arc_compute_frame_size (int size)	/* size = # of var. bytes allocated.  */
>    unsigned int total_size, var_size, args_size, pretend_size, extra_size;
>    unsigned int reg_size, reg_offset;
>    unsigned int gmask;
> -  enum arc_function_type fn_type;
> -  int interrupt_p;
>    struct arc_frame_info *frame_info = &cfun->machine->frame_info;
>  
>    size = ARC_STACK_ALIGN (size);
> @@ -2306,15 +2487,13 @@ arc_compute_frame_size (int size)	/* size = # of var. bytes allocated.  */
>  
>    reg_size = 0;
>    gmask = 0;
> -  fn_type = arc_compute_function_type (cfun);
> -  interrupt_p = ARC_INTERRUPT_P (fn_type);
>  
>    for (regno = 0; regno <= 31; regno++)
>      {
> -      if (MUST_SAVE_REGISTER (regno, interrupt_p))
> +      if (arc_must_save_register (regno, cfun))
>  	{
>  	  reg_size += UNITS_PER_WORD;
> -	  gmask |= 1 << regno;
> +	  gmask |= 1L << regno;
>  	}
>      }
>  
> @@ -2330,9 +2509,9 @@ arc_compute_frame_size (int size)	/* size = # of var. bytes allocated.  */
>      }
>  
>    extra_size = 0;
> -  if (MUST_SAVE_RETURN_ADDR)
> +  if (arc_must_save_return_addr (cfun))
>      extra_size = 4;
> -  if (frame_pointer_needed)
> +  if (arc_frame_pointer_needed ())
>      extra_size += 4;
>  
>    /* 5) Space for variable arguments passed in registers */
> @@ -2357,7 +2536,7 @@ arc_compute_frame_size (int size)	/* size = # of var. bytes allocated.  */
>       Frame: pretend_size <blink> reg_size <fp> var_size args_size <--sp
>    */
>    reg_offset = (total_size - (pretend_size + reg_size + extra_size)
> -		+ (frame_pointer_needed ? 4 : 0));
> +		+ (arc_frame_pointer_needed () ? 4 : 0));
>  
>    /* Save computed information.  */
>    frame_info->total_size   = total_size;
> @@ -2548,6 +2727,77 @@ arc_save_restore (rtx base_reg,
>  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.  */
> +
> +static void
> +arc_dwarf_emit_irq_save_regs (void)
> +{
> +  rtx tmp, par, insn, reg;
> +  int i, offset, j;
> +
> +  par = gen_rtx_SEQUENCE (VOIDmode,
> +			  rtvec_alloc (irq_ctrl_saved.irq_save_last_reg + 1
> +				       + irq_ctrl_saved.irq_save_blink
> +				       + irq_ctrl_saved.irq_save_lpcount
> +				       + 1));
> +
> +  /* Build the stack adjustment note for unwind info.  */
> +  j = 0;
> +  offset = UNITS_PER_WORD * (irq_ctrl_saved.irq_save_last_reg + 1
> +			     + irq_ctrl_saved.irq_save_blink
> +			     + irq_ctrl_saved.irq_save_lpcount);
> +  tmp = plus_constant (Pmode, stack_pointer_rtx, -1 * offset);
> +  tmp = gen_rtx_SET (stack_pointer_rtx, tmp);
> +  RTX_FRAME_RELATED_P (tmp) = 1;
> +  XVECEXP (par, 0, j++) = tmp;
> +
> +  offset -= UNITS_PER_WORD;
> +
> +  /* 1st goes LP_COUNT.  */
> +  if (irq_ctrl_saved.irq_save_lpcount)
> +    {
> +      reg = gen_rtx_REG (SImode, 60);
> +      tmp = plus_constant (Pmode, stack_pointer_rtx, offset);
> +      tmp = gen_frame_mem (SImode, tmp);
> +      tmp = gen_rtx_SET (tmp, reg);
> +      RTX_FRAME_RELATED_P (tmp) = 1;
> +      XVECEXP (par, 0, j++) = tmp;
> +      offset -= UNITS_PER_WORD;
> +    }
> +
> +  /* 2nd goes BLINK.  */
> +  if (irq_ctrl_saved.irq_save_blink)
> +    {
> +      reg = gen_rtx_REG (SImode, 31);
> +      tmp = plus_constant (Pmode, stack_pointer_rtx, offset);
> +      tmp = gen_frame_mem (SImode, tmp);
> +      tmp = gen_rtx_SET (tmp, reg);
> +      RTX_FRAME_RELATED_P (tmp) = 1;
> +      XVECEXP (par, 0, j++) = tmp;
> +      offset -= UNITS_PER_WORD;
> +    }
> +
> +  /* Build the parallel of the remaining registers recorded as saved
> +     for unwind.  */
> +  for (i = irq_ctrl_saved.irq_save_last_reg; i >= 0; i--)
> +    {
> +      reg = gen_rtx_REG (SImode, i);
> +      tmp = plus_constant (Pmode, stack_pointer_rtx, offset);
> +      tmp = gen_frame_mem (SImode, tmp);
> +      tmp = gen_rtx_SET (tmp, reg);
> +      RTX_FRAME_RELATED_P (tmp) = 1;
> +      XVECEXP (par, 0, j++) = tmp;
> +      offset -= UNITS_PER_WORD;
> +    }
> +
> +  /* Dummy insn used to anchor the dwarf info.  */
> +  insn = emit_insn (gen_stack_irq_dwarf());
> +  add_reg_note (insn, REG_FRAME_RELATED_EXPR, par);
> +  RTX_FRAME_RELATED_P (insn) = 1;
> +}
> +
>  /* Set up the stack and frame pointer (if desired) for the function.  */
>  
>  void
> @@ -2561,6 +2811,7 @@ arc_expand_prologue (void)
>       Change the stack layout so that we rather store a high register with the
>       PRE_MODIFY, thus enabling more short insn generation.)  */
>    int first_offset = 0;
> +  enum arc_function_type fn_type = arc_compute_function_type (cfun);
>  
>    size = ARC_STACK_ALIGN (size);
>  
> @@ -2588,16 +2839,25 @@ arc_expand_prologue (void)
>        frame_size_to_allocate -= cfun->machine->frame_info.pretend_size;
>      }
>  
> +  /* IRQ using automatic save mechanism will save the register before
> +     anything we do.  */
> +  if (ARC_AUTO_IRQ_P (fn_type))
> +    {
> +      arc_dwarf_emit_irq_save_regs ();
> +    }
> +
>    /* The home-grown ABI says link register is saved first.  */
> -  if (MUST_SAVE_RETURN_ADDR)
> +  if (arc_must_save_return_addr (cfun)
> +      && !ARC_AUTOBLINK_IRQ_P (fn_type))
>      {
>        rtx ra = gen_rtx_REG (SImode, RETURN_ADDR_REGNUM);
> -      rtx mem = gen_frame_mem (Pmode, gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx));
> +      rtx mem = gen_frame_mem (Pmode,
> +			       gen_rtx_PRE_DEC (Pmode,
> +						stack_pointer_rtx));
>  
>        frame_move_inc (mem, ra, stack_pointer_rtx, 0);
>        frame_size_to_allocate -= UNITS_PER_WORD;
> -
> -    } /* MUST_SAVE_RETURN_ADDR */
> +    }
>  
>    /* Save any needed call-saved regs (and call-used if this is an
>       interrupt handler) for ARCompact ISA.  */
> @@ -2609,9 +2869,10 @@ arc_expand_prologue (void)
>        frame_size_to_allocate -= cfun->machine->frame_info.reg_size;
>      }
>  
> -
> -  /* Save frame pointer if needed.  */
> -  if (frame_pointer_needed)
> +  /* Save frame pointer if needed.  First save the FP on stack, if not
> +     autosaved.  */
> +  if (arc_frame_pointer_needed ()
> +      && !ARC_AUTOFP_IRQ_P (fn_type))
>      {
>        rtx addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
>  			       GEN_INT (-UNITS_PER_WORD + first_offset));
> @@ -2621,6 +2882,11 @@ arc_expand_prologue (void)
>        frame_move_inc (mem, frame_pointer_rtx, stack_pointer_rtx, 0);
>        frame_size_to_allocate -= UNITS_PER_WORD;
>        first_offset = 0;
> +    }
> +
> +  /* Emit mov fp,sp.  */
> +  if (arc_frame_pointer_needed ())
> +    {
>        frame_move (frame_pointer_rtx, stack_pointer_rtx);
>      }
>  
> @@ -2675,13 +2941,13 @@ arc_expand_epilogue (int sibcall_p)
>       sp, but don't restore sp if we don't have to.  */
>  
>    if (!can_trust_sp_p)
> -    gcc_assert (frame_pointer_needed);
> +    gcc_assert (arc_frame_pointer_needed ());
>  
>    /* Restore stack pointer to the beginning of saved register area for
>       ARCompact ISA.  */
>    if (frame_size)
>      {
> -      if (frame_pointer_needed)
> +      if (arc_frame_pointer_needed ())
>  	frame_move (stack_pointer_rtx, frame_pointer_rtx);
>        else
>  	first_offset = frame_size;
> @@ -2692,7 +2958,8 @@ arc_expand_epilogue (int sibcall_p)
>  
>  
>    /* Restore any saved registers.  */
> -  if (frame_pointer_needed)
> +  if (arc_frame_pointer_needed ()
> +      && !ARC_AUTOFP_IRQ_P (fn_type))
>      {
>        rtx addr = gen_rtx_POST_INC (Pmode, stack_pointer_rtx);
>  
> @@ -2730,14 +2997,15 @@ arc_expand_epilogue (int sibcall_p)
>  	    : satisfies_constraint_C2a (GEN_INT (first_offset))))
>         /* Also do this if we have both gprs and return
>  	  address to restore, and they both would need a LIMM.  */
> -       || (MUST_SAVE_RETURN_ADDR
> -	   && !SMALL_INT ((cfun->machine->frame_info.reg_size + first_offset) >> 2)
> -	   && cfun->machine->frame_info.gmask))
> +      || (arc_must_save_return_addr (cfun)
> +	  && !SMALL_INT ((cfun->machine->frame_info.reg_size + first_offset) >> 2)
> +	  && cfun->machine->frame_info.gmask))
>      {
>        frame_stack_add (first_offset);
>        first_offset = 0;
>      }
> -  if (MUST_SAVE_RETURN_ADDR)
> +  if (arc_must_save_return_addr (cfun)
> +      && !ARC_AUTOBLINK_IRQ_P (fn_type))
>      {
>        rtx ra = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
>        int ra_offs = cfun->machine->frame_info.reg_size + first_offset;
> @@ -2802,7 +3070,6 @@ arc_expand_epilogue (int sibcall_p)
>  			   & ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK), 1, &first_offset);
>      }
>  
> -
>    /* The rest of this function does the following:
>       ARCompact    : handle epilogue_delay, restore sp (phase-2), return
>    */
> diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md
> index 802c3e9..2221fb5 100644
> --- a/gcc/config/arc/arc.md
> +++ b/gcc/config/arc/arc.md
> @@ -6241,6 +6241,14 @@
>    [(set (zero_extract:SI (match_dup 3) (match_dup 1) (match_dup 2))
>  	(zero_extract:SI (match_dup 0) (match_dup 1) (match_dup 2)))])
>  
> +;; Dummy pattern used as a place holder for automatically saved
> +;; registers.
> +(define_insn "stack_irq_dwarf"
> +  [(unspec_volatile [(const_int 1)] VUNSPEC_ARC_STACK_IRQ)]
> +  ""
> +  ""
> +  [(set_attr "length" "0")])
> +
>  ;; include the arc-FPX instructions
>  (include "fpx.md")
>  
> diff --git a/gcc/config/arc/arc.opt b/gcc/config/arc/arc.opt
> index 6060ded..483470d 100644
> --- a/gcc/config/arc/arc.opt
> +++ b/gcc/config/arc/arc.opt
> @@ -486,3 +486,7 @@ Enable use of NPS400 xld/xst extension.
>  munaligned-access
>  Target Report Var(unaligned_access) Init(UNALIGNED_ACCESS_DEFAULT)
>  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.
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 68a558e..bd3b339 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -606,7 +606,7 @@ 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 @gol
> +-mlong-calls  -mmedium-calls  -msdata -mirq-ctrl-saved @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
> @@ -14545,6 +14545,15 @@ hardware extensions.  Not available for ARC EM@.
>  
>  @end table
>  
> +@item -mirq-ctrl-saved=@var{register-range}, @var{blink}, @var{lp_count}
> +@opindex mirq-ctrl-saved
> +Specifies general-purposes registers that the processor automatically
> +saves/restores on interrupt entry and exit.  @var{register-range} is
> +specified as two registers separated by a dash.  The register range
> +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.
> +
>  @end table
>  
>  The following options are passed through to the assembler, and also
> diff --git a/gcc/testsuite/gcc.target/arc/interrupt-5.c b/gcc/testsuite/gcc.target/arc/interrupt-5.c
> new file mode 100644
> index 0000000..ee01d76
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/arc/interrupt-5.c
> @@ -0,0 +1,19 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "Not available for ARCv1" { arc700 ||  arc6xx } } */
> +/* { dg-options "-O2 -mirq-ctrl-saved=r0-r3,blink" } */
> +
> +/* Check if the registers R0-R3,blink are automatically saved. */
> +
> +extern int bar (void *);
> +
> +void  __attribute__ ((interrupt("ilink")))
> +foo(void)
> +{
> +  bar (0);
> +  __asm__ volatile ( "" : : : "r0","r1","r2","r3");
> +}
> +/* { dg-final { scan-assembler-not "st.*r0,\\\[sp" } } */
> +/* { dg-final { scan-assembler-not "st.*r1,\\\[sp" } } */
> +/* { dg-final { scan-assembler-not "st.*r2,\\\[sp" } } */
> +/* { dg-final { scan-assembler-not "st.*r3,\\\[sp" } } */
> +/* { dg-final { scan-assembler-not "push_s blink" } } */
> diff --git a/gcc/testsuite/gcc.target/arc/interrupt-6.c b/gcc/testsuite/gcc.target/arc/interrupt-6.c
> new file mode 100644
> index 0000000..509ff30
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/arc/interrupt-6.c
> @@ -0,0 +1,22 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "Not available for ARCv1" { arc700 || arc6xx } } */
> +/* { dg-options "-O2 -mirq-ctrl-saved=r0-ilink" } */
> +
> +#include <alloca.h>
> +
> +/* Check if ilink is recognized. Check how FP and BLINK are saved.
> +   BLINK is saved last on the stack because the IRQ autosave will do
> +   first r0-ilink.  To avoid this ABI exception, one needs to autosave
> +   always blink when using the IRQ autosave feature.  */
> +
> +extern int bar (void *);
> +
> +void  __attribute__ ((interrupt("ilink")))
> +foo(void)
> +{
> +  int *p = alloca (10);
> +  bar (p);
> +}
> +/* { dg-final { scan-assembler-not ".*fp,\\\[sp" } } */
> +/* { dg-final { scan-assembler "ld.*blink,\\\[sp\\\]" } } */
> +/* { dg-final { scan-assembler "push_s.*blink" } } */
> diff --git a/gcc/testsuite/gcc.target/arc/interrupt-7.c b/gcc/testsuite/gcc.target/arc/interrupt-7.c
> new file mode 100644
> index 0000000..547dfd3
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/arc/interrupt-7.c
> @@ -0,0 +1,16 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "Not available for ARCv1" { arc700 ||  arc6xx } } */
> +/* { dg-options "-O2 -mirq-ctrl-saved=r0-r17,blink" } */
> +
> +/* Check if the registers R0-R17,blink are automatically saved. */
> +
> +void  __attribute__ ((interrupt("ilink")))
> +foo(void)
> +{
> +  __asm__ volatile ( "" : : : "r13","r14","r15","r16");
> +}
> +/* { dg-final { scan-assembler-not "st.*r13,\\\[sp" } } */
> +/* { dg-final { scan-assembler-not "st.*r14,\\\[sp" } } */
> +/* { dg-final { scan-assembler-not "st.*r15,\\\[sp" } } */
> +/* { dg-final { scan-assembler-not "st.*r16,\\\[sp" } } */
> +/* { dg-final { scan-assembler-not "push_s blink" } } */
> diff --git a/gcc/testsuite/gcc.target/arc/interrupt-8.c b/gcc/testsuite/gcc.target/arc/interrupt-8.c
> new file mode 100644
> index 0000000..60fd87b
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/arc/interrupt-8.c
> @@ -0,0 +1,27 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "Not available for ARCv1" { arc700 || arc6xx } } */
> +/* { dg-options "-O2 -mirq-ctrl-saved=r0-r17" } */
> +
> +/* Check if the registers R0-R17 are automatically saved.  GP is saved
> +   by the compiler.  */
> +
> +int a;
> +
> +void  __attribute__ ((interrupt("ilink")))
> +foo(void)
> +{
> +  __asm__ volatile ( "" : : : "r0","r1","r2","r3");
> +  __asm__ volatile ( "" : : : "r13","r14","r15","r16");
> +  a++;
> +}
> +/* { dg-final { scan-assembler-not "st.*r13,\\\[sp" } } */
> +/* { dg-final { scan-assembler-not "st.*r14,\\\[sp" } } */
> +/* { dg-final { scan-assembler-not "st.*r15,\\\[sp" } } */
> +/* { dg-final { scan-assembler-not "st.*r16,\\\[sp" } } */
> +/* { dg-final { scan-assembler "st.*gp,\\\[sp,-4\\\]" } } */
> +/* { dg-final { scan-assembler "ld.*gp,\\\[sp\\\]" } } */
> +/* { dg-final { scan-assembler-not "st.*r0,\\\[sp" } } */
> +/* { dg-final { scan-assembler-not "st.*r1,\\\[sp" } } */
> +/* { dg-final { scan-assembler-not "st.*r2,\\\[sp" } } */
> +/* { dg-final { scan-assembler-not "st.*r3,\\\[sp" } } */
> +/* { dg-final { scan-assembler "rtie" } } */
> diff --git a/gcc/testsuite/gcc.target/arc/interrupt-9.c b/gcc/testsuite/gcc.target/arc/interrupt-9.c
> new file mode 100644
> index 0000000..4547fef
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/arc/interrupt-9.c
> @@ -0,0 +1,17 @@
> +/* { dg-do compile } */
> +/* { dg-require-effective-target archs }*/
> +/* { dg-options "-O0 -mirq-ctrl-saved=r0-fp" } */
> +
> +/* Check if we get the move operation between fp and sp.  */
> +
> +void __attribute__ ((interrupt("ilink")))
> +handler1 (void)
> +{
> +  asm (""
> +       :
> +       :
> +       : "r0", "r1", "r2", "r3", "r4",
> +         "r5", "r6", "r7", "r8", "r9");
> +}
> +/* { dg-final { scan-assembler "mov.*fp,sp" } } */
> +/* { dg-final { scan-assembler-not ".*fp,\\\[sp" } } */
> -- 
> 1.9.1
> 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/2] Fast interrupts support.
  2017-05-05 11:23       ` [PATCH 2/2] Fast interrupts support Claudiu Zissulescu
@ 2017-05-08 14:54         ` Andrew Burgess
  2017-05-09 14:25           ` Claudiu Zissulescu
  0 siblings, 1 reply; 17+ messages in thread
From: Andrew Burgess @ 2017-05-08 14:54 UTC (permalink / raw)
  To: Claudiu Zissulescu; +Cc: gcc-patches, Francois.Bedard, sandra

* 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
> 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 3/3] [ARC] Add support for advanced mpy/mac instructions.
  2017-04-25 13:21 ` [PATCH 3/3] [ARC] Add support for advanced mpy/mac instructions Claudiu Zissulescu
@ 2017-05-08 15:10   ` Andrew Burgess
  2017-05-09 14:42     ` Claudiu Zissulescu
  0 siblings, 1 reply; 17+ messages in thread
From: Andrew Burgess @ 2017-05-08 15:10 UTC (permalink / raw)
  To: Claudiu Zissulescu; +Cc: gcc-patches, Francois.Bedard

* Claudiu Zissulescu <Claudiu.Zissulescu@synopsys.com> [2017-04-25 15:03:44 +0200]:

> Add support for MAC and DMPY instructions. ARCv2 Only.
> 
> gcc/
> 2016-12-08  Claudiu Zissulescu  <claziss@synopsys.com>
> 
> 	* config/arc/arc.c (arc_conditional_register_usage): Handle ACCL,
> 	ACCH registers.
> 	* config/arc/arc.md (mulsidi3): Use advanced mpy instructions when
> 	available.
> 	(umulsidi3): Likewise.
> 	(mulsidi3_700): Disable this pattern when we have advanced mpy
> 	instructions.
> 	(umulsidi3_700): Likewise.
> 	(maddsidi4): New pattern.
> 	(macd, mac, mac_r, umaddsidi4, macdu, macu, macu_r): Likewise.
> 	(mpyd_arcv2hs, mpyd_imm_arcv2hs, mpydu_arcv2hs): Likewise.
> 	(mpydu_imm_arcv2hs): Likewise.
> 	* config/arc/predicates.md (accl_operand): New predicate.

Looks good, but is it not possible to write some tests?

Thanks,
Andrew




> ---
>  gcc/config/arc/arc.c         |   5 +-
>  gcc/config/arc/arc.md        | 266 ++++++++++++++++++++++++++++++++++++++++++-
>  gcc/config/arc/predicates.md |   5 +
>  3 files changed, 272 insertions(+), 4 deletions(-)
> 
> diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
> index 170b8dd..238244b 100644
> --- a/gcc/config/arc/arc.c
> +++ b/gcc/config/arc/arc.c
> @@ -1789,8 +1789,9 @@ arc_conditional_register_usage (void)
>    arc_regno_reg_class[PROGRAM_COUNTER_REGNO] = GENERAL_REGS;
>  
>    /*ARCV2 Accumulator.  */
> -  if (TARGET_V2
> -      && (TARGET_FP_DP_FUSED || TARGET_FP_SP_FUSED))
> +  if ((TARGET_V2
> +       && (TARGET_FP_DP_FUSED || TARGET_FP_SP_FUSED))
> +      || TARGET_PLUS_DMPY)
>    {
>      arc_regno_reg_class[ACCL_REGNO] = WRITABLE_CORE_REGS;
>      arc_regno_reg_class[ACCH_REGNO] = WRITABLE_CORE_REGS;
> diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md
> index ffab390..db5867c 100644
> --- a/gcc/config/arc/arc.md
> +++ b/gcc/config/arc/arc.md
> @@ -2157,6 +2157,18 @@
>    "TARGET_ANY_MPY"
>  "
>  {
> +  if (TARGET_PLUS_MACD)
> +    {
> +     if (CONST_INT_P (operands[2]))
> +       {
> +	emit_insn (gen_mpyd_imm_arcv2hs (operands[0], operands[1], operands[2]));
> +       }
> +     else
> +       {
> +	emit_insn (gen_mpyd_arcv2hs (operands[0], operands[1], operands[2]));
> +       }
> +     DONE;
> +    }
>    if (TARGET_MPY)
>      {
>        operands[2] = force_reg (SImode, operands[2]);
> @@ -2237,7 +2249,7 @@
>    [(set (match_operand:DI 0 "register_operand" "=&r")
>  	(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%c"))
>  		 (sign_extend:DI (match_operand:SI 2 "extend_operand" "cL"))))]
> -  "TARGET_MPY"
> +  "TARGET_MPY && !TARGET_PLUS_MACD"
>    "#"
>    "&& reload_completed"
>    [(const_int 0)]
> @@ -2390,6 +2402,18 @@
>  		 (zero_extend:DI (match_operand:SI 2 "nonmemory_operand" ""))))]
>    ""
>  {
> +  if (TARGET_PLUS_MACD)
> +    {
> +     if (CONST_INT_P (operands[2]))
> +       {
> +	emit_insn (gen_mpydu_imm_arcv2hs (operands[0], operands[1], operands[2]));
> +       }
> +     else
> +       {
> +	emit_insn (gen_mpydu_arcv2hs (operands[0], operands[1], operands[2]));
> +       }
> +     DONE;
> +    }
>    if (TARGET_MPY)
>      {
>        operands[2] = force_reg (SImode, operands[2]);
> @@ -2480,7 +2504,7 @@
>    [(set (match_operand:DI 0 "dest_reg_operand" "=&r")
>  	(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%c"))
>  		 (zero_extend:DI (match_operand:SI 2 "extend_operand" "cL"))))]
> -  "TARGET_MPY"
> +  "TARGET_MPY && !TARGET_PLUS_MACD"
>    "#"
>    "reload_completed"
>    [(const_int 0)]
> @@ -6215,6 +6239,244 @@
>    ""
>    [(set_attr "length" "0")])
>  
> +;; MAC and DMPY instructions
> +(define_insn_and_split "maddsidi4"
> +  [(set (match_operand:DI 0 "register_operand" "=r")
> +	(plus:DI
> +	 (mult:DI
> +	  (sign_extend:DI (match_operand:SI 1 "register_operand" "%r"))
> +	  (sign_extend:DI (match_operand:SI 2 "extend_operand" "ri")))
> +	 (match_operand:DI 3 "register_operand" "r")))]
> +  "TARGET_PLUS_DMPY"
> +  "#"
> +  "TARGET_PLUS_DMPY && reload_completed"
> +  [(const_int 0)]
> +  "{
> +   rtx acc_reg = gen_rtx_REG (DImode, ACC_REG_FIRST);
> +   emit_move_insn (acc_reg, operands[3]);
> +   if (TARGET_PLUS_MACD)
> +     emit_insn (gen_macd (operands[0], operands[1], operands[2]));
> +   else
> +     {
> +      emit_insn (gen_mac (operands[1], operands[2]));
> +      emit_move_insn (operands[0], acc_reg);
> +     }
> +   DONE;
> +   }"
> +  [(set_attr "type" "multi")
> +   (set_attr "length" "36")])
> +
> +(define_insn "macd"
> +  [(set (match_operand:DI 0 "even_register_operand"	       "=Rcr,r,r")
> +	(plus:DI
> +	 (mult:DI
> +	  (sign_extend:DI (match_operand:SI 1 "register_operand" "%0,c,c"))
> +	  (sign_extend:DI (match_operand:SI 2 "extend_operand" " c,cI,Cal")))
> +	 (reg:DI ARCV2_ACC)))
> +   (set (reg:DI ARCV2_ACC)
> +	(plus:DI
> +	 (mult:DI (sign_extend:DI (match_dup 1))
> +		  (sign_extend:DI (match_dup 2)))
> +	 (reg:DI ARCV2_ACC)))]
> + "TARGET_PLUS_MACD"
> + "macd %0,%1,%2"
> +  [(set_attr "length" "4,4,8")
> +   (set_attr "type" "multi")
> +   (set_attr "predicable" "yes,no,no")
> +   (set_attr "cond" "canuse,nocond,nocond")])
> +
> +(define_insn "mac"
> +  [(set (reg:DI ARCV2_ACC)
> +	(plus:DI
> +	 (mult:DI (sign_extend:DI (match_operand:SI 0 "register_operand" "%r,r"))
> +		  (sign_extend:DI (match_operand:SI 1 "extend_operand" "rI,i")))
> +	 (reg:DI ARCV2_ACC)))]
> + "TARGET_PLUS_DMPY"
> + "mac 0,%0,%1"
> +  [(set_attr "length" "4,8")
> +   (set_attr "type" "multi")
> +   (set_attr "predicable" "no")
> +   (set_attr "cond" "nocond")])
> +
> +(define_peephole2
> +  [(set (reg:DI ARCV2_ACC)
> +	(plus:DI
> +	 (mult:DI (sign_extend:DI (match_operand:SI 0 "register_operand" ""))
> +		  (sign_extend:DI (match_operand:SI 1 "extend_operand" "")))
> +	 (reg:DI ARCV2_ACC)))
> +   (set (match_operand:SI 2 "register_operand" "")
> +	(match_operand:SI 3 "accl_operand" ""))]
> + "TARGET_PLUS_DMPY"
> + [(const_int 0)]
> + {
> +  emit_insn (gen_mac_r (operands[2], operands[0], operands[1]));
> +  DONE;
> + })
> +
> +(define_insn "mac_r"
> +  [(set (match_operand:SI 0 "register_operand" "=r,r")
> +	(truncate:SI
> +	 (plus:DI
> +	  (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%r,r"))
> +		   (sign_extend:DI (match_operand:SI 2 "extend_operand" "rI,i")))
> +	  (reg:DI ARCV2_ACC))))
> +   (clobber (reg:DI ARCV2_ACC))]
> + "TARGET_PLUS_DMPY"
> + "mac %0,%1,%2"
> +  [(set_attr "length" "4,8")
> +   (set_attr "type" "multi")
> +   (set_attr "predicable" "no")
> +   (set_attr "cond" "nocond")])
> +
> +(define_insn_and_split "umaddsidi4"
> +  [(set (match_operand:DI 0 "register_operand" "=r")
> +	(plus:DI
> +	 (mult:DI
> +	  (zero_extend:DI (match_operand:SI 1 "register_operand" "%r"))
> +	  (zero_extend:DI (match_operand:SI 2 "extend_operand" "ri")))
> +	 (match_operand:DI 3 "register_operand" "r")))]
> +  "TARGET_PLUS_DMPY"
> +  "#"
> +  "TARGET_PLUS_DMPY && reload_completed"
> +  [(const_int 0)]
> +  "{
> +   rtx acc_reg = gen_rtx_REG (DImode, ACC_REG_FIRST);
> +   emit_move_insn (acc_reg, operands[3]);
> +   if (TARGET_PLUS_MACD)
> +     emit_insn (gen_macdu (operands[0], operands[1], operands[2]));
> +   else
> +     {
> +      emit_insn (gen_macu (operands[1], operands[2]));
> +      emit_move_insn (operands[0], acc_reg);
> +     }
> +   DONE;
> +   }"
> +  [(set_attr "type" "multi")
> +   (set_attr "length" "36")])
> +
> +(define_insn "macdu"
> +  [(set (match_operand:DI 0 "even_register_operand"	       "=Rcr,r,r")
> +	(plus:DI
> +	 (mult:DI
> +	  (zero_extend:DI (match_operand:SI 1 "register_operand" "%0,c,c"))
> +	  (zero_extend:DI (match_operand:SI 2 "extend_operand" " c,cI,i")))
> +	 (reg:DI ARCV2_ACC)))
> +   (set (reg:DI ARCV2_ACC)
> +	(plus:DI
> +	 (mult:DI (zero_extend:DI (match_dup 1))
> +		  (zero_extend:DI (match_dup 2)))
> +	 (reg:DI ARCV2_ACC)))]
> + "TARGET_PLUS_MACD"
> + "macdu %0,%1,%2"
> +  [(set_attr "length" "4,4,8")
> +   (set_attr "type" "multi")
> +   (set_attr "predicable" "yes,no,no")
> +   (set_attr "cond" "canuse,nocond,nocond")])
> +
> +(define_insn "macu"
> +  [(set (reg:DI ARCV2_ACC)
> +	(plus:DI
> +	 (mult:DI (zero_extend:DI (match_operand:SI 0 "register_operand" "%r,r"))
> +		  (zero_extend:DI (match_operand:SI 1 "extend_operand" "rI,i")))
> +	 (reg:DI ARCV2_ACC)))]
> + "TARGET_PLUS_DMPY"
> + "macu 0,%0,%1"
> +  [(set_attr "length" "4,8")
> +   (set_attr "type" "multi")
> +   (set_attr "predicable" "no")
> +   (set_attr "cond" "nocond")])
> +
> +(define_peephole2
> +  [(set (reg:DI ARCV2_ACC)
> +	(plus:DI
> +	 (mult:DI (zero_extend:DI (match_operand:SI 0 "register_operand" ""))
> +		  (zero_extend:DI (match_operand:SI 1 "extend_operand" "")))
> +	 (reg:DI ARCV2_ACC)))
> +   (set (match_operand:SI 2 "register_operand" "")
> +	(match_operand:SI 3 "accl_operand" ""))]
> + "TARGET_PLUS_DMPY"
> + [(const_int 0)]
> + {
> +  emit_insn (gen_macu_r (operands[2], operands[0], operands[1]));
> +  DONE;
> + })
> +
> +(define_insn "macu_r"
> +  [(set (match_operand:SI 0 "register_operand" "=r,r")
> +	(truncate:SI
> +	 (plus:DI
> +	  (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%r,r"))
> +		   (zero_extend:DI (match_operand:SI 2 "extend_operand" "rI,i")))
> +	  (reg:DI ARCV2_ACC))))
> +   (clobber (reg:DI ARCV2_ACC))]
> + "TARGET_PLUS_DMPY"
> + "macu %0,%1,%2"
> +  [(set_attr "length" "4,8")
> +   (set_attr "type" "multi")
> +   (set_attr "predicable" "no")
> +   (set_attr "cond" "nocond")])
> +
> +(define_insn "mpyd_arcv2hs"
> +  [(set (match_operand:DI 0 "even_register_operand"			"=Rcr, r")
> +	(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand"	 "  0, c"))
> +		 (sign_extend:DI (match_operand:SI 2 "register_operand"	 "  c, c"))))
> +   (set (reg:DI ARCV2_ACC)
> +	(mult:DI
> +	  (sign_extend:DI (match_dup 1))
> +	  (sign_extend:DI (match_dup 2))))]
> +  "TARGET_PLUS_MACD"
> +  "mpyd%? %0,%1,%2"
> +  [(set_attr "length" "4,4")
> +  (set_attr "iscompact" "false")
> +  (set_attr "type" "multi")
> +  (set_attr "predicable" "yes,no")
> +  (set_attr "cond" "canuse,nocond")])
> +
> +(define_insn "mpyd_imm_arcv2hs"
> +  [(set (match_operand:DI 0 "even_register_operand"			"=Rcr, r,r,Rcr,	 r")
> +	(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand"	 "  0, c,0,  0,	 c"))
> +		 (match_operand 2		    "immediate_operand"	 "  L, L,I,Cal,Cal")))
> +   (set (reg:DI ARCV2_ACC)
> +	(mult:DI (sign_extend:DI (match_dup 1))
> +		 (match_dup 2)))]
> +  "TARGET_PLUS_MACD"
> +  "mpyd%? %0,%1,%2"
> +  [(set_attr "length" "4,4,4,8,8")
> +  (set_attr "iscompact" "false")
> +  (set_attr "type" "multi")
> +  (set_attr "predicable" "yes,no,no,yes,no")
> +  (set_attr "cond" "canuse,nocond,nocond,canuse_limm,nocond")])
> +
> +(define_insn "mpydu_arcv2hs"
> +  [(set (match_operand:DI 0 "even_register_operand"			"=Rcr, r")
> +	(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand"	 "  0, c"))
> +		 (zero_extend:DI (match_operand:SI 2 "register_operand" "   c, c"))))
> +   (set (reg:DI ARCV2_ACC)
> +	(mult:DI (zero_extend:DI (match_dup 1))
> +		 (zero_extend:DI (match_dup 2))))]
> +  "TARGET_PLUS_MACD"
> +  "mpydu%? %0,%1,%2"
> +  [(set_attr "length" "4,4")
> +  (set_attr "iscompact" "false")
> +  (set_attr "type" "multi")
> +  (set_attr "predicable" "yes,no")
> +  (set_attr "cond" "canuse,nocond")])
> +
> +(define_insn "mpydu_imm_arcv2hs"
> +  [(set (match_operand:DI 0 "even_register_operand"			"=Rcr, r,r,Rcr,	 r")
> +	(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand"	 "  0, c,0,  0,	 c"))
> +		 (match_operand 2		    "immediate_operand"	 "  L, L,I,Cal,Cal")))
> +   (set (reg:DI ARCV2_ACC)
> +	(mult:DI (zero_extend:DI (match_dup 1))
> +		 (match_dup 2)))]
> +  "TARGET_PLUS_MACD"
> +  "mpydu%? %0,%1,%2"
> +  [(set_attr "length" "4,4,4,8,8")
> +  (set_attr "iscompact" "false")
> +  (set_attr "type" "multi")
> +  (set_attr "predicable" "yes,no,no,yes,no")
> +  (set_attr "cond" "canuse,nocond,nocond,canuse_limm,nocond")])
> +
>  ;; include the arc-FPX instructions
>  (include "fpx.md")
>  
> diff --git a/gcc/config/arc/predicates.md b/gcc/config/arc/predicates.md
> index f4c2a80..7ddec91 100644
> --- a/gcc/config/arc/predicates.md
> +++ b/gcc/config/arc/predicates.md
> @@ -697,6 +697,11 @@
>    (and (match_code "reg")
>         (match_test "REGNO (op) == (TARGET_BIG_ENDIAN ? 58 : 59)")))
>  
> +(define_predicate "accl_operand"
> +  (and (match_code "reg")
> +       (match_test "REGNO (op) == (TARGET_BIG_ENDIAN ? 59 : 58)")
> +       (match_test "TARGET_V2")))
> +
>  ; Unfortunately, we can not allow a const_int_operand before reload, because
>  ; reload needs a non-void mode to guide it how to reload the inside of a
>  ; {sign_}extend.
> -- 
> 1.9.1
> 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* RE: [PATCH 1/2] Automatic context save/restore for regular interrupts.
  2017-05-08 14:50         ` Andrew Burgess
@ 2017-05-09 14:24           ` Claudiu Zissulescu
  0 siblings, 0 replies; 17+ messages in thread
From: Claudiu Zissulescu @ 2017-05-09 14:24 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gcc-patches, Francois.Bedard, sandra

Committed r247795 including the indicated fixes.

Thank you for your review,
Claudiu

^ permalink raw reply	[flat|nested] 17+ messages in thread

* RE: [PATCH 2/2] Fast interrupts support.
  2017-05-08 14:54         ` Andrew Burgess
@ 2017-05-09 14:25           ` Claudiu Zissulescu
  0 siblings, 0 replies; 17+ messages in thread
From: Claudiu Zissulescu @ 2017-05-09 14:25 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gcc-patches, Francois.Bedard, sandra

Committed r247796.

Thank you for your review,
Claudiu

^ permalink raw reply	[flat|nested] 17+ messages in thread

* RE: [PATCH 3/3] [ARC] Add support for advanced mpy/mac instructions.
  2017-05-08 15:10   ` Andrew Burgess
@ 2017-05-09 14:42     ` Claudiu Zissulescu
  0 siblings, 0 replies; 17+ messages in thread
From: Claudiu Zissulescu @ 2017-05-09 14:42 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gcc-patches, Francois.Bedard

Added two new tests. Committed r247797.

Thank you for your review,
Claudiu

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2017-05-09 14:25 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-04-25 13:06 [PATCH 0/3] [ARC] New features Claudiu Zissulescu
2017-04-25 13:21 ` [PATCH 3/3] [ARC] Add support for advanced mpy/mac instructions Claudiu Zissulescu
2017-05-08 15:10   ` Andrew Burgess
2017-05-09 14:42     ` Claudiu Zissulescu
2017-04-25 13:27 ` [PATCH 2/3] [ARC] Fast interrupts support Claudiu Zissulescu
2017-04-25 15:54   ` Sandra Loosemore
2017-04-26 13:14     ` Claudiu Zissulescu
2017-04-25 13:29 ` [PATCH 1/3] [ARC] Automatic context save/restore for regular interrupts Claudiu Zissulescu
2017-04-25 15:46   ` Sandra Loosemore
2017-04-26 13:15     ` Claudiu Zissulescu
2017-05-05 11:05     ` [PATCH 0/2] [ARC] New features (updated) Claudiu Zissulescu
2017-05-05 11:05       ` [PATCH 1/2] Automatic context save/restore for regular interrupts Claudiu Zissulescu
2017-05-08 14:50         ` Andrew Burgess
2017-05-09 14:24           ` Claudiu Zissulescu
2017-05-05 11:23       ` [PATCH 2/2] Fast interrupts support Claudiu Zissulescu
2017-05-08 14:54         ` Andrew Burgess
2017-05-09 14:25           ` Claudiu Zissulescu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).