Add rudimentary support for atomics on RX.
authorOleg Endo <olegendo@gcc.gnu.org>
Tue, 10 May 2016 12:53:44 +0000 (12:53 +0000)
committerOleg Endo <olegendo@gcc.gnu.org>
Tue, 10 May 2016 12:53:44 +0000 (12:53 +0000)
Add rudimentary support for atomics on RX.  It is implemented by flipping
interrupts off/on around the atomic sequences.

gcc/
* config/rx/rx-protos.h (is_interrupt_func, is_fast_interrupt_func):
Forward declare.
(rx_atomic_sequence): New class.
* config/rx/rx.c (rx_print_operand): Use symbolic names for PSW bits.
(is_interrupt_func, is_fast_interrupt_func): Make non-static and
non-inline.
(rx_atomic_sequence::rx_atomic_sequence,
rx_atomic_sequence::~rx_atomic_sequence): New functions.
* config/rx/rx.md (CTRLREG_PSW, CTRLREG_USP, CTRLREG_FPSW, CTRLREG_CPEN,
CTRLREG_BPSW, CTRLREG_BPC, CTRLREG_ISP, CTRLREG_FINTV,
CTRLREG_INTB): New constants.
(FETCHOP): New code iterator.
(fethcop_name, fetchop_name2): New iterator code attributes.
(QIHI): New mode iterator.
(atomic_exchange<mode>, atomic_exchangesi, xchg_mem<mode>,
atomic_fetch_<fetchop_name>si, atomic_fetch_nandsi,
atomic_<fetchop_name>_fetchsi, atomic_nand_fetchsi): New patterns.

From-SVN: r236075

gcc/ChangeLog
gcc/config/rx/rx-protos.h
gcc/config/rx/rx.c
gcc/config/rx/rx.md

index 38b3869bce20cc9f649c5e2a9ed13a2aa3fc7580..fa23868f340d00d071b19aba116f0c69b0c98b6d 100644 (file)
@@ -1,3 +1,23 @@
+2016-05-10  Oleg Endo  <olegendo@gcc.gnu.org>
+
+       * config/rx/rx-protos.h (is_interrupt_func, is_fast_interrupt_func):
+       Forward declare.
+       (rx_atomic_sequence): New class.
+       * config/rx/rx.c (rx_print_operand): Use symbolic names for PSW bits.
+       (is_interrupt_func, is_fast_interrupt_func): Make non-static and
+       non-inline.
+       (rx_atomic_sequence::rx_atomic_sequence,
+       rx_atomic_sequence::~rx_atomic_sequence): New functions.
+       * config/rx/rx.md (CTRLREG_PSW, CTRLREG_USP, CTRLREG_FPSW, CTRLREG_CPEN,
+       CTRLREG_BPSW, CTRLREG_BPC, CTRLREG_ISP, CTRLREG_FINTV,
+       CTRLREG_INTB): New constants.
+       (FETCHOP): New code iterator.
+       (fethcop_name, fetchop_name2): New iterator code attributes.
+       (QIHI): New mode iterator.
+       (atomic_exchange<mode>, atomic_exchangesi, xchg_mem<mode>,
+       atomic_fetch_<fetchop_name>si, atomic_fetch_nandsi,
+       atomic_<fetchop_name>_fetchsi, atomic_nand_fetchsi): New patterns.
+
 2016-05-10  Martin Liska  <mliska@suse.cz>
 
        * tree-inline.c (remap_dependence_clique): Do not remap
index 160b9cce4aac81e6fbc3c4f708ae6a492a708a2c..771528b3dd55cf5da4a6e9760a369de898ba1d64 100644 (file)
@@ -26,6 +26,28 @@ extern void          rx_expand_epilogue (bool);
 extern void            rx_expand_prologue (void);
 extern int             rx_initial_elimination_offset (int, int);
 
+bool is_interrupt_func (const_tree decl);
+bool is_fast_interrupt_func (const_tree decl);
+
+/* rx_atomic_sequence is used to emit the header and footer
+   of an atomic sequence.  It's supposed to be used in a scope.
+   When constructed, it will emit the atomic sequence header insns.
+   When destructred (goes out of scope), it will emit the
+   corresponding atomic sequence footer insns.  */
+class rx_atomic_sequence
+{
+public:
+  rx_atomic_sequence (const_tree fun_decl);
+  ~rx_atomic_sequence (void);
+
+private:
+  rx_atomic_sequence (void);
+  rx_atomic_sequence (const rx_atomic_sequence&);
+  rx_atomic_sequence& operator = (const rx_atomic_sequence&);
+
+  rtx m_prev_psw_reg;
+};
+
 #ifdef RTX_CODE
 extern int             rx_adjust_insn_length (rtx_insn *, int);
 extern int             rx_align_for_label (rtx, int);
