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