This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[patch] Add TST to RX
- From: DJ Delorie <dj at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Paolo Bonzini <bonzini at gnu dot org>, Nick Clifton <nickc at redhat dot com>
- Date: Tue, 13 Jul 2010 22:17:51 -0400
- Subject: [patch] Add TST to RX
This patch adds support for the TST opcode to the RX target. The
first two patterns are the real patterns; the rest are other ways that
gcc handles "a & const", they're converted to one of the first two
forms. Paolo: if you replace the "return 0;" in the rtlanal.c chunk
with an abort(), you can see where the zero_extend comes from. GCC
uses that for single-bit tests other than bit 0.
Ok to apply?
* rtlanal.c (canonicalize_condition): Exit early if we're passed
something other than a condition.
* config/rx/predicates.md (rx_constshift_operand): New.
(rx_onebit_operand): New.
* config/rx/rx.md (zs_cond): New.
(*tstbranchsi4_<code>): New.
(*tstbranchsi4_<code>): New.
(*tstbranchsi4b_eq): New.
(*tstbranchsi4m_eq): New.
(*tstbranchsi4m_ne): New.
(*tstbranchsi4a_ne): New.
(*tstbranchsi4a_eq): New.
Index: rtlanal.c
===================================================================
--- rtlanal.c (revision 162148)
+++ rtlanal.c (working copy)
@@ -4695,12 +4695,17 @@ canonicalize_condition (rtx insn, rtx co
rtx tem;
rtx op0, op1;
int reverse_code = 0;
enum machine_mode mode;
basic_block bb = BLOCK_FOR_INSN (insn);
+ /* Single-bit tests sometimes use logic ops to generate the
+ condition, rather than comparisons. */
+ if (! COMPARISON_P (cond))
+ return 0;
+
code = GET_CODE (cond);
mode = GET_MODE (cond);
op0 = XEXP (cond, 0);
op1 = XEXP (cond, 1);
if (reverse)
Index: config/rx/predicates.md
===================================================================
--- config/rx/predicates.md (revision 162148)
+++ config/rx/predicates.md (working copy)
@@ -42,12 +42,29 @@
if (CONST_INT_P (op))
return IN_RANGE (INTVAL (op), 0, 31);
return true;
}
)
+(define_predicate "rx_constshift_operand"
+ (match_code "const_int")
+ {
+ return IN_RANGE (INTVAL (op), 0, 31);
+ }
+)
+
+;; Check that the operand is suitable for a TST inversion
+
+(define_predicate "rx_onebit_operand"
+ (match_code "const_int")
+ {
+ HOST_WIDE_INT ival = INTVAL (op);
+ return (ival && (ival & (ival-1)) == 0);
+ }
+)
+
;; Check that the operand is suitable as the source operand
;; for a logic or arithmeitc instruction. Registers, integers
;; and a restricted subset of memory addresses are allowed.
(define_predicate "rx_source_operand"
(match_code "const_int,const_double,const,symbol_ref,label_ref,reg,mem")
Index: config/rx/rx.md
===================================================================
--- config/rx/rx.md (revision 162148)
+++ config/rx/rx.md (working copy)
@@ -21,12 +21,15 @@
;; This code iterator allows all branch instructions to
;; be generated from a single define_expand template.
(define_code_iterator most_cond [eq ne gt ge lt le gtu geu ltu leu
unordered ordered ])
+;; Likewise, but only the ones that use Z or S.
+(define_code_iterator zs_cond [eq ne gtu geu ltu leu ])
+
;; This code iterator is used for sign- and zero- extensions.
(define_mode_iterator small_int_modes [(HI "") (QI "")])
;; We do not handle DFmode here because it is either
;; the same as SFmode, or if -m64bit-doubles is active
;; then all operations on doubles have to be handled by
@@ -186,12 +189,190 @@
emit_jump_insn (gen_conditional_branch (operands[2],
gen_rtx_fmt_ee (<most_cond:CODE>, CCmode,
gen_rtx_REG (CCmode, CC_REG), const0_rtx)));
"
)
+;; -----------------------------------------------------------------------------
+;; These two are the canonical TST/branch insns. However, GCC
+;; generates a wide variety of tst-like patterns, we catch those
+;; below.
+(define_insn_and_split "*tstbranchsi4_<code>"
+ [(set (pc)
+ (if_then_else (zs_cond:SI (and:SI (match_operand:SI 0 "register_operand" "r")
+ (match_operand:SI 1 "rx_source_operand" "riQ"))
+ (const_int 0))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))
+ ]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ "
+ emit_insn (gen_tstsi (operands[0], operands[1]));
+
+ emit_jump_insn (gen_conditional_branch (operands[2],
+ gen_rtx_fmt_ee (<zs_cond:CODE>, CCmode,
+ gen_rtx_REG (CCmode, CC_REG), const0_rtx)));
+ "
+)
+
+;; Inverse of above
+(define_insn_and_split "*tstbranchsi4_<code>"
+ [(set (pc)
+ (if_then_else (zs_cond:SI (and:SI (match_operand:SI 0 "register_operand" "r")
+ (match_operand:SI 1 "rx_source_operand" "riQ"))
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 2 "" ""))))
+ ]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ "
+ emit_insn (gen_tstsi (operands[0], operands[1]));
+
+ emit_jump_insn (gen_conditional_branch (operands[2],
+ gen_rtx_fmt_ee (reverse_condition (<zs_cond:CODE>), CCmode,
+ gen_rtx_REG (CCmode, CC_REG), const0_rtx)));
+ "
+)
+
+;; Various other ways that GCC codes "var & const"
+
+(define_insn_and_split "*tstbranchsi4b_eq"
+ [(set (pc)
+ (if_then_else (zero_extract:SI (xor:SI (match_operand:SI 0 "register_operand" "r")
+ (match_operand 1 "immediate_operand" "i"))
+ (const_int 1)
+ (match_operand 2 "rx_constshift_operand" "i"))
+ (label_ref (match_operand 3 "" ""))
+ (pc)))
+ ]
+ ""
+ "#"
+ ""
+ [(set (pc)
+ (if_then_else (eq:SI (and:SI (match_dup 0)
+ (match_dup 4))
+ (const_int 0))
+ (label_ref (match_dup 3))
+ (pc)))
+ ]
+ "operands[4] = GEN_INT (1 << INTVAL (operands[2]));"
+)
+
+(define_insn_and_split "*tstbranchsi4b_ne"
+ [(set (pc)
+ (if_then_else (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
+ (match_operand 1 "rx_constshift_operand" "i")
+ (match_operand 2 "rx_constshift_operand" "i"))
+ (label_ref (match_operand 3 "" ""))
+ (pc)))
+ ]
+ ""
+ "#"
+ ""
+ [(set (pc)
+ (if_then_else (ne:SI (and:SI (match_dup 0)
+ (match_dup 4))
+ (const_int 0))
+ (label_ref (match_dup 3))
+ (pc)))
+ ]
+ "operands[4] = GEN_INT (((1 << INTVAL (operands[1]))-1) << INTVAL (operands[2]));"
+)
+
+(define_insn_and_split "*tstbranchsi4m_eq"
+ [(set (pc)
+ (if_then_else (eq:SI (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
+ (match_operand 1 "rx_constshift_operand" "i")
+ (match_operand 2 "rx_constshift_operand" "i"))
+ (const_int 0))
+ (label_ref (match_operand 3 "" ""))
+ (pc)))
+ ]
+ ""
+ "#"
+ ""
+ [(set (pc)
+ (if_then_else (eq:SI (and:SI (match_dup 0)
+ (match_dup 4))
+ (const_int 0))
+ (label_ref (match_dup 3))
+ (pc)))
+ ]
+ "operands[4] = GEN_INT (((1 << INTVAL (operands[1]))-1) << INTVAL (operands[2]));"
+)
+
+(define_insn_and_split "*tstbranchsi4m_ne"
+ [(set (pc)
+ (if_then_else (ne:SI (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
+ (match_operand 1 "rx_constshift_operand" "i")
+ (match_operand 2 "rx_constshift_operand" "i"))
+ (const_int 0))
+ (label_ref (match_operand 3 "" ""))
+ (pc)))
+ ]
+ ""
+ "#"
+ ""
+ [(set (pc)
+ (if_then_else (ne:SI (and:SI (match_dup 0)
+ (match_dup 4))
+ (const_int 0))
+ (label_ref (match_dup 3))
+ (pc)))
+ ]
+ "operands[4] = GEN_INT (((1 << INTVAL (operands[1]))-1) << INTVAL (operands[2]));"
+)
+
+(define_insn_and_split "*tstbranchsi4a_ne"
+ [(set (pc)
+ (if_then_else (and:SI (match_operand:SI 0 "register_operand" "r")
+ (match_operand 1 "immediate_operand" "i"))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))
+ ]
+ ""
+ "#"
+ ""
+ [(set (pc)
+ (if_then_else (ne:SI (and:SI (match_dup 0)
+ (match_dup 1))
+ (const_int 0))
+ (label_ref (match_dup 2))
+ (pc)))
+ ]
+ ""
+)
+
+(define_insn_and_split "*tstbranchsi4a_eq"
+ [(set (pc)
+ (if_then_else (and:SI (not:SI (match_operand:SI 0 "register_operand" "r"))
+ (match_operand 1 "immediate_operand" "i"))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))
+ ]
+ "rx_onebit_operand (operands[1], VOIDmode)"
+ "#"
+ ""
+ [(set (pc)
+ (if_then_else (eq:SI (and:SI (match_dup 0)
+ (match_dup 1))
+ (const_int 0))
+ (label_ref (match_dup 2))
+ (pc)))
+ ]
+ ""
+)
+
+;; -----------------------------------------------------------------------------
+
(define_expand "cbranchsf4"
[(set (pc)
(if_then_else (match_operator:SF 0 "comparison_operator"
[(match_operand:SF 1 "register_operand")
(match_operand:SF 2 "rx_source_operand")])
(label_ref (match_operand 3 ""))