http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51681
--- Comment #5 from Uros Bizjak <ubizjak at gmail dot com> 2012-01-02 12:35:25 UTC --- Patch: --cut here-- Index: ia64.c =================================================================== --- ia64.c (revision 182780) +++ ia64.c (working copy) @@ -11085,7 +11085,7 @@ static bool expand_vec_perm_shrp (struct expand_vec_perm_d *d) { unsigned i, nelt = d->nelt, shift, mask; - rtx tmp, op0, op1;; + rtx tmp, hi, lo; /* ??? Don't force V2SFmode into the integer registers. */ if (d->vmode == V2SFmode) @@ -11101,6 +11101,11 @@ expand_vec_perm_shrp (struct expand_vec_perm_d *d) if (d->testing_p) return true; + hi = shift < nelt ? d->op1 : d->op0; + lo = shift < nelt ? d->op0 : d->op1; + + shift %= nelt; + shift *= GET_MODE_UNIT_SIZE (d->vmode) * BITS_PER_UNIT; /* We've eliminated the shift 0 case via expand_vec_perm_identity. */ @@ -11113,11 +11118,9 @@ expand_vec_perm_shrp (struct expand_vec_perm_d *d) shift = 64 - shift; tmp = gen_reg_rtx (DImode); - op0 = (shift < nelt ? d->op0 : d->op1); - op1 = (shift < nelt ? d->op1 : d->op0); - op0 = gen_lowpart (DImode, op0); - op1 = gen_lowpart (DImode, op1); - emit_insn (gen_shrp (tmp, op0, op1, GEN_INT (shift))); + hi = gen_lowpart (DImode, hi); + lo = gen_lowpart (DImode, lo); + emit_insn (gen_shrp (tmp, hi, lo, GEN_INT (shift))); emit_move_insn (d->target, gen_lowpart (d->vmode, tmp)); return true; --cut here-- Just a bunch of mix-ups; where high/low part goes, shift value is not adjusted after operand swap, and shift value is compared in *bits* to number of elements.