From aa8c6aad445339e9fdb1e9bbbcf3c9516a69a228 Mon Sep 17 00:00:00 2001 From: rask Date: Tue, 14 Aug 2007 14:39:24 +0000 Subject: [PATCH] PR target/30315 * config/i386/i386.h (CANONICALIZE_COMPARISON): New. * config/i386/i386.md (plusminus)(addsub)(SWI): New. (*3_cc_overflow): New. (*add3_cconly_overflow): New. (*sub3_cconly_overflow): New. (*si3_zext_cc_overflow): New. * config/i386/predicates.md (fcmov_comparison_operator): Accept CCCmode for LTU, GTU, LEU and GEU. (ix86_comparison_operator): Likewise. (ix86_carry_flag_operator): Carry flag is set if LTU or GTU in CCCmode. * gcc/config/i386/i386.c (put_condition_code): Support CCCmode. (ix86_cc_mode): Use CCCmode when testing for overflow of PLUS or MINUS expressions. testsuite/ PR target/30315 * gcc.target/i386/pr30315.c: New. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@127481 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 17 ++++++ gcc/config/i386/i386.c | 36 +++++++++--- gcc/config/i386/i386.h | 10 ++++ gcc/config/i386/i386.md | 77 ++++++++++++++++++++++++++ gcc/config/i386/predicates.md | 13 ++++- gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/gcc.target/i386/pr30315.c | 97 +++++++++++++++++++++++++++++++++ 7 files changed, 244 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr30315.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 72c9401..f22ca22 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2007-08-14 Rask Ingemann Lambertsen + + PR target/30315 + * config/i386/i386.h (CANONICALIZE_COMPARISON): New. + * config/i386/i386.md (plusminus)(addsub)(SWI): New. + (*3_cc_overflow): New. + (*add3_cconly_overflow): New. + (*sub3_cconly_overflow): New. + (*si3_zext_cc_overflow): New. + * config/i386/predicates.md (fcmov_comparison_operator): Accept + CCCmode for LTU, GTU, LEU and GEU. + (ix86_comparison_operator): Likewise. + (ix86_carry_flag_operator): Carry flag is set if LTU or GTU in CCCmode. + * gcc/config/i386/i386.c (put_condition_code): Support CCCmode. + (ix86_cc_mode): Use CCCmode when testing for overflow of PLUS + or MINUS expressions. + 2007-08-14 Andrew Pinski PR c/30428 diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 602b555..20044fd 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -8261,8 +8261,12 @@ put_condition_code (enum rtx_code code, enum machine_mode mode, int reverse, case GTU: /* ??? Use "nbe" instead of "a" for fcmov lossage on some assemblers. Those same assemblers have the same but opposite lossage on cmov. */ - gcc_assert (mode == CCmode); - suffix = fp ? "nbe" : "a"; + if (mode == CCmode) + suffix = fp ? "nbe" : "a"; + else if (mode == CCCmode) + suffix = "b"; + else + gcc_unreachable (); break; case LT: switch (mode) @@ -8282,7 +8286,7 @@ put_condition_code (enum rtx_code code, enum machine_mode mode, int reverse, } break; case LTU: - gcc_assert (mode == CCmode); + gcc_assert (mode == CCmode || mode == CCCmode); suffix = "b"; break; case GE: @@ -8304,7 +8308,7 @@ put_condition_code (enum rtx_code code, enum machine_mode mode, int reverse, break; case GEU: /* ??? As above. */ - gcc_assert (mode == CCmode); + gcc_assert (mode == CCmode || mode == CCCmode); suffix = fp ? "nb" : "ae"; break; case LE: @@ -8312,8 +8316,13 @@ put_condition_code (enum rtx_code code, enum machine_mode mode, int reverse, suffix = "le"; break; case LEU: - gcc_assert (mode == CCmode); - suffix = "be"; + /* ??? As above. */ + if (mode == CCmode) + suffix = "be"; + else if (mode == CCCmode) + suffix = fp ? "nb" : "ae"; + else + gcc_unreachable (); break; case UNORDERED: suffix = fp ? "u" : "p"; @@ -11040,10 +11049,21 @@ ix86_cc_mode (enum rtx_code code, rtx op0, rtx op1) return CCZmode; /* Codes needing carry flag. */ case GEU: /* CF=0 */ - case GTU: /* CF=0 & ZF=0 */ case LTU: /* CF=1 */ + /* Detect overflow checks. They need just the carry flag. */ + if (GET_CODE (op0) == PLUS + && rtx_equal_p (op1, XEXP (op0, 0))) + return CCCmode; + else + return CCmode; + case GTU: /* CF=0 & ZF=0 */ case LEU: /* CF=1 | ZF=1 */ - return CCmode; + /* Detect overflow checks. They need just the carry flag. */ + if (GET_CODE (op0) == MINUS + && rtx_equal_p (op1, XEXP (op0, 0))) + return CCCmode; + else + return CCmode; /* Codes possibly doable only with sign flag when comparing against zero. */ case GE: /* SF=OF or SF=0 */ diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index f205c81..4a41a6c 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -2065,6 +2065,16 @@ do { \ #define SELECT_CC_MODE(OP, X, Y) ix86_cc_mode ((OP), (X), (Y)) +/* Canonicalize overflow checks to save on the insn patterns. We change + "a + b < b" into "a + b < a" and "a + b >= b" into "a + b >= a". */ +#define CANONICALIZE_COMPARISON(code, op0, op1) \ +{ \ + if ((code == LTU || code == GEU) \ + && GET_CODE (op0) == PLUS \ + && rtx_equal_p (op1, XEXP (op0, 1))) \ + op1 = XEXP (op0, 0); \ +} + /* Return nonzero if MODE implies a floating point inequality can be reversed. */ diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index cb96182..f316cec 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -488,6 +488,33 @@ [(set_attr "length" "128") (set_attr "type" "multi")]) +(define_code_macro plusminus [plus minus]) + +;; Base name for define_insn and insn mnemonic. +(define_code_attr addsub [(plus "add") (minus "sub")]) + +;; Mark commutative operators as such in constraints. +(define_code_attr comm [(plus "%") (minus "")]) + +;; All single word integer modes. +(define_mode_macro SWI [QI HI SI (DI "TARGET_64BIT")]) + +;; Instruction suffix for integer modes. +(define_mode_attr imodesuffix [(QI "b") (HI "w") (SI "l") (DI "q")]) + +;; Register class for integer modes. +(define_mode_attr r [(QI "q") (HI "r") (SI "r") (DI "r")]) + +;; Immediate operand constraint for integer modes. +(define_mode_attr i [(QI "i") (HI "i") (SI "i") (DI "e")]) + +;; General operand predicate for integer modes. +(define_mode_attr general_operand + [(QI "general_operand") + (HI "general_operand") + (SI "general_operand") + (DI "x86_64_general_operand")]) + ;; All x87 floating point modes (define_mode_macro X87MODEF [SF DF XF]) @@ -4855,6 +4882,56 @@ [(set_attr "type" "alu") (set_attr "mode" "DI")]) +(define_insn "*3_cc_overflow" + [(set (reg:CCC FLAGS_REG) + (compare:CCC + (plusminus:SWI + (match_operand:SWI 1 "nonimmediate_operand" "0,0") + (match_operand:SWI 2 "" ",m")) + (match_dup 1))) + (set (match_operand:SWI 0 "nonimmediate_operand" "=m,") + (plusminus:SWI (match_dup 1) (match_dup 2)))] + "ix86_binary_operator_ok (, mode, operands)" + "{}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "")]) + +(define_insn "*add3_cconly_overflow" + [(set (reg:CCC FLAGS_REG) + (compare:CCC + (plus:SWI (match_operand:SWI 1 "nonimmediate_operand" "%0") + (match_operand:SWI 2 "" "m")) + (match_dup 1))) + (clobber (match_scratch:SWI 0 "="))] + "ix86_binary_operator_ok (PLUS, mode, operands)" + "add{}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "")]) + +(define_insn "*sub3_cconly_overflow" + [(set (reg:CCC FLAGS_REG) + (compare:CCC + (minus:SWI (match_operand:SWI 0 "nonimmediate_operand" "m,") + (match_operand:SWI 1 "" ",m")) + (match_dup 0)))] + "" + "cmp{}\t{%1, %0|%0, %1}" + [(set_attr "type" "icmp") + (set_attr "mode" "")]) + +(define_insn "*si3_zext_cc_overflow" + [(set (reg:CCC FLAGS_REG) + (compare:CCC + (plusminus:SI (match_operand:SI 1 "nonimmediate_operand" "0") + (match_operand:SI 2 "general_operand" "g")) + (match_dup 1))) + (set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI (plusminus:SI (match_dup 1) (match_dup 2))))] + "TARGET_64BIT && ix86_binary_operator_ok (, SImode, operands)" + "{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + (define_insn "addqi3_carry" [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q") (plus:QI (plus:QI (match_operand:QI 3 "ix86_carry_flag_operator" "") diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index ef1a22b..f231c57 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -879,7 +879,8 @@ switch (code) { case LTU: case GTU: case LEU: case GEU: - if (inmode == CCmode || inmode == CCFPmode || inmode == CCFPUmode) + if (inmode == CCmode || inmode == CCFPmode || inmode == CCFPUmode + || inmode == CCCmode) return 1; return 0; case ORDERED: case UNORDERED: @@ -924,7 +925,11 @@ || inmode == CCGOCmode || inmode == CCNOmode) return 1; return 0; - case LTU: case GTU: case LEU: case ORDERED: case UNORDERED: case GEU: + case LTU: case GTU: case LEU: case GEU: + if (inmode == CCmode || inmode == CCCmode) + return 1; + return 0; + case ORDERED: case UNORDERED: if (inmode == CCmode) return 1; return 0; @@ -939,7 +944,7 @@ ;; Return 1 if OP is a valid comparison operator testing carry flag to be set. (define_predicate "ix86_carry_flag_operator" - (match_code "ltu,lt,unlt,gt,ungt,le,unle,ge,unge,ltgt,uneq") + (match_code "ltu,lt,unlt,gtu,gt,ungt,le,unle,ge,unge,ltgt,uneq") { enum machine_mode inmode = GET_MODE (XEXP (op, 0)); enum rtx_code code = GET_CODE (op); @@ -957,6 +962,8 @@ return 0; code = ix86_fp_compare_code_to_integer (code); } + else if (inmode == CCCmode) + return code == LTU || code == GTU; else if (inmode != CCmode) return 0; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 827f4c4..124a822 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2007-08-14 Rask Ingemann Lambertsen + + PR target/30315 + * gcc.target/i386/pr30315.c: New. + 2007-08-14 Francois-Xavier Coudert PR fortran/32594 diff --git a/gcc/testsuite/gcc.target/i386/pr30315.c b/gcc/testsuite/gcc.target/i386/pr30315.c new file mode 100644 index 0000000..998d507 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr30315.c @@ -0,0 +1,97 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { scan-assembler-times "cmp" 4 } } */ + +extern void abort (void); +int c; + +#define PLUSCC1(T, t, C) \ +T pluscc##t##C (T a, T b) \ +{ \ + T sum = a + b; \ + if (sum < C) \ + abort (); \ + return sum; \ +} +#define PLUSCC(T, t) PLUSCC1(T, t, a) PLUSCC1(T, t, b) + +#define INCCC1(T, t, C) \ +T inccc##t##C (T a, T b) \ +{ \ + T sum = a + b; \ + if (sum < C) \ + c ++; \ + return sum; \ +} +#define INCCC(T, t) INCCC1(T, t, a) INCCC1(T, t, b) + +#define PLUSCCONLY1(T, t, C) \ +void pluscconly##t##C (T a, T b) \ +{ \ + T sum = a + b; \ + if (sum < C) \ + abort (); \ +} +#define PLUSCCONLY(T, t) PLUSCCONLY1(T, t, a) PLUSCCONLY1(T, t, b) + +#define MINUSCC(T, t) \ +T minuscc##t (T a, T b) \ +{ \ + T difference = a - b; \ + if (difference > a) \ + abort (); \ + return difference; \ +} + +#define DECCC(T, t) \ +T deccc##t (T a, T b) \ +{ \ + T difference = a - b; \ + if (difference > a) \ + c --; \ + return difference; \ +} + +#define MINUSCCONLY(T, t) \ +void minuscconly##t (T a, T b) \ +{ \ + T difference = a - b; \ + if (difference > a) \ + abort (); \ +} + +#define TEST(T, t) \ + PLUSCC(T, t) \ + PLUSCCONLY(T, t) \ + INCCC(T, t) \ + MINUSCC(T, t) \ + MINUSCCONLY(T, t) \ + DECCC(T, t) + +TEST (unsigned long, l) +TEST (unsigned int, i) +TEST (unsigned short, s) +TEST (unsigned char, c) + +#define PLUSCCZEXT(C) \ +unsigned long pluscczext##C (unsigned int a, unsigned int b) \ +{ \ + unsigned int sum = a + b; \ + if (sum < C) \ + abort (); \ + return sum; \ +} + +PLUSCCZEXT(a) +PLUSCCZEXT(b) + +#define MINUSCCZEXT \ +unsigned long minuscczext (unsigned int a, unsigned int b) \ +{ \ + unsigned int difference = a - b; \ + if (difference > a) \ + abort (); \ + return difference; \ +} + +MINUSCCZEXT -- 2.7.4