diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 68f33f96f5a..2f896efb5e2 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -20057,13 +20057,16 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno, } else if (GET_CODE (XEXP (x, 0)) == PLUS) { + rtx op = XEXP (XEXP (x, 0), 0); + /* Add with carry, ignore the cost of adding a carry flag. */ - if (ix86_carry_flag_operator (XEXP (XEXP (x, 0), 0), mode)) + if (ix86_carry_flag_operator (op, mode) + || ix86_carry_flag_unset_operator (op, mode)) *total = cost->add; else { *total = cost->lea; - *total += rtx_cost (XEXP (XEXP (x, 0), 0), mode, + *total += rtx_cost (op, mode, outer_code, opno, speed); } @@ -20081,7 +20084,8 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno, if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_SIZE (mode) <= UNITS_PER_WORD && GET_CODE (XEXP (x, 0)) == MINUS - && ix86_carry_flag_operator (XEXP (XEXP (x, 0), 1), mode)) + && (ix86_carry_flag_operator (XEXP (XEXP (x, 0), 1), mode) + || ix86_carry_flag_unset_operator (XEXP (XEXP (x, 0), 1), mode))) { *total = cost->add; *total += rtx_cost (XEXP (XEXP (x, 0), 0), mode, diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index b7f3e36a70c..bb89eb97c69 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -6773,8 +6773,8 @@ (define_insn "@add3_carry" (define_insn "*add3_carry_0" [(set (match_operand:SWI 0 "nonimmediate_operand" "=m") (plus:SWI - (match_operator:SWI 3 "ix86_carry_flag_operator" - [(match_operand 2 "flags_reg_operand") (const_int 0)]) + (match_operator:SWI 2 "ix86_carry_flag_operator" + [(reg FLAGS_REG) (const_int 0)]) (match_operand:SWI 1 "nonimmediate_operand" "0"))) (clobber (reg:CC FLAGS_REG))] "!MEM_P (operands[0]) || rtx_equal_p (operands[0], operands[1])" @@ -6784,6 +6784,20 @@ (define_insn "*add3_carry_0" (set_attr "pent_pair" "pu") (set_attr "mode" "")]) +(define_insn "*add3_carry_0r" + [(set (match_operand:SWI 0 "nonimmediate_operand" "=m") + (plus:SWI + (match_operator:SWI 2 "ix86_carry_flag_unset_operator" + [(reg FLAGS_REG) (const_int 0)]) + (match_operand:SWI 1 "nonimmediate_operand" "0"))) + (clobber (reg:CC FLAGS_REG))] + "!MEM_P (operands[0]) || rtx_equal_p (operands[0], operands[1])" + "sbb{}\t{$-1, %0|%0, -1}" + [(set_attr "type" "alu") + (set_attr "use_carry" "1") + (set_attr "pent_pair" "pu") + (set_attr "mode" "")]) + (define_insn "*addsi3_carry_zext" [(set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI @@ -6814,6 +6828,20 @@ (define_insn "*addsi3_carry_zext_0" (set_attr "pent_pair" "pu") (set_attr "mode" "SI")]) +(define_insn "*addsi3_carry_zext_0r" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (plus:SI (match_operator:SI 2 "ix86_carry_flag_unset_operator" + [(reg FLAGS_REG) (const_int 0)]) + (match_operand:SI 1 "register_operand" "0")))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_64BIT" + "sbb{l}\t{$-1, %k0|%k0, -1}" + [(set_attr "type" "alu") + (set_attr "use_carry" "1") + (set_attr "pent_pair" "pu") + (set_attr "mode" "SI")]) + ;; There is no point to generate ADCX instruction. ADC is shorter and faster. (define_insn "addcarry" @@ -6916,8 +6944,8 @@ (define_insn "*sub3_carry_0" [(set (match_operand:SWI 0 "nonimmediate_operand" "=m") (minus:SWI (match_operand:SWI 1 "nonimmediate_operand" "0") - (match_operator:SWI 3 "ix86_carry_flag_operator" - [(match_operand 2 "flags_reg_operand") (const_int 0)]))) + (match_operator:SWI 2 "ix86_carry_flag_operator" + [(reg FLAGS_REG) (const_int 0)]))) (clobber (reg:CC FLAGS_REG))] "!MEM_P (operands[0]) || rtx_equal_p (operands[0], operands[1])" "sbb{}\t{$0, %0|%0, 0}" @@ -6926,6 +6954,20 @@ (define_insn "*sub3_carry_0" (set_attr "pent_pair" "pu") (set_attr "mode" "")]) +(define_insn "*sub3_carry_0r" + [(set (match_operand:SWI 0 "nonimmediate_operand" "=m") + (minus:SWI + (match_operand:SWI 1 "nonimmediate_operand" "0") + (match_operator:SWI 2 "ix86_carry_flag_unset_operator" + [(reg FLAGS_REG) (const_int 0)]))) + (clobber (reg:CC FLAGS_REG))] + "!MEM_P (operands[0]) || rtx_equal_p (operands[0], operands[1])" + "adc{}\t{$-1, %0|%0, -1}" + [(set_attr "type" "alu") + (set_attr "use_carry" "1") + (set_attr "pent_pair" "pu") + (set_attr "mode" "")]) + (define_insn "*subsi3_carry_zext" [(set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI @@ -6958,6 +7000,21 @@ (define_insn "*subsi3_carry_zext_0" (set_attr "pent_pair" "pu") (set_attr "mode" "SI")]) +(define_insn "*subsi3_carry_zext_0r" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (minus:SI + (match_operand:SI 1 "register_operand" "0") + (match_operator:SI 2 "ix86_carry_flag_unset_operator" + [(reg FLAGS_REG) (const_int 0)])))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_64BIT" + "adc{l}\t{$-1, %k0|%k0, -1}" + [(set_attr "type" "alu") + (set_attr "use_carry" "1") + (set_attr "pent_pair" "pu") + (set_attr "mode" "SI")]) + (define_insn "@sub3_carry_ccc" [(set (reg:CCC FLAGS_REG) (compare:CCC diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index 04a03a70b46..6dfbb0873be 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -1455,6 +1455,22 @@ (define_predicate "ix86_carry_flag_operator" return code == LTU; }) +;; Return true if OP is a valid comparison operator +;; testing carry flag to be unset. +(define_predicate "ix86_carry_flag_unset_operator" + (match_code "geu,ge") +{ + machine_mode inmode = GET_MODE (XEXP (op, 0)); + enum rtx_code code = GET_CODE (op); + + if (inmode == CCFPmode) + code = ix86_fp_compare_code_to_integer (code); + else if (inmode != CCmode && inmode != CCCmode && inmode != CCGZmode) + return false; + + return code == GEU; +}) + ;; Return true if this comparison only requires testing one flag bit. (define_predicate "ix86_trivial_fp_comparison_operator" (match_code "gt,ge,unlt,unle,uneq,ltgt,ordered,unordered")) diff --git a/gcc/testsuite/gcc.target/i386/pr98060.c b/gcc/testsuite/gcc.target/i386/pr98060.c new file mode 100644 index 00000000000..f82620ceb64 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr98060.c @@ -0,0 +1,47 @@ +/* PR target/98060 */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +/* { dg-final { scan-assembler-not "set" } } */ +/* { dg-final { scan-assembler-times "adc" 4 } } */ +/* { dg-final { scan-assembler-times "sbb" 4 } } */ + +int r1 (unsigned v0, unsigned v1, int v2) +{ + return v2 + (v0 >= v1); +} + +int r2 (unsigned v0, unsigned v1, int v2) +{ + return v2 + (v0 <= v1); +} + +int r3 (unsigned v0, unsigned v1, int v2) +{ + return v2 + (v0 > v1); +} + +int r4 (unsigned v0, unsigned v1, int v2) +{ + return v2 + (v0 < v1); +} + +int r5 (unsigned v0, unsigned v1, int v2) +{ + return v2 - (v0 >= v1); +} + +int r6 (unsigned v0, unsigned v1, int v2) +{ + return v2 - (v0 <= v1); +} + +int r7 (unsigned v0, unsigned v1, int v2) +{ + return v2 - (v0 > v1); +} + +int r8 (unsigned v0, unsigned v1, int v2) +{ + return v2 - (v0 < v1); +}