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