On Sat, Oct 19, 2019 at 7:54 AM Jakub Jelinek <ja...@redhat.com> wrote: > > Hi! > > As mentioned in the PR, x == 0 can be equivalently tested as x < 1U > and the latter form has the advantage that it sets the carry flag and if it > is consumed by an instruction that can directly use the carry flag, it is a > win. > The following patch adds a couple of (pre-reload only) define_insn_and_split > to handle the most common cases. > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? > > 2019-10-18 Jakub Jelinek <ja...@redhat.com> > Uroš Bizjak <ubiz...@gmail.com> > > PR target/92140 > * config/i386/predicates.md (int_nonimmediate_operand): New special > predicate. > * config/i386/i386.md (*add<mode>3_eq, *add<mode>3_ne, > *add<mode>3_eq_0, *add<mode>3_ne_0, *sub<mode>3_eq, *sub<mode>3_ne, > *sub<mode>3_eq_1, *sub<mode>3_eq_0, *sub<mode>3_ne_0): New > define_insn_and_split patterns. > > * gcc.target/i386/pr92140.c: New test. > * gcc.c-torture/execute/pr92140.c: New test.
OK. Thanks, Uros. > --- gcc/config/i386/predicates.md.jj 2019-10-07 13:09:06.486261815 +0200 > +++ gcc/config/i386/predicates.md 2019-10-18 15:47:50.781855838 +0200 > @@ -100,6 +100,15 @@ (define_special_predicate "ext_register_ > (match_test "GET_MODE (op) == SImode") > (match_test "GET_MODE (op) == HImode")))) > > +;; Match a DI, SI, HI or QImode nonimmediate_operand. > +(define_special_predicate "int_nonimmediate_operand" > + (and (match_operand 0 "nonimmediate_operand") > + (ior (and (match_test "TARGET_64BIT") > + (match_test "GET_MODE (op) == DImode")) > + (match_test "GET_MODE (op) == SImode") > + (match_test "GET_MODE (op) == HImode") > + (match_test "GET_MODE (op) == QImode")))) > + > ;; Match register operands, but include memory operands for TARGET_SSE_MATH. > (define_predicate "register_ssemem_operand" > (if_then_else > --- gcc/config/i386/i386.md.jj 2019-09-20 12:25:48.000000000 +0200 > +++ gcc/config/i386/i386.md 2019-10-18 15:52:22.697717013 +0200 > @@ -6843,6 +6843,228 @@ (define_insn "*addsi3_zext_cc_overflow_2 > [(set_attr "type" "alu") > (set_attr "mode" "SI")]) > > +;; x == 0 with zero flag test can be done also as x < 1U with carry flag > +;; test, where the latter is preferrable if we have some carry consuming > +;; instruction. > +;; For x != 0, we need to use x < 1U with negation of carry, i.e. > +;; + (1 - CF). > +(define_insn_and_split "*add<mode>3_eq" > + [(set (match_operand:SWI 0 "nonimmediate_operand") > + (plus:SWI > + (plus:SWI > + (eq:SWI (match_operand 3 "int_nonimmediate_operand") (const_int > 0)) > + (match_operand:SWI 1 "nonimmediate_operand")) > + (match_operand:SWI 2 "<general_operand>"))) > + (clobber (reg:CC FLAGS_REG))] > + "ix86_binary_operator_ok (PLUS, <MODE>mode, operands) > + && can_create_pseudo_p ()" > + "#" > + "&& 1" > + [(set (reg:CC FLAGS_REG) > + (compare:CC (match_dup 3) (const_int 1))) > + (parallel [(set (match_dup 0) > + (plus:SWI > + (plus:SWI (ltu:SWI (reg:CC FLAGS_REG) (const_int 0)) > + (match_dup 1)) > + (match_dup 2))) > + (clobber (reg:CC FLAGS_REG))])]) > + > +(define_insn_and_split "*add<mode>3_ne" > + [(set (match_operand:SWI 0 "nonimmediate_operand") > + (plus:SWI > + (plus:SWI > + (ne:SWI (match_operand 3 "int_nonimmediate_operand") (const_int > 0)) > + (match_operand:SWI 1 "nonimmediate_operand")) > + (match_operand:SWI 2 "<immediate_operand>"))) > + (clobber (reg:CC FLAGS_REG))] > + "CONST_INT_P (operands[2]) > + && (<MODE>mode != DImode > + || INTVAL (operands[2]) != HOST_WIDE_INT_C (-0x80000000)) > + && ix86_binary_operator_ok (PLUS, <MODE>mode, operands) > + && can_create_pseudo_p ()" > + "#" > + "&& 1" > + [(set (reg:CC FLAGS_REG) > + (compare:CC (match_dup 3) (const_int 1))) > + (parallel [(set (match_dup 0) > + (minus:SWI > + (minus:SWI (match_dup 1) > + (ltu:SWI (reg:CC FLAGS_REG) (const_int 0))) > + (match_dup 2))) > + (clobber (reg:CC FLAGS_REG))])] > +{ > + operands[2] = gen_int_mode (~INTVAL (operands[2]), > + <MODE>mode == DImode ? SImode : <MODE>mode); > +}) > + > +(define_insn_and_split "*add<mode>3_eq_0" > + [(set (match_operand:SWI 0 "nonimmediate_operand") > + (plus:SWI > + (eq:SWI (match_operand 2 "int_nonimmediate_operand") (const_int 0)) > + (match_operand:SWI 1 "<general_operand>"))) > + (clobber (reg:CC FLAGS_REG))] > + "ix86_unary_operator_ok (PLUS, <MODE>mode, operands) > + && can_create_pseudo_p ()" > + "#" > + "&& 1" > + [(set (reg:CC FLAGS_REG) > + (compare:CC (match_dup 2) (const_int 1))) > + (parallel [(set (match_dup 0) > + (plus:SWI (ltu:SWI (reg:CC FLAGS_REG) (const_int 0)) > + (match_dup 1))) > + (clobber (reg:CC FLAGS_REG))])] > +{ > + if (!nonimmediate_operand (operands[1], <MODE>mode)) > + operands[1] = force_reg (<MODE>mode, operands[1]); > +}) > + > +(define_insn_and_split "*add<mode>3_ne_0" > + [(set (match_operand:SWI 0 "nonimmediate_operand") > + (plus:SWI > + (ne:SWI (match_operand 2 "int_nonimmediate_operand") (const_int 0)) > + (match_operand:SWI 1 "<general_operand>"))) > + (clobber (reg:CC FLAGS_REG))] > + "ix86_unary_operator_ok (PLUS, <MODE>mode, operands) > + && can_create_pseudo_p ()" > + "#" > + "&& 1" > + [(set (reg:CC FLAGS_REG) > + (compare:CC (match_dup 2) (const_int 1))) > + (parallel [(set (match_dup 0) > + (minus:SWI (minus:SWI > + (match_dup 1) > + (ltu:SWI (reg:CC FLAGS_REG) (const_int 0))) > + (const_int -1))) > + (clobber (reg:CC FLAGS_REG))])] > +{ > + if (!nonimmediate_operand (operands[1], <MODE>mode)) > + operands[1] = force_reg (<MODE>mode, operands[1]); > +}) > + > +(define_insn_and_split "*sub<mode>3_eq" > + [(set (match_operand:SWI 0 "nonimmediate_operand") > + (minus:SWI > + (minus:SWI > + (match_operand:SWI 1 "nonimmediate_operand") > + (eq:SWI (match_operand 3 "int_nonimmediate_operand") > + (const_int 0))) > + (match_operand:SWI 2 "<general_operand>"))) > + (clobber (reg:CC FLAGS_REG))] > + "ix86_binary_operator_ok (MINUS, <MODE>mode, operands) > + && can_create_pseudo_p ()" > + "#" > + "&& 1" > + [(set (reg:CC FLAGS_REG) > + (compare:CC (match_dup 3) (const_int 1))) > + (parallel [(set (match_dup 0) > + (minus:SWI > + (minus:SWI (match_dup 1) > + (ltu:SWI (reg:CC FLAGS_REG) (const_int 0))) > + (match_dup 2))) > + (clobber (reg:CC FLAGS_REG))])]) > + > +(define_insn_and_split "*sub<mode>3_ne" > + [(set (match_operand:SWI 0 "nonimmediate_operand") > + (plus:SWI > + (minus:SWI > + (match_operand:SWI 1 "nonimmediate_operand") > + (ne:SWI (match_operand 3 "int_nonimmediate_operand") > + (const_int 0))) > + (match_operand:SWI 2 "<immediate_operand>"))) > + (clobber (reg:CC FLAGS_REG))] > + "CONST_INT_P (operands[2]) > + && (<MODE>mode != DImode > + || INTVAL (operands[2]) != HOST_WIDE_INT_C (-0x80000000)) > + && ix86_binary_operator_ok (MINUS, <MODE>mode, operands) > + && can_create_pseudo_p ()" > + "#" > + "&& 1" > + [(set (reg:CC FLAGS_REG) > + (compare:CC (match_dup 3) (const_int 1))) > + (parallel [(set (match_dup 0) > + (plus:SWI > + (plus:SWI (ltu:SWI (reg:CC FLAGS_REG) (const_int 0)) > + (match_dup 1)) > + (match_dup 2))) > + (clobber (reg:CC FLAGS_REG))])] > +{ > + operands[2] = gen_int_mode (INTVAL (operands[2]) - 1, > + <MODE>mode == DImode ? SImode : <MODE>mode); > +}) > + > +(define_insn_and_split "*sub<mode>3_eq_1" > + [(set (match_operand:SWI 0 "nonimmediate_operand") > + (plus:SWI > + (minus:SWI > + (match_operand:SWI 1 "nonimmediate_operand") > + (eq:SWI (match_operand 3 "int_nonimmediate_operand") > + (const_int 0))) > + (match_operand:SWI 2 "<immediate_operand>"))) > + (clobber (reg:CC FLAGS_REG))] > + "CONST_INT_P (operands[2]) > + && (<MODE>mode != DImode > + || INTVAL (operands[2]) != HOST_WIDE_INT_C (-0x80000000)) > + && ix86_binary_operator_ok (MINUS, <MODE>mode, operands) > + && can_create_pseudo_p ()" > + "#" > + "&& 1" > + [(set (reg:CC FLAGS_REG) > + (compare:CC (match_dup 3) (const_int 1))) > + (parallel [(set (match_dup 0) > + (minus:SWI > + (minus:SWI (match_dup 1) > + (ltu:SWI (reg:CC FLAGS_REG) (const_int 0))) > + (match_dup 2))) > + (clobber (reg:CC FLAGS_REG))])] > +{ > + operands[2] = gen_int_mode (-INTVAL (operands[2]), > + <MODE>mode == DImode ? SImode : <MODE>mode); > +}) > + > +(define_insn_and_split "*sub<mode>3_eq_0" > + [(set (match_operand:SWI 0 "nonimmediate_operand") > + (minus:SWI > + (match_operand:SWI 1 "<general_operand>") > + (eq:SWI (match_operand 2 "int_nonimmediate_operand") (const_int > 0)))) > + (clobber (reg:CC FLAGS_REG))] > + "ix86_unary_operator_ok (MINUS, <MODE>mode, operands) > + && can_create_pseudo_p ()" > + "#" > + "&& 1" > + [(set (reg:CC FLAGS_REG) > + (compare:CC (match_dup 2) (const_int 1))) > + (parallel [(set (match_dup 0) > + (minus:SWI (match_dup 1) > + (ltu:SWI (reg:CC FLAGS_REG) (const_int 0)))) > + (clobber (reg:CC FLAGS_REG))])] > +{ > + if (!nonimmediate_operand (operands[1], <MODE>mode)) > + operands[1] = force_reg (<MODE>mode, operands[1]); > +}) > + > +(define_insn_and_split "*sub<mode>3_ne_0" > + [(set (match_operand:SWI 0 "nonimmediate_operand") > + (minus:SWI > + (match_operand:SWI 1 "<general_operand>") > + (ne:SWI (match_operand 2 "int_nonimmediate_operand") (const_int > 0)))) > + (clobber (reg:CC FLAGS_REG))] > + "ix86_unary_operator_ok (MINUS, <MODE>mode, operands) > + && can_create_pseudo_p ()" > + "#" > + "&& 1" > + [(set (reg:CC FLAGS_REG) > + (compare:CC (match_dup 2) (const_int 1))) > + (parallel [(set (match_dup 0) > + (plus:SWI (plus:SWI > + (ltu:SWI (reg:CC FLAGS_REG) (const_int 0)) > + (match_dup 1)) > + (const_int -1))) > + (clobber (reg:CC FLAGS_REG))])] > +{ > + if (!nonimmediate_operand (operands[1], <MODE>mode)) > + operands[1] = force_reg (<MODE>mode, operands[1]); > +}) > + > ;; The patterns that match these are at the end of this file. > > (define_expand "<plusminus_insn>xf3" > --- gcc/testsuite/gcc.target/i386/pr92140.c.jj 2019-10-18 15:21:26.347972472 > +0200 > +++ gcc/testsuite/gcc.target/i386/pr92140.c 2019-10-18 15:41:10.748944727 > +0200 > @@ -0,0 +1,38 @@ > +/* PR target/92140 */ > +/* { dg-do compile { target nonpic } } */ > +/* { dg-options "-O2 -mtune=generic -masm=att" } */ > +/* { dg-additional-options "-mregparm=1" { target ia32 } } */ > +/* { dg-final { scan-assembler-times "\tsbbl\t\\\$-1, v" 1 } } */ > +/* { dg-final { scan-assembler-times "\tadcl\t\\\$-1, v" 1 } } */ > +/* { dg-final { scan-assembler-times "\tadcl\t\\\$0, v" 1 } } */ > +/* { dg-final { scan-assembler-times "\tsbbl\t\\\$0, v" 1 } } */ > +/* { dg-final { scan-assembler-times "\tsbbl\t\\\$25, v" 1 } } */ > +/* { dg-final { scan-assembler-times "\tadcl\t\\\$25, v" 1 } } */ > +/* { dg-final { scan-assembler-times "\tadcl\t\\\$-26, v" 1 } } */ > +/* { dg-final { scan-assembler-times "\tsbbl\t\\\$-26, v" 1 } } */ > +/* { dg-final { scan-assembler-times "\tsbbl\t\\\$-43, v" 1 } } */ > +/* { dg-final { scan-assembler-times "\tadcl\t\\\$-43, v" 1 } } */ > +/* { dg-final { scan-assembler-times "\tadcl\t\\\$42, v" 1 } } */ > +/* { dg-final { scan-assembler-times "\tsbbl\t\\\$42, v" 1 } } */ > +/* { dg-final { scan-assembler-times "\tadcl\t%\[a-z0-9]*, v" 1 } } */ > +/* { dg-final { scan-assembler-times "\tsbbl\t%\[a-z0-9]*, v" 1 } } */ > +/* { dg-final { scan-assembler-times "\tsbbl\t\\\$-1, %" 1 } } */ > + > +char c; > +int v; > + > +__attribute__((noipa)) void f1 (void) { v += c != 0; } > +__attribute__((noipa)) void f2 (void) { v -= c != 0; } > +__attribute__((noipa)) void f3 (void) { v += c == 0; } > +__attribute__((noipa)) void f4 (void) { v -= c == 0; } > +__attribute__((noipa)) void f5 (void) { v += (c != 0) - 26; } > +__attribute__((noipa)) void f6 (void) { v -= (c != 0) - 26; } > +__attribute__((noipa)) void f7 (void) { v += (c == 0) - 26; } > +__attribute__((noipa)) void f8 (void) { v -= (c == 0) - 26; } > +__attribute__((noipa)) void f9 (void) { v += (c != 0) + 42; } > +__attribute__((noipa)) void f10 (void) { v -= (c != 0) + 42; } > +__attribute__((noipa)) void f11 (void) { v += (c == 0) + 42; } > +__attribute__((noipa)) void f12 (void) { v -= (c == 0) + 42; } > +__attribute__((noipa)) void f13 (int z) { v += (c == 0) + z; } > +__attribute__((noipa)) void f14 (int z) { v -= (c == 0) + z; } > +__attribute__((noipa)) unsigned int f15 (unsigned int n) { return n ? 2 : 1; > } > --- gcc/testsuite/gcc.c-torture/execute/pr92140.c.jj 2019-10-18 > 14:13:57.787580586 +0200 > +++ gcc/testsuite/gcc.c-torture/execute/pr92140.c 2019-10-18 > 15:20:27.629866214 +0200 > @@ -0,0 +1,83 @@ > +/* PR target/92140 */ > + > +char c; > +int v; > + > +__attribute__((noipa)) void f1 (void) { v += c != 0; } > +__attribute__((noipa)) void f2 (void) { v -= c != 0; } > +__attribute__((noipa)) void f3 (void) { v += c == 0; } > +__attribute__((noipa)) void f4 (void) { v -= c == 0; } > +__attribute__((noipa)) void f5 (void) { v += (c != 0) - 26; } > +__attribute__((noipa)) void f6 (void) { v -= (c != 0) - 26; } > +__attribute__((noipa)) void f7 (void) { v += (c == 0) - 26; } > +__attribute__((noipa)) void f8 (void) { v -= (c == 0) - 26; } > +__attribute__((noipa)) void f9 (void) { v += (c != 0) + 42; } > +__attribute__((noipa)) void f10 (void) { v -= (c != 0) + 42; } > +__attribute__((noipa)) void f11 (void) { v += (c == 0) + 42; } > +__attribute__((noipa)) void f12 (void) { v -= (c == 0) + 42; } > +__attribute__((noipa)) void f13 (int z) { v += (c == 0) + z; } > +__attribute__((noipa)) void f14 (int z) { v -= (c == 0) + z; } > +__attribute__((noipa)) unsigned int f15 (unsigned int n) { return n ? 2 : 1; > } > + > +int > +main () > +{ > + int i; > + for (i = 0; i < 2; i++) > + { > + v = 15; > + if (i == 1) > + c = 37; > + f1 (); > + if (v != 15 + i) > + __builtin_abort (); > + f2 (); > + if (v != 15) > + __builtin_abort (); > + f3 (); > + if (v != 16 - i) > + __builtin_abort (); > + f4 (); > + if (v != 15) > + __builtin_abort (); > + f5 (); > + if (v != 15 + i - 26) > + __builtin_abort (); > + f6 (); > + if (v != 15) > + __builtin_abort (); > + f7 (); > + if (v != 16 - i - 26) > + __builtin_abort (); > + f8 (); > + if (v != 15) > + __builtin_abort (); > + f9 (); > + if (v != 15 + i + 42) > + __builtin_abort (); > + f10 (); > + if (v != 15) > + __builtin_abort (); > + f11 (); > + if (v != 16 - i + 42) > + __builtin_abort (); > + f12 (); > + if (v != 15) > + __builtin_abort (); > + f13 (173); > + if (v != 16 - i + 173) > + __builtin_abort (); > + f14 (173); > + if (v != 15) > + __builtin_abort (); > + f13 (-35); > + if (v != 16 - i - 35) > + __builtin_abort (); > + f14 (-35); > + if (v != 15) > + __builtin_abort (); > + } > + if (f15 (0) != 1 || f15 (1) != 2 || f15 (371) != 2) > + __builtin_abort (); > + return 0; > +} > > Jakub