[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