Quoting Ian Lance Taylor <i...@google.com>:

Can you give us some examples of useful combine-split patterns?

sh.md:

;; combiner splitter for test-and-branch on single bit in register.  This
;; is endian dependent because the non-paradoxical subreg looks different
;; on big endian.
(define_split
  [(set (pc)
        (if_then_else
          (match_operator 3 "equality_comparison_operator"
            [(subreg:SI (zero_extract:DI (subreg:DI (match_operand:SI 1
                                                      "extend_reg_operand" "")
                                                    0)
                                         (const_int 1)
                                         (match_operand 2
                                          "const_int_operand" "")) 0)
             (const_int 0)])
          (match_operand 0 "target_operand" "")
          (pc)))
   (clobber (match_operand:SI 4 "arith_reg_dest" ""))]
  "TARGET_SHMEDIA && TARGET_LITTLE_ENDIAN"
  [(set (match_dup 4) (ashift:SI (match_dup 1) (match_dup 5)))
   (set (pc) (if_then_else (match_dup 6) (match_dup 0) (pc)))]

  "
{
  operands[5] = GEN_INT (31 - INTVAL (operands[2]));
  operands[6] = (GET_CODE (operands[3]) == EQ
                 ? gen_rtx_GE (VOIDmode, operands[4], const0_rtx)
                 : gen_rtx_GT (VOIDmode, const0_rtx, operands[4]));
}")


arc.md in arc-4_4-20090909-branch (combine.c in this branch can do a two insn->two insn split when this lowers cost):

; combiner-splitter cmp / scc -> cmp / adc
(define_split
  [(set (match_operand:SI 0 "dest_reg_operand" "")
        (gtu:SI (match_operand:SI 1 "register_operand" "")
                (match_operand:SI 2 "register_operand" "")))
   (clobber (reg CC_REG))]
  ""
  [(set (reg:CC_C CC_REG) (compare:CC_C (match_dup 2) (match_dup 1)))
   (set (match_dup 0) (ltu:SI (reg:CC_C CC_REG) (const_int 0)))])

Note: scc is generally not a single instruction on ARCompact.


; combiner splitter, pattern found in ldtoa.c .
; and op3,op0,op1 / cmp op3,op2 -> add op3,op0,op4 / bmsk.f 0,op3,op1
(define_split
  [(set (reg:CC_Z CC_REG)
        (compare:CC_Z (and:SI (match_operand:SI 0 "register_operand" "")
                              (match_operand 1 "const_int_operand" ""))
                      (match_operand 2 "const_int_operand" "")))
   (clobber (match_operand:SI 3 "register_operand" ""))]
  "((INTVAL (operands[1]) + 1) & INTVAL (operands[1])) == 0"
  [(set (match_dup 3)
        (plus:SI (match_dup 0) (match_dup 4)))
   (set (reg:CC_Z CC_REG)
        (compare:CC_Z (and:SI (match_dup 3) (match_dup 1))
                      (const_int 0)))]
  "operands[4] = GEN_INT ( -(~INTVAL (operands[1]) | INTVAL (operands[2])));")

Note: This saves a long immediate.

I think there is really a lot more potential, but AFAIK combiner splitter
are only made so far when someone stumbles upon such a peephole-esce
optimization opportunity more or less by accident, and has both the
time and skill to exploit it.

If we could replace the combiner splitters with peephole patterns that allow
intervening instructions, so that the peephole matching insns are like i3,i2,i1
in combine, an run these in combine, that would probably give a easier to
use and more powerful mechanism.

OTOH, a I could imagine a superoptimizer coupled with machine learning finding
new combine-split patterns.

But I have no current plans to implement either of these scenarios.

Reply via email to