+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
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);
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));
/* 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");
/* 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");
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
(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.