index 3a374a01c70a1e2f3625a234aacfd64a918c6dd8..8dfc8856abe542cd554169a7bb5d0dababbd2cb9 100644 (file)
@@ -630,15 +630,15 @@ rx_print_operand (FILE * file, rtx op, int letter)
       gcc_assert (CONST_INT_P (op));
       switch (INTVAL (op))
        {
-       case 0:   fprintf (file, "psw"); break;
-       case 2:   fprintf (file, "usp"); break;
-       case 3:   fprintf (file, "fpsw"); break;
-       case 4:   fprintf (file, "cpen"); break;
-       case 8:   fprintf (file, "bpsw"); break;
-       case 9:   fprintf (file, "bpc"); break;
-       case 0xa: fprintf (file, "isp"); break;
-       case 0xb: fprintf (file, "fintv"); break;
-       case 0xc: fprintf (file, "intb"); break;
+       case CTRLREG_PSW:   fprintf (file, "psw"); break;
+       case CTRLREG_USP:   fprintf (file, "usp"); break;
+       case CTRLREG_FPSW:  fprintf (file, "fpsw"); break;
+       case CTRLREG_CPEN:  fprintf (file, "cpen"); break;
+       case CTRLREG_BPSW:  fprintf (file, "bpsw"); break;
+       case CTRLREG_BPC:   fprintf (file, "bpc"); break;
+       case CTRLREG_ISP:   fprintf (file, "isp"); break;
+       case CTRLREG_FINTV: fprintf (file, "fintv"); break;
+       case CTRLREG_INTB:  fprintf (file, "intb"); break;
        default:
          warning (0, "unrecognized control register number: %d - using 'psw'",
                   (int) INTVAL (op));
@@ -1216,7 +1216,7 @@ has_func_attr (const_tree decl, const char * func_attr)
 
 /* Returns true if the provided function has the "fast_interrupt" attribute.  */
 
-static inline bool
+bool
 is_fast_interrupt_func (const_tree decl)
 {
   return has_func_attr (decl, "fast_interrupt");
@@ -1224,7 +1224,7 @@ is_fast_interrupt_func (const_tree decl)
 
 /* Returns true if the provided function has the "interrupt" attribute.  */
 
-static inline bool
+bool
 is_interrupt_func (const_tree decl)
 {
   return has_func_attr (decl, "interrupt");
@@ -3409,6 +3409,29 @@ rx_enable_lra (void)
   return TARGET_ENABLE_LRA;
 }
 
+rx_atomic_sequence::rx_atomic_sequence (const_tree fun_decl)
+{
+  if (is_fast_interrupt_func (fun_decl) || is_interrupt_func (fun_decl))
+    {
+      /* If we are inside an interrupt handler, assume that interrupts are
+        off -- which is the default hardware behavior.  In this case, there
+        is no need to disable the interrupts.  */
+      m_prev_psw_reg = NULL;
+    }
+  else
+    {
+      m_prev_psw_reg = gen_reg_rtx (SImode);
+      emit_insn (gen_mvfc (m_prev_psw_reg, GEN_INT (CTRLREG_PSW)));
+      emit_insn (gen_clrpsw (GEN_INT ('I')));
+    }
+}
+
+rx_atomic_sequence::~rx_atomic_sequence (void)
+{
+  if (m_prev_psw_reg != NULL)
+    emit_insn (gen_mvtc (GEN_INT (CTRLREG_PSW), m_prev_psw_reg));
+}
+
 \f
 #undef  TARGET_NARROW_VOLATILE_BITFIELD
 #define TARGET_NARROW_VOLATILE_BITFIELD                rx_narrow_volatile_bitfield
index 787c37bc96792a831f39ab68685640990af61d85..9af16828b8cb29142895d2597613f3c727fa5180 100644 (file)
    (UNSPEC_BUILTIN_WAIT           51)
 
    (UNSPEC_PID_ADDR       52)
+
+   (CTRLREG_PSW                    0)
+   (CTRLREG_USP                    2)
+   (CTRLREG_FPSW           3)
+   (CTRLREG_CPEN           4)
+   (CTRLREG_BPSW           8)
+   (CTRLREG_BPC                    9)
+   (CTRLREG_ISP                   10)
+   (CTRLREG_FINTV         11)
+   (CTRLREG_INTB          12)
   ]
 )
 
     FAIL;
 })
 \f
