PR target/30315
authorrask <rask@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 14 Aug 2007 14:39:24 +0000 (14:39 +0000)
committerrask <rask@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 14 Aug 2007 14:39:24 +0000 (14:39 +0000)
* config/i386/i386.h (CANONICALIZE_COMPARISON): New.
* config/i386/i386.md (plusminus)(addsub)(SWI): New.
(*<addsub><mode>3_cc_overflow): New.
(*add<mode>3_cconly_overflow): New.
(*sub<mode>3_cconly_overflow): New.
(*<addsub>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
gcc/config/i386/i386.c
gcc/config/i386/i386.h
gcc/config/i386/i386.md
gcc/config/i386/predicates.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/pr30315.c [new file with mode: 0644]

index 72c9401..f22ca22 100644 (file)
@@ -1,3 +1,20 @@
+2007-08-14  Rask Ingemann Lambertsen  <rask@sygehus.dk>
+
+       PR target/30315
+       * config/i386/i386.h (CANONICALIZE_COMPARISON): New.
+       * config/i386/i386.md (plusminus)(addsub)(SWI): New.
+       (*<addsub><mode>3_cc_overflow): New.
+       (*add<mode>3_cconly_overflow): New.
+       (*sub<mode>3_cconly_overflow): New.
+       (*<addsub>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  <pinskia@gmail.com>
 
        PR c/30428
index 602b555..20044fd 100644 (file)
@@ -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 */
index f205c81..4a41a6c 100644 (file)
@@ -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.  */
 
index cb96182..f316cec 100644 (file)
   [(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])
 
   [(set_attr "type" "alu")
    (set_attr "mode" "DI")])
 
+(define_insn "*<addsub><mode>3_cc_overflow"
+  [(set (reg:CCC FLAGS_REG)
+       (compare:CCC
+           (plusminus:SWI
+               (match_operand:SWI 1 "nonimmediate_operand" "<comm>0,0")
+               (match_operand:SWI 2 "<general_operand>" "<r><i>,<r>m"))
+           (match_dup 1)))
+   (set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m,<r>")
+       (plusminus:SWI (match_dup 1) (match_dup 2)))]
+  "ix86_binary_operator_ok (<CODE>, <MODE>mode, operands)"
+  "<addsub>{<imodesuffix>}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "alu")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*add<mode>3_cconly_overflow"
+  [(set (reg:CCC FLAGS_REG)
+       (compare:CCC
+               (plus:SWI (match_operand:SWI 1 "nonimmediate_operand" "%0")
+                         (match_operand:SWI 2 "<general_operand>" "<r><i>m"))
+               (match_dup 1)))
+   (clobber (match_scratch:SWI 0 "=<r>"))]
+  "ix86_binary_operator_ok (PLUS, <MODE>mode, operands)"
+  "add{<imodesuffix>}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "alu")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*sub<mode>3_cconly_overflow"
+  [(set (reg:CCC FLAGS_REG)
+       (compare:CCC
+            (minus:SWI (match_operand:SWI 0 "nonimmediate_operand" "<r>m,<r>")
+                       (match_operand:SWI 1 "<general_operand>" "<r><i>,<r>m"))
+            (match_dup 0)))]
+  ""
+  "cmp{<imodesuffix>}\t{%1, %0|%0, %1}"
+  [(set_attr "type" "icmp")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*<addsub>si3_zext_cc_overflow"
+  [(set (reg:CCC FLAGS_REG)
+       (compare:CCC
+           (plusminus:SI (match_operand:SI 1 "nonimmediate_operand" "<comm>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 (<CODE>, SImode, operands)"
+  "<addsub>{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" "")
index ef1a22b..f231c57 100644 (file)
   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:
          || 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;
 
 ;; 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);
        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;
 
index 827f4c4..124a822 100644 (file)
@@ -1,3 +1,8 @@
+2007-08-14  Rask Ingemann Lambertsen  <rask@sygehus.dk>
+
+       PR target/30315
+       * gcc.target/i386/pr30315.c: New.
+
 2007-08-14  Francois-Xavier Coudert  <fxcoudert@gcc.gnu.org>
 
        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 (file)
index 0000000..998d507
--- /dev/null
@@ -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