1 /* { dg-do run { target { powerpc*-*-linux* && lp64 } } } */
2 /* { dg-skip-if "" { powerpc*-*-darwin* } } */
3 /* { dg-skip-if "" { powerpc*-*-*spe* } } */
4 /* { dg-require-effective-target p8vector_hw } */
5 /* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
6 /* { dg-options "-mcpu=power8 -O2" } */
7 
8 #include <stddef.h>
9 #include <stdlib.h>
10 #include <altivec.h>
11 
12 #ifdef DEBUG
13 #include <stdio.h>
14 #define UNUSED
15 
16 #ifdef __LITTLE_ENDIAN__
17 #define HI_WORD 1
18 #define LO_WORD 0
19 #else
20 #define HI_WORD 0
21 #define LO_WORD 1
22 #endif
23 
24 #else
25 #define UNUSED __attribute__((__unused__))
26 #endif
27 
28 #ifndef S_TYPE
29 #define S_TYPE __uint128_t
30 #endif
31 
32 #ifndef V_TYPE
33 #define V_TYPE vector S_TYPE
34 #endif
35 
36 static int compare (S_TYPE, V_TYPE, const char *, const char *)
37   __attribute__((__noinline__));
38 
39 static int
compare(S_TYPE scalar,V_TYPE vect,const char * nl UNUSED,const char * which UNUSED)40 compare (S_TYPE scalar,
41 	 V_TYPE vect,
42 	 const char *nl    UNUSED,
43 	 const char *which UNUSED)
44 {
45   unsigned long scalar_lo = (unsigned long) scalar;
46   unsigned long scalar_hi = (unsigned long) (scalar >> 64);
47   unsigned long vect_lo;
48   unsigned long vect_hi;
49   vector long long tmp;
50   int ret;
51 
52   __asm__ ("mfvsrd %0,%x3\n\t"
53 	   "xxpermdi %x2,%x3,%x3,3\n\t"
54 	   "mfvsrd %1,%x2"
55 	   : "=r" (vect_hi),
56 	     "=r" (vect_lo),
57 	     "=wa" (tmp)
58 	   : "wa" (vect));
59 
60   ret = (scalar_lo != vect_lo) || (scalar_hi != vect_hi);
61 
62 #ifdef DEBUG
63   printf ("%s%s: 0x%.16lx %.16lx %s 0x%.16lx %.16lx\n",
64 	  nl, which,
65 	  scalar_hi, scalar_lo,
66 	  (ret) ? "!=" : "==",
67 	  vect_hi, vect_lo);
68 
69   fflush (stdout);
70 #endif
71 
72   return ret;
73 }
74 
75 static void convert_via_mem (V_TYPE *, S_TYPE *)
76   __attribute__((__noinline__));
77 
78 static void
convert_via_mem(V_TYPE * v,S_TYPE * s)79 convert_via_mem (V_TYPE *v, S_TYPE *s)
80 {
81   *v = (V_TYPE) { *s };
82   __asm__ volatile ("nop"
83 		    : "+m" (*s), "+m" (*v)
84 		    :
85 		    : "memory");
86 
87 }
88 
89 
90 /* Check if vadduqm returns the same values as normal 128-bit add.  */
91 
92 /* Values to add together.  */
93 const static struct {
94   unsigned long hi_1;
95   unsigned long lo_1;
96   unsigned long hi_2;
97   unsigned long lo_2;
98 } values[] = {
99   { 0x0000000000000000UL, 0xfffffffffffffffeUL,
100     0x0000000000000000UL, 0x0000000000000002UL },
101   { 0x0000000000000000UL, 0x0000000000000002UL,
102     0x0000000000000000UL, 0xfffffffffffffffeUL },
103   { 0xffffffffffffffffUL, 0xfffffffffffffffeUL,
104     0x0000000000000000UL, 0x0000000000000002UL },
105   { 0xfffffffffffffff2UL, 0xffffffffffffffffUL,
106     0x0000000000000002UL, 0x0000000000000000UL },
107   { 0x7fffffffffffffffUL, 0xfffffffffffffffeUL,
108     0x0000000000000000UL, 0x0000000000000002UL },
109   { 0x7ffffffffffffff2UL, 0xffffffffffffffffUL,
110     0x0000000000000002UL, 0x0000000000000000UL },
111 };
112 
113 int
main(void)114 main (void)
115 {
116   int reg_errors = 0;
117   int mem_errors = 0;
118   size_t i;
119   const char *nl = "";
120 
121   for (i = 0; i < sizeof (values) / sizeof (values[0]); i++)
122     {
123       S_TYPE s_reg_res, s_reg_in1, s_reg_in2, s_mem_res, s_mem_in1, s_mem_in2;
124       V_TYPE v_reg_res, v_reg_in1, v_reg_in2, v_mem_res, v_mem_in1, v_mem_in2;
125 
126       s_reg_in1 = ((((S_TYPE)values[i].hi_1 << 64)) + ((S_TYPE)values[i].lo_1));
127       reg_errors += compare (s_reg_in1, (V_TYPE) { s_reg_in1 }, nl, "reg, in1");
128 
129       s_reg_in2 = ((((S_TYPE)values[i].hi_2 << 64)) + ((S_TYPE)values[i].lo_2));
130       reg_errors += compare (s_reg_in2, (V_TYPE) { s_reg_in2 }, "", "reg, in2");
131 
132       s_reg_res = s_reg_in1 + s_reg_in2;
133 
134       v_reg_in1 = (V_TYPE) { s_reg_in1 };
135       v_reg_in2 = (V_TYPE) { s_reg_in2 };
136       v_reg_res = vec_vadduqm (v_reg_in1, v_reg_in2);
137       reg_errors += compare (s_reg_res, v_reg_res, "", "reg, res");
138 
139       s_mem_in1 = s_reg_in1;
140       convert_via_mem (&v_mem_in1, &s_mem_in1);
141       mem_errors += compare (s_mem_in1, (V_TYPE) { s_mem_in1 }, "\n", "mem, in1");
142 
143       s_mem_in2 = s_reg_in2;
144       convert_via_mem (&v_mem_in2, &s_mem_in2);
145       mem_errors += compare (s_mem_in2, (V_TYPE) { s_mem_in2 }, "", "mem, in2");
146 
147       s_mem_res = s_mem_in1 + s_mem_in2;
148       v_mem_res = vec_vadduqm (v_mem_in1, v_mem_in2);
149       mem_errors += compare (s_mem_res, v_mem_res, "", "mem, res");
150 
151       nl = "\n";
152     }
153 
154 #ifdef DEBUG
155   putchar ('\n');
156 
157   if (!reg_errors)
158     fputs ("no errors found on register operations\n", stdout);
159   else
160     printf ("%d error%s found on register operations\n",
161 	    reg_errors,
162 	    (reg_errors == 1) ? "s" : "");
163 
164   if (!mem_errors)
165     fputs ("no errors found on memory operations\n", stdout);
166   else
167     printf ("%d error%s found on memory operations\n",
168 	    mem_errors,
169 	    (mem_errors == 1) ? "s" : "");
170 
171   fflush (stdout);
172 #endif
173 
174   if ((reg_errors + mem_errors) != 0)
175     abort ();
176 
177   return 0;
178 }
179