1  /* { dg-do compile } */
       2  /* { dg-require-effective-target powerpc_p8vector_ok } */
       3  /* { dg-options "-mdejagnu-cpu=power8 -O3 " } */
       4  
       5  /* Previous versions of this test required that the assembler does not
       6     contain xxpermdi or xxswapd.  However, with the more sophisticated
       7     code generation used today, it is now possible that xxpermdi (aka
       8     xxswapd) show up without being part of a lxvd2x or stxvd2x
       9     sequence.  */
      10  
      11  #include <altivec.h>
      12  
      13  extern void abort (void);
      14  
      15  const vector char y = { 0, 1, 2, 3,
      16  			4, 5, 6, 7,
      17  			8, 9, 10, 11,
      18  			12, 13, 14, 15 };
      19  
      20  vector char x, z;
      21  
      22  vector char
      23  foo (void)
      24  {
      25    return y;			/* Remove 1 swap and use lvx.  */
      26  }
      27  
      28  vector char
      29  foo1 (void)
      30  {
      31    x = y;			/* Remove 2 redundant swaps here.  */
      32    return x;			/* Remove 1 swap and use lvx.  */
      33  }
      34  
      35  void __attribute__ ((noinline))
      36  fill_local (vector char *vp)
      37  {
      38    *vp = x;			/* Remove 2 redundant swaps here.  */
      39  }
      40  
      41  /* Test aligned load from local.  */
      42  vector char
      43  foo2 (void)
      44  {
      45    vector char v;
      46  
      47    /* Need to be clever here because v will normally reside in a
      48       register rather than memory.  */
      49    fill_local (&v);
      50    return v;			/* Remove 1 swap and use lvx.  */
      51  }
      52  
      53  
      54  /* Test aligned load from pointer.  */
      55  vector char
      56  foo3 (vector char *arg)
      57  {
      58    return *arg;			/* Remove 1 swap and use lvx.  */
      59  }
      60  
      61  /* In this structure, the compiler should insert padding to assure
      62     that a_vector is properly aligned.  */
      63  struct bar {
      64    char a_field;
      65    vector char a_vector;
      66  };
      67  
      68  vector char
      69  foo4 (struct bar *bp)
      70  {
      71    return bp->a_vector;		/* Remove 1 swap and use lvx.  */
      72  }
      73  
      74  /* Test aligned store to global.  */
      75  void
      76  baz (vector char arg)
      77  {
      78    x = arg;			/* Remove 1 swap and use stvx.  */
      79  }
      80  
      81  void __attribute__ ((noinline))
      82  copy_local (vector char *arg)
      83  {
      84    x = *arg;			/* Remove 2 redundant swaps.  */
      85  }
      86  
      87  
      88  /* Test aligned store to local.  */
      89  void
      90  baz1 (vector char arg)
      91  {
      92    vector char v;
      93  
      94    /* Need cleverness, because v will normally reside in a register
      95       rather than memory.  */
      96    v = arg;			/* Aligned store to local: remove 1
      97  				   swap and use stvx.  */
      98    copy_local (&v);
      99  }
     100  
     101  /* Test aligned store to pointer.  */
     102  void
     103  baz2 (vector char *arg1, vector char arg2)
     104  {
     105    /* Assume arg2 resides in register.  */
     106    *arg1 = arg2;			/* Remove 1 swap and use stvx.  */
     107  }
     108  
     109  void
     110  baz3 (struct bar *bp, vector char v)
     111  {
     112    /* Assume v resides in register.  */
     113    bp->a_vector = v;		/* Remove 1 swap and use stvx.  */
     114  }
     115  
     116  int
     117  main (int argc, char *argv[])
     118  {
     119    vector char fetched_value = foo ();
     120    if (fetched_value[0] != 0 || fetched_value[15] != 15)
     121      abort ();
     122  
     123    fetched_value = foo1 ();
     124    if (fetched_value[1] != 1 || fetched_value[14] != 14)
     125      abort ();
     126  
     127    fetched_value = foo2 ();
     128    if (fetched_value[2] != 2 || fetched_value[13] != 13)
     129      abort ();
     130  
     131    fetched_value = foo3 (&x);
     132    if (fetched_value[3] != 3 || fetched_value[12] != 12)
     133      abort ();
     134  
     135    struct bar a_struct;
     136    a_struct.a_vector = x;	/* Remove 2 redundant swaps.  */
     137    fetched_value = foo4 (&a_struct);
     138    if (fetched_value[4] != 4 || fetched_value[11] != 11)
     139      abort ();
     140  
     141    for (int i = 0; i < 16; i++)
     142      z[i] = 15 - i;
     143  
     144    baz (z);
     145    if (x[0] != 15 || x[15] != 0)
     146      abort ();
     147  
     148    vector char source = { 8, 7, 6, 5, 4, 3, 2, 1,
     149  			 0, 9, 10, 11, 12, 13, 14, 15 };
     150  
     151    baz1 (source);
     152    if (x[3] != 5 || x[8] != 0)
     153      abort ();
     154  
     155    vector char dest;
     156    baz2 (&dest, source);
     157    if (dest[4] != 4 || dest[1] != 7)
     158      abort ();
     159  
     160    baz3 (&a_struct, source);
     161    if (a_struct.a_vector[7] != 1 || a_struct.a_vector[15] != 15)
     162      abort ();
     163  
     164    return 0;
     165  }