It turns out that when doing a vector shift by 2, the optab routine passes (const_int 2) to convert_modes with oldmode set to the mode of the shift (e.g. something like V8HI). When the target mode is a real integer mode like SImode, mainline just ignores that oldmode and returns a (const_int 2) regardless, but wide-int doesn't.
Saying that (const_int 2) has a vector mode is almost certainly a bug that ought to be trapped by an assert, but we're not trying to fight that battle here. The current code: if (CONST_SCALAR_INT_P (x) && GET_MODE_CLASS (mode) == MODE_INT && (oldmode == VOIDmode || GET_MODE_CLASS (oldmode) == MODE_INT)) is already coping with bogus oldmodes, just not in the way that other routines seem to expect. Tested on powerpc64-linux-gnu and x86_64-linux-gnu. This fixed several testsuite changes on the ARM targets. OK to install? Thanks, Richard Index: gcc/expr.c =================================================================== --- gcc/expr.c 2013-11-02 10:34:44.083635650 +0000 +++ gcc/expr.c 2013-11-02 10:42:55.179233840 +0000 @@ -712,13 +712,12 @@ convert_modes (enum machine_mode mode, e return x; if (CONST_SCALAR_INT_P (x) - && GET_MODE_CLASS (mode) == MODE_INT - && (oldmode == VOIDmode || GET_MODE_CLASS (oldmode) == MODE_INT)) + && GET_MODE_CLASS (mode) == MODE_INT) { /* If the caller did not tell us the old mode, then there is not much to do with respect to canonization. We have to assume that all the bits are significant. */ - if (oldmode == VOIDmode) + if (GET_MODE_CLASS (oldmode) != MODE_INT) oldmode = MAX_MODE_INT; wide_int w = wide_int::from (std::make_pair (x, oldmode), GET_MODE_PRECISION (mode),