Commit f033541c by Richard Henderson Committed by Richard Henderson

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
parent 34fee389
2011-01-17 Richard Henderson <rth@redhat.com> 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. * config/rx/rx.md (bswapsi2): Use = not + for output reload.
(bswaphi2, bitinvert, revw): Likewise. (bswaphi2, bitinvert, revw): Likewise.
......
...@@ -310,3 +310,7 @@ ...@@ -310,3 +310,7 @@
(define_predicate "rx_fp_comparison_operator" (define_predicate "rx_fp_comparison_operator"
(match_code "eq,ne,lt,ge,ordered,unordered,uneq,unlt,unge,ltgt") (match_code "eq,ne,lt,ge,ordered,unordered,uneq,unlt,unge,ltgt")
) )
(define_predicate "rshift_operator"
(match_code "ashiftrt,lshiftrt")
)
...@@ -33,7 +33,6 @@ extern int rx_initial_elimination_offset (int, int); ...@@ -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_popm (rtx *, bool);
extern void rx_emit_stack_pushm (rtx *); extern void rx_emit_stack_pushm (rtx *);
extern void rx_expand_epilogue (bool); extern void rx_expand_epilogue (bool);
extern bool rx_expand_insv (rtx *);
extern char * rx_gen_move_template (rtx *, bool); extern char * rx_gen_move_template (rtx *, bool);
extern bool rx_is_legitimate_constant (rtx); extern bool rx_is_legitimate_constant (rtx);
extern bool rx_is_mode_dependent_addr (rtx); extern bool rx_is_mode_dependent_addr (rtx);
......
...@@ -2339,48 +2339,6 @@ rx_is_ms_bitfield_layout (const_tree record_type ATTRIBUTE_UNUSED) ...@@ -2339,48 +2339,6 @@ rx_is_ms_bitfield_layout (const_tree record_type ATTRIBUTE_UNUSED)
/* The packed attribute overrides the MS behaviour. */ /* The packed attribute overrides the MS behaviour. */
return ! TYPE_PACKED (record_type); 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 /* Returns true if X a legitimate constant for an immediate
operand on the RX. X is already known to satisfy CONSTANT_P. */ operand on the RX. X is already known to satisfy CONSTANT_P. */
......
...@@ -1518,91 +1518,208 @@ ...@@ -1518,91 +1518,208 @@
) )
;; Bit manipulation instructions. ;; 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") [(set (match_operand:SI 0 "register_operand" "=r")
(ior:SI (match_operand:SI 1 "register_operand" "0") (ior:SI (ashift:SI (const_int 1)
(ashift:SI (const_int 1) (match_operand:SI 1 "rx_shift_operand" "ri"))
(match_operand:SI 2 "nonmemory_operand" "ri"))))] (match_operand:SI 2 "register_operand" "0")))]
"" ""
"bset\t%2, %0" "bset\t%1, %0"
[(set_attr "length" "3")] [(set_attr "length" "3")]
) )
(define_insn "bitset_in_memory" (define_insn "*bitset_in_memory"
[(set (match_operand:QI 0 "memory_operand" "=m") [(set (match_operand:QI 0 "memory_operand" "+Q")
(ior:QI (match_operand:QI 1 "memory_operand" "0") (ior:QI (ashift:QI (const_int 1)
(ashift:QI (const_int 1) (match_operand:QI 1 "nonmemory_operand" "ri"))
(match_operand:QI 2 "nonmemory_operand" "ri"))))] (match_dup 0)))]
"" ""
"bset\t%2, %0.B" "bset\t%1, %0.B"
[(set_attr "length" "3") [(set_attr "length" "3")
(set_attr "timings" "34")] (set_attr "timings" "34")]
) )
(define_insn "*bitinvert" (define_insn "*bitinvert"
[(set (match_operand:SI 0 "register_operand" "=r") [(set (match_operand:SI 0 "register_operand" "=r")
(xor:SI (match_operand:SI 1 "register_operand" "0") (xor:SI (ashift:SI (const_int 1)
(ashift:SI (const_int 1) (match_operand:SI 1 "rx_shift_operand" "ri"))
(match_operand:SI 2 "nonmemory_operand" "ri"))))] (match_operand:SI 2 "register_operand" "0")))]
"" ""
"bnot\t%2, %0" "bnot\t%1, %0"
[(set_attr "length" "3")] [(set_attr "length" "3")]
) )
(define_insn "bitinvert_in_memory" (define_insn "*bitinvert_in_memory"
[(set (match_operand:QI 0 "memory_operand" "+m") [(set (match_operand:QI 0 "memory_operand" "+Q")
(xor:QI (match_operand:QI 1 "register_operand" "0") (xor:QI (ashift:QI (const_int 1)
(ashift:QI (const_int 1) (match_operand:QI 1 "nonmemory_operand" "ri"))
(match_operand:QI 2 "nonmemory_operand" "ri"))))] (match_dup 0)))]
"" ""
"bnot\t%2, %0.B" "bnot\t%1, %0.B"
[(set_attr "length" "5") [(set_attr "length" "5")
(set_attr "timings" "33")] (set_attr "timings" "33")]
) )
(define_insn "bitclr" (define_insn "*bitclr"
[(set (match_operand:SI 0 "register_operand" "=r") [(set (match_operand:SI 0 "register_operand" "=r")
(and:SI (match_operand:SI 1 "register_operand" "0") (and:SI (not:SI
(not:SI
(ashift:SI (ashift:SI
(const_int 1) (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")] [(set_attr "length" "3")]
) )
(define_insn "bitclr_in_memory" (define_insn "*bitclr_in_memory"
[(set (match_operand:QI 0 "memory_operand" "=m") [(set (match_operand:QI 0 "memory_operand" "+Q")
(and:QI (match_operand:QI 1 "memory_operand" "0") (and:QI (not:QI
(not:QI
(ashift:QI (ashift:QI
(const_int 1) (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 "length" "3")
(set_attr "timings" "34")] (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" (define_expand "insv"
[(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand") ;; Destination [(set (zero_extract:SI
(match_operand 1 "immediate_operand") ;; # of bits to set (match_operand:SI 0 "register_operand") ;; Destination
(match_operand 2 "immediate_operand")) ;; Starting bit (match_operand:SI 1 "const_int_operand") ;; # of bits to set
(match_operand 3 "immediate_operand"))] ;; Bits to insert (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; DONE;
}
else
FAIL; FAIL;
} })
)
;; Atomic exchange operation. ;; Atomic exchange operation.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment