On 12/21/2009 08:10 PM, Richard Henderson wrote:
(define_insn_and_split "*cmp" [(set (match_operand:SI 0 "register_operand" "=r") (lt:SI (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "register_operand" "r")))] "" "cmp %0,%1,%2\;andi $0,$0,1" "" [(set (match_dup 0) (unspec:SI [(match_dup 1) (match_dup 2)] UNSPEC_CMP)) (set (match_dup 0) (and:SI (match_dup 0) (const_int 1)))] "")
It's actually the MSB that is affected, and the entire register is set to zero if a == b. Basically cmp/cmpu prepare rD so that a signed compare-with-zero-and-branch will do the requested conditional branch.
So, branches are easy, but cstores are tricky. Something like this should work; indeed you do not need any CC mode:
;; cbranch expander, possibly use cmp/cmpu to make operand 0 into a ;; signed comparison with zero (define_expand "cbranchsi4" [(set (pc) (if_then_else (match_operator 0 "ordered_comparison_operator" [(match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "register_operand_or_0" "")]) (label_ref (match_operand 3 "")) (pc)))] "enum rtx_code signed = signed_condition (GET_CODE (operands[0])); if (operands[2] != const0_rtx || signed != GET_CODE (operands[0])) { rtx reg = gen_reg_rtx (SImode); if (signed != GET_CODE (operands[0])) emit_insn (gen_cmpusi (reg, operands[1], operands[2])); else emit_insn (gen_cmpsi (reg, operands[1], operands[2])); operands[1] = reg; operands[2] = const0_rtx; operands[0] = gen_rtx_fmt_ee (signed, SImode, reg, const0_rtx); }") ;; branch instructions do a signed comparison with 0 (needs ;; a predicate signed_comparison_operator), you could also ;; write a pattern for indirect conditional branches (define_insn "*branch" [(set (pc) (if_then_else (match_operator 0 "signed_comparison_operator" [(match_operand:SI 1 "register_operand" "") (const_int 0)]) (label_ref (match_operand 2 "")) (pc)))] "" "b%0i %1,%2" "") ;; unspecs for cmp/cmpu (define_insn "cmpsi" [(set (match_operand:SI 0 "register_operand" "=r") (unspec [(match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "register_operand" "r")] UNSPEC_CMP))] "" "cmp %0,%1,%2" "") (define_insn "cmpusi" [(set (match_operand:SI 0 "register_operand" "=r") (unspec [(match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "register_operand" "r")] UNSPEC_CMPU))] "" "cmp %0,%1,%2" "") ;; these are used for cstore tricks when the old contents of rD are ;; significant (define_insn "*cmpsi4" [(set (match_operand:SI 0 "register_operand" "+r") (unspec [(match_dup 0) (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "register_operand" "r")] UNSPEC_CMP))] "" "cmp %0,%1,%2" "") (define_insn "*cmpusi4" [(set (match_operand:SI 0 "register_operand" "+r") (unspec [(match_dup 0) (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "register_operand" "r")] UNSPEC_CMPU))] "" "cmp %0,%1,%2" "") ;; some cstore patterns: cstoresi4 should canonicalize lt/ltu to gt/gtu, ;; as should CANONICALIZE_COMPARISON. ;; ;; common code takes care of ge/geu/le/leu as long as the rtx_costs say ;; it's profitable. Same for a != b for nonzero b. ;; ;; ... ;; if (GET_CODE (operands[1]) == LT || GET_CODE (operands[1]) == LTU) ;; { ;; operands[1] = ;; gen_rtx_fmt_ee (swap_condition (GET_CODE (operands[1])), ;; SImode, operands[3], operands[2]); ;; operands[2] = XEXP (operands[1], 0); ;; operands[3] = XEXP (operands[1], 1); ;; } ;; else if (GET_CODE (operands[1]) == NE && operands[3] != const0_rtx) ;; FAIL; ;; ;; preset rD to 1 to implement a == b (define_insn_and_split "eqsi3" [(set (match_operand:SI 0 "register_operand" "=&r") (eq:SI (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "register_operand" "r")))] "" "" "" [(set (match_dup 0) (const_int 1)) (set (match_dup 0) (unspec:SI [(match_dup 0) (match_dup 1) (match_dup 2)] UNSPEC_CMP)) (set (match_dup 0) (and:SI (match_dup 0) (const_int 1))] "") ;; use a GTU 0 to implement a != 0. but cmpu does not accept immediates (define_insn_and_split "nesi3" [(set (match_operand:SI 0 "register_operand" "=&r") (ne:SI (match_operand:SI 1 "register_operand" "r") (const_int 0)))] "" "" "" [(set (match_dup 0) (const_int 0)) (set (match_dup 0) (unspec:SI [(match_dup 1) (match_dup 0)] UNSPEC_CMPU)) (set (match_dup 0) (lshiftrt:SI (match_dup 0) (const_int 31))] "") ;; these are easy at least :-) (define_insn_and_split "gtsi3" [(set (match_operand:SI 0 "register_operand" "=r") (gt:SI (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "register_operand" "r")))] "" "" "" [(set (match_dup 0) (unspec:SI [(const_int 0) (match_dup 1) (match_dup 2)] UNSPEC_CMP)) (set (match_dup 0) (lshiftrt:SI (match_dup 0) (const_int 31))] "") (define_insn_and_split "gtusi3" [(set (match_operand:SI 0 "register_operand" "=r") (gtu:SI (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "register_operand" "r")))] "" "" "" [(set (match_dup 0) (unspec:SI [(const_int 0) (match_dup 1) (match_dup 2)] UNSPEC_CMPU)) (set (match_dup 0) (lshiftrt:SI (match_dup 0) (const_int 31))] "") ;; some sample combiner patterns (define_insn_and_split "*negnesi3" [(set (match_operand:SI 0 "register_operand" "=&r") (neg:SI (ne:SI (match_operand:SI 1 "register_operand" "r") (const_int 0))))] "" "" "" [(set (match_dup 0) (const_int 0)) (set (match_dup 0) (unspec:SI [(match_dup 1) (match_dup 0)] UNSPEC_CMPU)) (set (match_dup 0) (ashiftrt:SI (match_dup 0) (const_int 31))] "") (define_insn_and_split "*neggtsi3" [(set (match_operand:SI 0 "register_operand" "=r") (neg:SI (gt:SI (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "register_operand" "r"))))] "" "" "" [(set (match_dup 0) (unspec:SI [(const_int 0) (match_dup 1) (match_dup 2)] UNSPEC_CMP)) (set (match_dup 0) (ashiftrt:SI (match_dup 0) (const_int 31))] "") (define_insn_and_split "*neggtusi3" [(set (match_operand:SI 0 "register_operand" "=r") (neg:SI (gtu:SI (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "register_operand" "r"))))] "" "" "" [(set (match_dup 0) (unspec:SI [(const_int 0) (match_dup 1) (match_dup 2)] UNSPEC_CMPU)) (set (match_dup 0) (ashiftrt:SI (match_dup 0) (const_int 31))] "") Paolo