diff options
author | Richard Henderson <rth@redhat.com> | 2011-01-17 10:16:39 -0800 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2011-01-17 10:16:39 -0800 |
commit | f033541c61c4d7ca041a52c842d9358841334017 (patch) | |
tree | 978d9ea1e829fea72f365f6ce5fa549a48d98f82 | |
parent | 34fee389ffbd4e8e5a262027b253ca09a54e0578 (diff) | |
download | gcc-f033541c61c4d7ca041a52c842d9358841334017.zip gcc-f033541c61c4d7ca041a52c842d9358841334017.tar.gz gcc-f033541c61c4d7ca041a52c842d9358841334017.tar.bz2 |
rx: Rewrite the bit manipulation patterns.
The patterns represented with ashift 1 canonically need to have
the ashift as the first operand of the logical operation.
Leave insv represented as a zero_extract store.
Implement a variable store to a 1 bit field as tst+bmne.
Implement a variable store of a condition into a 1 bit field with bmcc.
From-SVN: r168927
-rw-r--r-- | gcc/ChangeLog | 10 | ||||
-rw-r--r-- | gcc/config/rx/predicates.md | 4 | ||||
-rw-r--r-- | gcc/config/rx/rx-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/rx/rx.c | 42 | ||||
-rw-r--r-- | gcc/config/rx/rx.md | 207 |
5 files changed, 176 insertions, 88 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a58c1eb..4b6aa41 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,15 @@ 2011-01-17 Richard Henderson <rth@redhat.com> + * config/rx/predicates.md (rshift_operator): New. + * config/rx/rx.c (rx_expand_insv): Remove. + * config/rx/rx-protos.h: Update. + * config/rx/rx.md (*bitset): Rename from bitset. Swap the ashift + operand to the canonical position. + (*bitset_in_memory, *bitinvert, *bitinvert_in_memory): Similarly. + (*bitclr, *bitclr_in_memory): Similarly. + (*insv_imm, rx_insv_reg, *insv_cond, *bmcc, *insv_cond_lt): New. + (insv): Retain the zero_extract in the expansion. + * config/rx/rx.md (bswapsi2): Use = not + for output reload. (bswaphi2, bitinvert, revw): Likewise. diff --git a/gcc/config/rx/predicates.md b/gcc/config/rx/predicates.md index 0ab4df3..5ae5d22 100644 --- a/gcc/config/rx/predicates.md +++ b/gcc/config/rx/predicates.md @@ -310,3 +310,7 @@ (define_predicate "rx_fp_comparison_operator" (match_code "eq,ne,lt,ge,ordered,unordered,uneq,unlt,unge,ltgt") ) + +(define_predicate "rshift_operator" + (match_code "ashiftrt,lshiftrt") +) diff --git a/gcc/config/rx/rx-protos.h b/gcc/config/rx/rx-protos.h index 9bb76b2..3c3f2d4 100644 --- a/gcc/config/rx/rx-protos.h +++ b/gcc/config/rx/rx-protos.h @@ -33,7 +33,6 @@ extern int rx_initial_elimination_offset (int, int); extern void rx_emit_stack_popm (rtx *, bool); extern void rx_emit_stack_pushm (rtx *); extern void rx_expand_epilogue (bool); -extern bool rx_expand_insv (rtx *); extern char * rx_gen_move_template (rtx *, bool); extern bool rx_is_legitimate_constant (rtx); extern bool rx_is_mode_dependent_addr (rtx); diff --git a/gcc/config/rx/rx.c b/gcc/config/rx/rx.c index 16646aeb..8cc46e7 100644 --- a/gcc/config/rx/rx.c +++ b/gcc/config/rx/rx.c @@ -2339,48 +2339,6 @@ rx_is_ms_bitfield_layout (const_tree record_type ATTRIBUTE_UNUSED) /* The packed attribute overrides the MS behaviour. */ return ! TYPE_PACKED (record_type); } - -/* Try to generate code for the "isnv" pattern which inserts bits - into a word. - operands[0] => Location to be altered. - operands[1] => Number of bits to change. - operands[2] => Starting bit. - operands[3] => Value to insert. - Returns TRUE if successful, FALSE otherwise. */ - -bool -rx_expand_insv (rtx * operands) -{ - if (INTVAL (operands[1]) != 1 - || ! CONST_INT_P (operands[3])) - return false; - - if (MEM_P (operands[0]) - && INTVAL (operands[2]) > 7) - return false; - - switch (INTVAL (operands[3])) - { - case 0: - if (MEM_P (operands[0])) - emit_insn (gen_bitclr_in_memory (operands[0], operands[0], - operands[2])); - else - emit_insn (gen_bitclr (operands[0], operands[0], operands[2])); - break; - case 1: - case -1: - if (MEM_P (operands[0])) - emit_insn (gen_bitset_in_memory (operands[0], operands[0], - operands[2])); - else - emit_insn (gen_bitset (operands[0], operands[0], operands[2])); - break; - default: - return false; - } - return true; -} /* Returns true if X a legitimate constant for an immediate operand on the RX. X is already known to satisfy CONSTANT_P. */ diff --git a/gcc/config/rx/rx.md b/gcc/config/rx/rx.md index 864b4a5..7fa8668 100644 --- a/gcc/config/rx/rx.md +++ b/gcc/config/rx/rx.md @@ -1518,91 +1518,208 @@ ) ;; Bit manipulation instructions. -;; Note - there are two versions of each pattern because the memory -;; accessing versions use QImode whilst the register accessing -;; versions use SImode. -;; The peephole are here because the combiner only looks at a maximum -;; of three instructions at a time. -(define_insn "bitset" +;; ??? The *_in_memory patterns will not be matched without further help. +;; At one time we had the insv expander generate them, but I suspect that +;; in general we get better performance by exposing the register load to +;; the optimizers. +;; +;; An alternate solution would be to re-organize these patterns such +;; that allow both register and memory operands. This would allow the +;; register allocator to spill and not load the register operand. This +;; would be possible only for operations for which we have a constant +;; bit offset, so that we can adjust the address by ofs/8 and replace +;; the offset in the insn by ofs%8. + +(define_insn "*bitset" [(set (match_operand:SI 0 "register_operand" "=r") - (ior:SI (match_operand:SI 1 "register_operand" "0") - (ashift:SI (const_int 1) - (match_operand:SI 2 "nonmemory_operand" "ri"))))] + (ior:SI (ashift:SI (const_int 1) + (match_operand:SI 1 "rx_shift_operand" "ri")) + (match_operand:SI 2 "register_operand" "0")))] "" - "bset\t%2, %0" + "bset\t%1, %0" [(set_attr "length" "3")] ) -(define_insn "bitset_in_memory" - [(set (match_operand:QI 0 "memory_operand" "=m") - (ior:QI (match_operand:QI 1 "memory_operand" "0") - (ashift:QI (const_int 1) - (match_operand:QI 2 "nonmemory_operand" "ri"))))] +(define_insn "*bitset_in_memory" + [(set (match_operand:QI 0 "memory_operand" "+Q") + (ior:QI (ashift:QI (const_int 1) + (match_operand:QI 1 "nonmemory_operand" "ri")) + (match_dup 0)))] "" - "bset\t%2, %0.B" + "bset\t%1, %0.B" [(set_attr "length" "3") (set_attr "timings" "34")] ) (define_insn "*bitinvert" [(set (match_operand:SI 0 "register_operand" "=r") - (xor:SI (match_operand:SI 1 "register_operand" "0") - (ashift:SI (const_int 1) - (match_operand:SI 2 "nonmemory_operand" "ri"))))] + (xor:SI (ashift:SI (const_int 1) + (match_operand:SI 1 "rx_shift_operand" "ri")) + (match_operand:SI 2 "register_operand" "0")))] "" - "bnot\t%2, %0" + "bnot\t%1, %0" [(set_attr "length" "3")] ) -(define_insn "bitinvert_in_memory" - [(set (match_operand:QI 0 "memory_operand" "+m") - (xor:QI (match_operand:QI 1 "register_operand" "0") - (ashift:QI (const_int 1) - (match_operand:QI 2 "nonmemory_operand" "ri"))))] +(define_insn "*bitinvert_in_memory" + [(set (match_operand:QI 0 "memory_operand" "+Q") + (xor:QI (ashift:QI (const_int 1) + (match_operand:QI 1 "nonmemory_operand" "ri")) + (match_dup 0)))] "" - "bnot\t%2, %0.B" + "bnot\t%1, %0.B" [(set_attr "length" "5") (set_attr "timings" "33")] ) -(define_insn "bitclr" +(define_insn "*bitclr" [(set (match_operand:SI 0 "register_operand" "=r") - (and:SI (match_operand:SI 1 "register_operand" "0") - (not:SI + (and:SI (not:SI (ashift:SI (const_int 1) - (match_operand:SI 2 "nonmemory_operand" "ri")))))] + (match_operand:SI 1 "rx_shift_operand" "ri"))) + (match_operand:SI 2 "register_operand" "0")))] "" - "bclr\t%2, %0" + "bclr\t%1, %0" [(set_attr "length" "3")] ) -(define_insn "bitclr_in_memory" - [(set (match_operand:QI 0 "memory_operand" "=m") - (and:QI (match_operand:QI 1 "memory_operand" "0") - (not:QI +(define_insn "*bitclr_in_memory" + [(set (match_operand:QI 0 "memory_operand" "+Q") + (and:QI (not:QI (ashift:QI (const_int 1) - (match_operand:QI 2 "nonmemory_operand" "ri")))))] + (match_operand:QI 1 "nonmemory_operand" "ri"))) + (match_dup 0)))] "" - "bclr\t%2, %0.B" + "bclr\t%1, %0.B" [(set_attr "length" "3") (set_attr "timings" "34")] ) +(define_insn "*insv_imm" + [(set (zero_extract:SI + (match_operand:SI 0 "register_operand" "+r") + (const_int 1) + (match_operand:SI 1 "rx_shift_operand" "ri")) + (match_operand:SI 2 "const_int_operand" ""))] + "" +{ + if (INTVAL (operands[2]) & 1) + return "bset\t%1, %0"; + else + return "bclr\t%1, %0"; +} + [(set_attr "length" "3")] +) + +(define_insn_and_split "rx_insv_reg" + [(set (zero_extract:SI + (match_operand:SI 0 "register_operand" "+r") + (const_int 1) + (match_operand:SI 1 "const_int_operand" "")) + (match_operand:SI 2 "register_operand" "r")) + (clobber (reg:CC CC_REG))] + "" + "#" + "reload_completed" + [(set (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1)) + (match_dup 3))] +{ + rtx flags, x; + + /* Emit tst #1, op2. */ + flags = gen_rtx_REG (CC_ZSmode, CC_REG); + x = gen_rtx_AND (SImode, operands[2], const1_rtx); + x = gen_rtx_COMPARE (CC_ZSmode, x, const0_rtx); + x = gen_rtx_SET (VOIDmode, flags, x); + emit_insn (x); + + /* Emit bmne. */ + operands[3] = gen_rtx_NE (SImode, flags, const0_rtx); +}) + +(define_insn_and_split "*insv_cond" + [(set (zero_extract:SI + (match_operand:SI 0 "register_operand" "+r") + (const_int 1) + (match_operand:SI 1 "const_int_operand" "")) + (match_operator:SI 4 "comparison_operator" + [(match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "rx_source_operand" "riQ")])) + (clobber (reg:CC CC_REG))] + "" + "#" + "reload_completed" + [(set (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1)) + (match_dup 4))] +{ + rtx flags, x; + + flags = gen_rtx_REG (CCmode, CC_REG); + x = gen_rtx_COMPARE (CCmode, operands[2], operands[3]); + x = gen_rtx_SET (VOIDmode, flags, x); + emit_insn (x); + + operands[4] = gen_rtx_fmt_ee (GET_CODE (operands[4]), SImode, + flags, const0_rtx); +}) + +(define_insn "*bmcc" + [(set (zero_extract:SI + (match_operand:SI 0 "register_operand" "+r") + (const_int 1) + (match_operand:SI 1 "const_int_operand" "")) + (match_operator:SI 2 "comparison_operator" + [(reg CC_REG) (const_int 0)]))] + "reload_completed" + "bm%B2\t%1, %0" + [(set_attr "length" "3")] +) + +;; Work around the fact that X=Y<0 is preferentially expanded as a shift. +(define_insn_and_split "*insv_cond_lt" + [(set (zero_extract:SI + (match_operand:SI 0 "register_operand" "+r") + (const_int 1) + (match_operand:SI 1 "const_int_operand" "")) + (match_operator:SI 3 "rshift_operator" + [(match_operand:SI 2 "register_operand" "r") + (const_int 31)])) + (clobber (reg:CC CC_REG))] + "" + "#" + "" + [(parallel [(set (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1)) + (lt:SI (match_dup 2) (const_int 0))) + (clobber (reg:CC CC_REG))])] + "" +) + (define_expand "insv" - [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand") ;; Destination - (match_operand 1 "immediate_operand") ;; # of bits to set - (match_operand 2 "immediate_operand")) ;; Starting bit - (match_operand 3 "immediate_operand"))] ;; Bits to insert + [(set (zero_extract:SI + (match_operand:SI 0 "register_operand") ;; Destination + (match_operand:SI 1 "const_int_operand") ;; # of bits to set + (match_operand:SI 2 "nonmemory_operand")) ;; Starting bit + (match_operand:SI 3 "nonmemory_operand"))] ;; Bits to insert "" - { - if (rx_expand_insv (operands)) +{ + /* We only handle single-bit inserts. */ + if (!CONST_INT_P (operands[1]) || INTVAL (operands[1]) != 1) + FAIL; + + /* Either the bit to insert or the position must be constant. */ + if (CONST_INT_P (operands[3])) + operands[3] = GEN_INT (INTVAL (operands[3]) & 1); + else if (CONST_INT_P (operands[2])) + { + emit_insn (gen_rx_insv_reg (operands[0], operands[2], operands[3])); DONE; + } + else FAIL; - } -) +}) ;; Atomic exchange operation. |