This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix COND_EXPR with sibcall optimization
- From: Jakub Jelinek <jakub at redhat dot com>
- To: Richard Henderson <rth at redhat dot com>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Wed, 4 Dec 2002 19:26:19 +0100
- Subject: [PATCH] Fix COND_EXPR with sibcall optimization
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
Hi!
The following testcase is miscompiled on SPARC and I suppose lots of other
arches too with -O2.
The problem is that expand_expr [COND_EXPR] changes operand 0 of COND_EXPR
in place and if do_store_flag is successful, doesn't reset it back.
With sibcall optimization, that COND_EXPR is evaluated twice, once in
the sibcall RTL chain and once in normal RTL chain, and thus in the second
case it is not z > 0 ? b - a : b - a - 1 as it should, but
z <= 0 ? b - a : b - a - 1 instead. This call cannot be a sibling and thus
we get the wrong result.
The comment above it said that it modifies it in place because
invert_truthvalue might modify the tree pointed by its argument.
Comment above invert_truthvalue says the contrary, ie.
this never alters ARG itself and my inspection leads me to believe the
latter is true. If not, the second invert_truthvalue would have to be called
right after do_store_flag, not only in one of the branches.
Ok to commit if bootstrap succeeds?
What about 3.2 branch? It is definitely a regression from pre-sibcall gcc's.
2002-12-04 Jakub Jelinek <jakub@redhat.com>
* expr.c (expand_expr) [COND_EXPR]: Never modify exp in place.
* gcc.c-torture/execute/20021204-1.c: New test.
--- gcc/testsuite/gcc.c-torture/execute/20021204-1.c.jj 2002-12-04 20:35:40.000000000 +0100
+++ gcc/testsuite/gcc.c-torture/execute/20021204-1.c 2002-12-04 20:35:04.000000000 +0100
@@ -0,0 +1,25 @@
+/* This test was miscompiled when using sibling call optimization,
+ because X ? Y : Y - 1 optimization changed X into !X in place
+ and haven't reverted it if do_store_flag was successful, so
+ when expanding the expression the second time it was
+ !X ? Y : Y - 1. */
+
+extern void abort (void);
+extern void exit (int);
+
+void foo (int x)
+{
+ if (x != 1)
+ abort ();
+}
+
+int z;
+
+int main (int argc, char **argv)
+{
+ char *a = "test";
+ char *b = a + 2;
+
+ foo (z > 0 ? b - a : b - a - 1);
+ exit (0);
+}
--- gcc/expr.c.jj 2002-11-28 17:07:33.000000000 +0100
+++ gcc/expr.c 2002-12-04 20:21:30.000000000 +0100
@@ -8618,6 +8618,7 @@ expand_expr (exp, target, tmode, modifie
&& TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<')
{
rtx result;
+ tree cond;
optab boptab = (TREE_CODE (binary_op) == PLUS_EXPR
? (TYPE_TRAP_SIGNED (TREE_TYPE (binary_op))
? addv_optab : add_optab)
@@ -8627,20 +8628,14 @@ expand_expr (exp, target, tmode, modifie
: TREE_CODE (binary_op) == BIT_IOR_EXPR ? ior_optab
: xor_optab);
- /* If we had X ? A : A + 1, do this as A + (X == 0).
-
- We have to invert the truth value here and then put it
- back later if do_store_flag fails. We cannot simply copy
- TREE_OPERAND (exp, 0) to another variable and modify that
- because invert_truthvalue can modify the tree pointed to
- by its argument. */
+ /* If we had X ? A : A + 1, do this as A + (X == 0). */
if (singleton == TREE_OPERAND (exp, 1))
- TREE_OPERAND (exp, 0)
- = invert_truthvalue (TREE_OPERAND (exp, 0));
+ cond = invert_truthvalue (TREE_OPERAND (exp, 0));
+ else
+ cond = TREE_OPERAND (exp, 0);
- result = do_store_flag (TREE_OPERAND (exp, 0),
- (safe_from_p (temp, singleton, 1)
- ? temp : NULL_RTX),
+ result = do_store_flag (cond, (safe_from_p (temp, singleton, 1)
+ ? temp : NULL_RTX),
mode, BRANCH_COST <= 1);
if (result != 0 && ! integer_onep (TREE_OPERAND (binary_op, 1)))
@@ -8658,9 +8653,6 @@ expand_expr (exp, target, tmode, modifie
return expand_binop (mode, boptab, op1, result, temp,
unsignedp, OPTAB_LIB_WIDEN);
}
- else if (singleton == TREE_OPERAND (exp, 1))
- TREE_OPERAND (exp, 0)
- = invert_truthvalue (TREE_OPERAND (exp, 0));
}
do_pending_stack_adjust ();
Jakub