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