-;; Atomic exchange operation.
+;; Atomic operations.
+
+(define_code_iterator FETCHOP [plus minus ior xor and])
+
+(define_code_attr fetchop_name
+  [(plus "add") (minus "sub") (ior "or") (xor "xor") (and "and")])
+
+(define_code_attr fetchop_name2
+  [(plus "add") (minus "sub") (ior "ior") (xor "xor") (and "and")])
+
+(define_mode_iterator QIHI [QI HI])
 
 (define_insn "sync_lock_test_and_setsi"
   [(set (match_operand:SI 0 "register_operand"   "=r,r")
   [(set_attr "length" "3,6")
    (set_attr "timings" "22")]
 )
+
+(define_expand "atomic_exchange<mode>"
+  [(match_operand:QIHI 0 "register_operand")           ;; oldval output
+   (match_operand:QIHI 1 "rx_restricted_mem_operand")  ;; memory
+   (match_operand:QIHI 2 "register_operand")           ;; newval input
+   (match_operand:QIHI 3 "const_int_operand")]         ;; memory model
+  ""
+{
+  emit_insn (gen_xchg_mem<mode> (operands[0], operands[1], operands[2]));
+  DONE;
+})
+
+(define_expand "atomic_exchangesi"
+  [(match_operand:SI 0 "register_operand")             ;; oldval output
+   (match_operand:SI 1 "rx_restricted_mem_operand")    ;; memory
+   (match_operand:SI 2 "register_operand")             ;; newval input
+   (match_operand:SI 3 "const_int_operand")]           ;; memory model
+  ""
+{
+  emit_insn (gen_sync_lock_test_and_setsi (operands[0], operands[1],
+                                          operands[2]));
+  DONE;
+})
+
+(define_insn "xchg_mem<mode>"
+  [(set (match_operand:QIHI 0 "register_operand"   "=r")
+       (match_operand:QIHI 1 "rx_compare_operand" "=Q"))
+   (set (match_dup 1)
+       (match_operand:QIHI 2 "register_operand"    "0"))]
+  ""
+  "xchg\t%1, %0"
+  [(set_attr "length" "6")
+   (set_attr "timings" "22")]
+)
+
+;; read - modify - write - return old value
+(define_expand "atomic_fetch_<fetchop_name>si"
+  [(set (match_operand:SI 0 "register_operand")
+       (match_operand:SI 1 "memory_operand"))
+   (set (match_dup 1)
+       (FETCHOP:SI (match_dup 1) (match_operand:SI 2 "rx_source_operand")))
+   (match_operand:SI 3 "const_int_operand")]           ;; memory model
+  ""
+{
+  {
+    rx_atomic_sequence seq (current_function_decl);
+
+    emit_move_insn (operands[0], operands[1]);
+
+    rtx tmp = gen_reg_rtx (SImode);
+    emit_insn (gen_<fetchop_name2>si3 (tmp, operands[0], operands[2]));
+
+    emit_move_insn (operands[1], tmp);
+  }
+  DONE;
+})
+
+(define_expand "atomic_fetch_nandsi"
+  [(set (match_operand:SI 0 "register_operand")
+       (match_operand:SI 1 "memory_operand"))
+   (set (match_dup 1)
+       (not:SI (and:SI (match_dup 1)
+                       (match_operand:SI 2 "rx_source_operand"))))
+   (match_operand:SI 3 "const_int_operand")]           ;; memory model
+  ""
+{
+  {
+    rx_atomic_sequence seq (current_function_decl);
+
+    emit_move_insn (operands[0], operands[1]);
+
+    rtx tmp = gen_reg_rtx (SImode);
+    emit_insn (gen_andsi3 (tmp, operands[0], operands[2]));
+    emit_insn (gen_one_cmplsi2 (tmp, tmp));
+
+    emit_move_insn (operands[1], tmp);
+  }
+  DONE;
+})
+
+;; read - modify - write - return new value
+(define_expand "atomic_<fetchop_name>_fetchsi"
+  [(set (match_operand:SI 0 "register_operand")
+       (FETCHOP:SI (match_operand:SI 1 "rx_restricted_mem_operand")
+                   (match_operand:SI 2 "register_operand")))
+   (set (match_dup 1)
+       (FETCHOP:SI (match_dup 1) (match_dup 2)))
+   (match_operand:SI 3 "const_int_operand")]           ;; memory model
+  ""
+{
+  {
+    rx_atomic_sequence seq (current_function_decl);
+
+    emit_move_insn (operands[0], operands[2]);
+    emit_insn (gen_<fetchop_name2>si3 (operands[0], operands[0], operands[1]));
+    emit_move_insn (operands[1], operands[0]);
+  }
+  DONE;
+})
+
+(define_expand "atomic_nand_fetchsi"
+  [(set (match_operand:SI 0 "register_operand")
+       (not:SI (and:SI (match_operand:SI 1 "rx_restricted_mem_operand")
+                       (match_operand:SI 2 "register_operand"))))
+   (set (match_dup 1)
+       (not:SI (and:SI (match_dup 1) (match_dup 2))))
+   (match_operand:SI 3 "const_int_operand")]           ;; memory model
+  ""
+{
+  {
+    rx_atomic_sequence seq (current_function_decl);
+
+    emit_move_insn (operands[0], operands[2]);
+    emit_insn (gen_andsi3 (operands[0], operands[0], operands[1]));
+    emit_insn (gen_one_cmplsi2 (operands[0], operands[0]));
+    emit_move_insn (operands[1], operands[0]);
+  }
+  DONE;
+});
+
 \f
 ;; Block move functions.