In this pr, we have a -1 in type __int128.  Since this value can be
represented in a HOST_WIDE_INT, we expand this to a const_int.

The expansion from tree to rtl happens in expand_builtin_atomic_store.  And as
with most of our builtins, we then pass off the rtl to another routine for
expansion.  When we fill in the blanks of the expand_operand in
expand_atomic_compare_and_swap, we've forgotten that the const_int is of
TImode.  Then convert_modes attempts to zero-extend what it assumes is a
narrower mode and we get corrupt data.

For a bit I thought that the bug was in convert_modes, but honestly any
change I make there merely moves the bug around.  The biggest problem is
that we've lost the mode.

Given that we lose the mode through any of 10 stack frames, I believe it
to be implausible to adjust all of the call frames in optabs.c.  The real
bug is that const_int doesn't carry a mode.

The most isolated patch I can come up with, especially since we ought to
fix this in 4.8 branch as well, is to only allow expansion of wide int
modes to const_int when they're positive.

Thoughts?


r~
        PR rtl/58542
        * emit-rtl.c (immed_double_const): Use const_double for negative
        numbers of very wide modes.


diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index b0fc846..d055f56 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -545,7 +545,10 @@ immed_double_const (HOST_WIDE_INT i0, HOST_WIDE_INT i1, 
enum machine_mode mode)
     }
 
   /* If this integer fits in one word, return a CONST_INT.  */
-  if ((i1 == 0 && i0 >= 0) || (i1 == ~0 && i0 < 0))
+  /* ??? On occasion we lose track of the original mode, and a CONST_INT gets
+     interpreted incorrectly for modes larger than HOST_BITS_PER_WIDE_INT.
+     If we only use CONST_INT for positive values, we work around that.  */
+  if (i1 == 0 && i0 >= 0)
     return GEN_INT (i0);
 
   /* We use VOIDmode for integers.  */

Reply via email to