Hi,

Brooks Moses reported a bug with code that sets a single element of a
vector to a given value and the rest of the vector to zero.  This is
implemented in rs6000_expand_vector_set, which uses a vperm instruction
to place the nonzero value.  As usual, we need to adjust the permute
control vector and swap the order of the input operands.  I added a test
case based on the bug report.

Bootstrapped and tested on powerpc64{,le}-unknown-linux-gnu with no
regressions.  The new test now passes for both endiannesses.  Is this ok
for trunk?

Thanks,
Bill


gcc:

2013-10-31  Bill Schmidt  <wschm...@vnet.linux.ibm.com>

        * config/rs6000/rs6000.c (rs6000_expand_vector_set): Adjust for
        little endian.

gcc/testsuite:

2013-10-31  Bill Schmidt  <wschm...@vnet.linux.ibm.com>

        * gcc.dg/vmx/vec-set.c: New.


Index: gcc/testsuite/gcc.dg/vmx/vec-set.c
===================================================================
--- gcc/testsuite/gcc.dg/vmx/vec-set.c  (revision 0)
+++ gcc/testsuite/gcc.dg/vmx/vec-set.c  (revision 0)
@@ -0,0 +1,14 @@
+#include "harness.h"
+
+vector short
+vec_set (short m)
+{
+  return (vector short){m, 0, 0, 0, 0, 0, 0, 0};
+}
+
+static void test()
+{
+  check (vec_all_eq (vec_set (7),
+                    ((vector short){7, 0, 0, 0, 0, 0, 0, 0})),
+        "vec_set");
+}
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c  (revision 204192)
+++ gcc/config/rs6000/rs6000.c  (working copy)
@@ -5529,10 +5529,27 @@ rs6000_expand_vector_set (rtx target, rtx val, int
     XVECEXP (mask, 0, elt*width + i)
       = GEN_INT (i + 0x10);
   x = gen_rtx_CONST_VECTOR (V16QImode, XVEC (mask, 0));
-  x = gen_rtx_UNSPEC (mode,
-                     gen_rtvec (3, target, reg,
-                                force_reg (V16QImode, x)),
-                     UNSPEC_VPERM);
+
+  if (!BYTES_BIG_ENDIAN)
+    {
+      /* Invert selector.  */
+      rtx splat = gen_rtx_VEC_DUPLICATE (V16QImode,
+                                        gen_rtx_CONST_INT (QImode, -1));
+      rtx tmp = gen_reg_rtx (V16QImode);
+      emit_move_insn (tmp, splat);
+      x = gen_rtx_MINUS (V16QImode, tmp, force_reg (V16QImode, x));
+      emit_move_insn (tmp, x);
+
+      /* Permute with operands reversed and adjusted selector.  */
+      x = gen_rtx_UNSPEC (mode, gen_rtvec (3, reg, target, tmp),
+                         UNSPEC_VPERM);
+    }
+  else 
+    x = gen_rtx_UNSPEC (mode,
+                       gen_rtvec (3, target, reg,
+                                  force_reg (V16QImode, x)),
+                       UNSPEC_VPERM);
+
   emit_insn (gen_rtx_SET (VOIDmode, target, x));
 }
 


Reply via email to