===================================================================
@@ -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)
===================================================================
@@ -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")
===================================================================
@@ -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 ""))