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

Reply via email to