From 927d22fa017bb0bdfcb221e64f13b4e548f697aa Mon Sep 17 00:00:00 2001 From: Oleg Endo Date: Tue, 10 May 2016 12:53:44 +0000 Subject: [PATCH] Add rudimentary support for atomics on RX. 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, atomic_exchangesi, xchg_mem, atomic_fetch_si, atomic_fetch_nandsi, atomic__fetchsi, atomic_nand_fetchsi): New patterns. From-SVN: r236075 --- gcc/ChangeLog | 20 ++++++ gcc/config/rx/rx-protos.h | 22 ++++++ gcc/config/rx/rx.c | 45 +++++++++--- gcc/config/rx/rx.md | 142 +++++++++++++++++++++++++++++++++++++- 4 files changed, 217 insertions(+), 12 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 38b3869bce2..fa23868f340 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,23 @@ +2016-05-10 Oleg Endo + + * 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, atomic_exchangesi, xchg_mem, + atomic_fetch_si, atomic_fetch_nandsi, + atomic__fetchsi, atomic_nand_fetchsi): New patterns. + 2016-05-10 Martin Liska * tree-inline.c (remap_dependence_clique): Do not remap diff --git a/gcc/config/rx/rx-protos.h b/gcc/config/rx/rx-protos.h index 160b9cce4aa..771528b3dd5 100644 --- a/gcc/config/rx/rx-protos.h +++ b/gcc/config/rx/rx-protos.h @@ -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); diff --git a/gcc/config/rx/rx.c b/gcc/config/rx/rx.c index 3a374a01c70..8dfc8856abe 100644 --- a/gcc/config/rx/rx.c +++ b/gcc/config/rx/rx.c @@ -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)); +} + #undef TARGET_NARROW_VOLATILE_BITFIELD #define TARGET_NARROW_VOLATILE_BITFIELD rx_narrow_volatile_bitfield diff --git a/gcc/config/rx/rx.md b/gcc/config/rx/rx.md index 787c37bc967..9af16828b8c 100644 --- a/gcc/config/rx/rx.md +++ b/gcc/config/rx/rx.md @@ -75,6 +75,16 @@ (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) ] ) @@ -2145,7 +2155,17 @@ FAIL; }) -;; 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") @@ -2157,6 +2177,126 @@ [(set_attr "length" "3,6") (set_attr "timings" "22")] ) + +(define_expand "atomic_exchange" + [(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 (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" + [(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_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_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__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_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; +}); + ;; Block move functions. -- 2.30.2