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. */