aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Meissner <meissner@redhat.com>2000-07-15 14:58:53 +0000
committerMichael Meissner <meissner@gcc.gnu.org>2000-07-15 14:58:53 +0000
commit4d06bcc527aca789f9282167528aa02f77cdd6ca (patch)
treecc186924767d7116187ea8c5addebe72555b7ae8
parentbbed132f325e85bb0ee7cdfeac9c4504278e99d6 (diff)
downloadgcc-4d06bcc527aca789f9282167528aa02f77cdd6ca.zip
gcc-4d06bcc527aca789f9282167528aa02f77cdd6ca.tar.gz
gcc-4d06bcc527aca789f9282167528aa02f77cdd6ca.tar.bz2
Fix (<cond> ? FOO++ : BAR++) == 2 from misoptimizing FOO++ into ++FOO without bumping up the comparison value
From-SVN: r35046
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/fold-const.c32
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/20000715-1.c118
4 files changed, 152 insertions, 8 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 7199aea..45b1d54 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2000-07-15 Michael Meissner <meissner@redhat.com>
+
+ * fold-const.c (fold): When optimizing FOO++ == CONST into ++FOO
+ == CONST + INCREMENT, don't overwrite the tree node for FOO++,
+ create a new node instead.
+
2000-07-15 Neil Booth <NeilB@earthling.net>
* README.Portability: Correct example about calling a function
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 26ac5d2..f259115 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -6136,7 +6136,15 @@ fold (expr)
tree newconst
= fold (build (PLUS_EXPR, TREE_TYPE (varop),
constop, TREE_OPERAND (varop, 1)));
- TREE_SET_CODE (varop, PREINCREMENT_EXPR);
+
+ /* Do not overwrite the current varop to be a preincrement,
+ create a new node so that we won't confuse our caller who
+ might create trees and throw them away, reusing the
+ arguments that they passed to build. This shows up in
+ the THEN or ELSE parts of ?: being postincrements. */
+ varop = build (PREINCREMENT_EXPR, TREE_TYPE (varop),
+ TREE_OPERAND (varop, 0),
+ TREE_OPERAND (varop, 1));
/* If VAROP is a reference to a bitfield, we must mask
the constant by the width of the field. */
@@ -6180,9 +6188,9 @@ fold (expr)
}
- t = build (code, type, TREE_OPERAND (t, 0),
- TREE_OPERAND (t, 1));
- TREE_OPERAND (t, constopnum) = newconst;
+ t = build (code, type,
+ (constopnum == 0) ? newconst : varop,
+ (constopnum == 1) ? newconst : varop);
return t;
}
}
@@ -6195,7 +6203,15 @@ fold (expr)
tree newconst
= fold (build (MINUS_EXPR, TREE_TYPE (varop),
constop, TREE_OPERAND (varop, 1)));
- TREE_SET_CODE (varop, PREDECREMENT_EXPR);
+
+ /* Do not overwrite the current varop to be a predecrement,
+ create a new node so that we won't confuse our caller who
+ might create trees and throw them away, reusing the
+ arguments that they passed to build. This shows up in
+ the THEN or ELSE parts of ?: being postdecrements. */
+ varop = build (PREDECREMENT_EXPR, TREE_TYPE (varop),
+ TREE_OPERAND (varop, 0),
+ TREE_OPERAND (varop, 1));
if (TREE_CODE (TREE_OPERAND (varop, 0)) == COMPONENT_REF
&& DECL_BIT_FIELD(TREE_OPERAND
@@ -6234,9 +6250,9 @@ fold (expr)
}
- t = build (code, type, TREE_OPERAND (t, 0),
- TREE_OPERAND (t, 1));
- TREE_OPERAND (t, constopnum) = newconst;
+ t = build (code, type,
+ (constopnum == 0) ? newconst : varop,
+ (constopnum == 1) ? newconst : varop);
return t;
}
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 1f94bdb..e778d70 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2000-07-15 Michael Meissner <meissner@redhat.com>
+
+ * gcc.c-torture/execute/20000715-1.c: New test.
+
2000-07-13 Jakub Jelinek <jakub@redhat.com>
* gcc.c-torture/execute/20000707-1.c: New test.
diff --git a/gcc/testsuite/gcc.c-torture/execute/20000715-1.c b/gcc/testsuite/gcc.c-torture/execute/20000715-1.c
new file mode 100644
index 0000000..43af114
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/20000715-1.c
@@ -0,0 +1,118 @@
+void abort(void);
+void exit(int);
+
+void
+test1(void)
+{
+ int x = 3, y = 2;
+
+ if ((x < y ? x++ : y++) != 2)
+ abort ();
+
+ if (x != 3)
+ abort ();
+
+ if (y != 3)
+ abort ();
+}
+
+void
+test2(void)
+{
+ int x = 3, y = 2, z;
+
+ z = (x < y) ? x++ : y++;
+ if (z != 2)
+ abort ();
+
+ if (x != 3)
+ abort ();
+
+ if (y != 3)
+ abort ();
+}
+
+void
+test3(void)
+{
+ int x = 3, y = 2;
+ int xx = 3, yy = 2;
+
+ if ((xx < yy ? x++ : y++) != 2)
+ abort ();
+
+ if (x != 3)
+ abort ();
+
+ if (y != 3)
+ abort ();
+}
+
+int x, y;
+
+static void
+init_xy(void)
+{
+ x = 3;
+ y = 2;
+}
+
+void
+test4(void)
+{
+ init_xy();
+ if ((x < y ? x++ : y++) != 2)
+ abort ();
+
+ if (x != 3)
+ abort ();
+
+ if (y != 3)
+ abort ();
+}
+
+void
+test5(void)
+{
+ int z;
+
+ init_xy();
+ z = (x < y) ? x++ : y++;
+ if (z != 2)
+ abort ();
+
+ if (x != 3)
+ abort ();
+
+ if (y != 3)
+ abort ();
+}
+
+void
+test6(void)
+{
+ int xx = 3, yy = 2;
+ int z;
+
+ init_xy();
+ z = (xx < y) ? x++ : y++;
+ if (z != 2)
+ abort ();
+
+ if (x != 3)
+ abort ();
+
+ if (y != 3)
+ abort ();
+}
+
+int
+main(){
+ test1 ();
+ test2 ();
+ test3 ();
+ test4 ();
+ test5 ();
+ test6 ();
+ exit (0);
+}