[PATCH] i386: Improve chaining of _{addcarry, subborrow}_u{32, 64} [PR97387]

Jakub Jelinek jakub@redhat.com
Wed Oct 14 13:49:05 GMT 2020


On Wed, Oct 14, 2020 at 03:17:03PM +0200, Uros Bizjak wrote:
> > +(define_insn_and_split "*setcc_qi_addqi3_cconly_overflow_1_<mode>"
> > +  [(set (reg:CCC FLAGS_REG)
> > +       (compare:CCC (neg:QI (geu:QI (reg:CC_CCC FLAGS_REG) (const_int 0)))
> > +                    (ltu:QI (reg:CC_CCC FLAGS_REG) (const_int 0))))]
> > +  "ix86_pre_reload_split ()"
> > +  "#"
> > +  "&& 1"
> > +  [(const_int 0)])
> >
> 
> Hmm... does the above really represent a NOP?

It is just what combine.c + simplify-rtx.c make out of this.
We have:
(insn 10 9 11 2 (set (reg:QI 88 [ _31 ])
        (ltu:QI (reg:CCC 17 flags)
            (const_int 0 [0]))) "include/adxintrin.h":69:10 785 {*setcc_qi}
     (expr_list:REG_DEAD (reg:CCC 17 flags)
        (nil)))
and
(insn 17 15 18 2 (parallel [
            (set (reg:CCC 17 flags)
                (compare:CCC (plus:QI (reg:QI 88 [ _31 ])
                        (const_int -1 [0xffffffffffffffff]))
                    (reg:QI 88 [ _31 ])))
            (clobber (scratch:QI))
        ]) "include/adxintrin.h":69:10 350 {*addqi3_cconly_overflow_1}
     (expr_list:REG_DEAD (reg:QI 88 [ _31 ])
        (nil)))
So when substituting (reg:QI 88) for (ltu:QI flags 0), we initially get:
(compare:CCC (plus:QI (ltu:QI (reg:CCC 17 flags) (const_int [0])) (const_int -1 [0xffffffffffffffff]))
	     (ltu:QI (reg:CCC 17 flags) (const_int [0])))
On this triggers simplify_binary_operation_1 rule:
      /* (plus (comparison A B) C) can become (neg (rev-comp A B)) if
         C is 1 and STORE_FLAG_VALUE is -1 or if C is -1 and STORE_FLAG_VALUE
         is 1.  */
      if (COMPARISON_P (op0)
          && ((STORE_FLAG_VALUE == -1 && trueop1 == const1_rtx)
              || (STORE_FLAG_VALUE == 1 && trueop1 == constm1_rtx))
          && (reversed = reversed_comparison (op0, mode)))
        return
          simplify_gen_unary (NEG, mode, reversed, mode);
As STORE_FLAG_VALUE is 1 on i386, it triggers for that -1.

Now, in CCCmode we have just 2 possible values, 0 and 1, CF clear and CF set.
So, either (ltu:QI (reg:CCC 17 flags) (const_int 0 [0])) is 0, in that case
(geu:QI (reg:CCC 17 flags) (const_int 0 [0])) is 1 and so
(compare:CCC (neg:QI (geu:QI (reg:CCC FLAGS_REG) (const_int 0)))
	     (ltu:QI (reg:CCC FLAGS_REG) (const_int 0))))
is (compare:CCC (neg:QI (const_int 1 [0x1])) (const_int 0 [0]))
which is (compare:CCC (const_int -1 [0xffffffffffffffff]) (const_int 0 [0]))
Or (ltu:QI (reg:CCC 17 flags) (const_int 0 [0])) is 1, in that case
(geu:QI (reg:CCC 17 flags) (const_int 0 [0])) is 0 and so
(compare:CCC (neg:QI (geu:QI (reg:CCC FLAGS_REG) (const_int 0)))
	     (ltu:QI (reg:CCC FLAGS_REG) (const_int 0))))
is (compare:CCC (neg:QI (const_int 0 [0x0])) (const_int 1 [0x1]))
which is (compare:CCC (const_int 0 [0]) (const_int 1 [0x1]))
As CCCmode flags can be only used in LTU or GEU comparisons, we are asking if
0xffU < 0 (false, CF clear) or 0 < 1 (true, CF set).

So I think the pattern is meaningful and is really a nop.

	Jakub



More information about the Gcc-patches mailing list