@@ -50,8 +50,8 @@ namespace quda
5050
5151#ifdef QUAD_SUM
5252 __host__ __device__ inline double set (doubledouble &a) { return a.head (); }
53- __host__ __device__ inline double2 set (doubledouble2 &a) { return make_double2 ( a.x .head (), a.y .head ()) ; }
54- __host__ __device__ inline double3 set (doubledouble3 &a) { return make_double3 ( a.x .head (), a.y .head (), a.z .head ()) ; }
53+ __host__ __device__ inline double2 set (doubledouble2 &a) { return { a.x .head (), a.y .head ()} ; }
54+ __host__ __device__ inline double3 set (doubledouble3 &a) { return { a.x .head (), a.y .head (), a.z .head ()} ; }
5555 __host__ __device__ inline void sum (double &a, doubledouble &b) { a += b.head (); }
5656 __host__ __device__ inline void sum (double2 &a, doubledouble2 &b)
5757 {
@@ -99,20 +99,14 @@ namespace quda
9999 Helper struct that contains the meta data required for
100100 read and writing to a spinor field in the BLAS kernels.
101101 @tparam store_t Type used to store field in memory
102- @tparam N Length of vector
103102 */
104- template <typename store_t , int N, bool is_fixed> struct data_t {
105- store_t *spinor;
106- int stride;
107- unsigned int cb_offset;
108- data_t () :
109- spinor (nullptr ),
110- stride (0 ),
111- cb_offset (0 )
112- {}
113-
103+ template <typename store_t , bool is_fixed> struct data_t {
104+ store_t *spinor = nullptr ;
105+ int stride = 0 ;
106+ unsigned int cb_offset = 0 ;
107+ data_t () = default ;
114108 data_t (const ColorSpinorField &x) :
115- spinor (x.data<store_t *>()), stride(x.VolumeCB()), cb_offset(x.Bytes() / (2 * sizeof (store_t ) * N ))
109+ spinor (x.data<store_t *>()), stride(x.VolumeCB()), cb_offset(x.Bytes() / (2 * sizeof (store_t )))
116110 {}
117111 };
118112
@@ -122,28 +116,20 @@ namespace quda
122116 specialized variant for fixed-point fields where need to store
123117 the meta data for the norm field.
124118 @tparam store_t Type used to store field in memory
125- @tparam N Length of vector
126119 */
127- template <typename store_t , int N > struct data_t <store_t , N , true > {
120+ template <typename store_t > struct data_t <store_t , true > {
128121 using norm_t = float ;
129- store_t *spinor;
130- norm_t *norm;
131- int stride;
132- unsigned int cb_offset;
133- unsigned int cb_norm_offset;
134- data_t () :
135- spinor (nullptr ),
136- norm (nullptr ),
137- stride (0 ),
138- cb_offset (0 ),
139- cb_norm_offset (0 )
140- {}
141-
122+ store_t *spinor = nullptr ;
123+ norm_t *norm = nullptr ;
124+ int stride = 0 ;
125+ unsigned int cb_offset = 0 ;
126+ unsigned int cb_norm_offset = 0 ;
127+ data_t () = default ;
142128 data_t (const ColorSpinorField &x) :
143129 spinor (x.data<store_t *>()),
144130 norm (static_cast <norm_t *>(x.Norm())),
145131 stride (x.VolumeCB()),
146- cb_offset (x.Bytes() / (2 * sizeof (store_t ) * N )),
132+ cb_offset (x.Bytes() / (2 * sizeof (store_t ))),
147133 cb_norm_offset (x.Bytes() / (2 * sizeof (norm_t )))
148134 {}
149135 };
@@ -156,10 +142,9 @@ namespace quda
156142 template <typename store_t , int N> struct Spinor {
157143 using Vector = typename VectorType<store_t , N>::type;
158144 using norm_t = float ;
159- data_t <store_t , N, isFixed<store_t >::value> data;
160-
161- Spinor () {}
145+ data_t <store_t , isFixed<store_t >::value> data;
162146
147+ Spinor () = default ;
163148 Spinor (const ColorSpinorField &x) : data(x) {}
164149
165150 /* *
@@ -234,37 +219,37 @@ namespace quda
234219 array<real, len> v_;
235220
236221 constexpr int M = len / N;
222+ constexpr int Nrem = len - M * N;
237223#pragma unroll
238224 for (int i = 0 ; i < M; i++) {
239225 // first load from memory
240- Vector vecTmp = vector_load<Vector >(data.spinor , parity * data.cb_offset + x + data.stride * i);
226+ auto vecTmp = vector_load<store_t , N >(data.spinor + parity * data.cb_offset , data.stride * i + x );
241227 // now copy into output and scale
242- #pragma unroll
243- // for (int j = 0; j < N; j++) copy_and_scale(v_[i * N + j], reinterpret_cast<store_t *>(&vecTmp)[j], nrm);
244- for (int j = 0 ; j < N; j++) copy_and_scale (v_[i * N + j], elem (vecTmp, j), nrm);
228+ copy_and_scale (&v_[i * N], vecTmp, nrm);
229+ }
230+ if constexpr (Nrem > 0 ) {
231+ // first load from memory
232+ auto vecTmp = vector_load<store_t , Nrem>(data.spinor + parity * data.cb_offset + data.stride * M * N, x);
233+ // now copy into output and scale
234+ copy_and_scale (&v_[M * N], vecTmp, nrm);
245235 }
246236
237+ #pragma unroll
247238 for (int i = 0 ; i < n; i++) { v[i] = complex <real>(v_[2 * i + 0 ], v_[2 * i + 1 ]); }
248239 } else {
249240 // specialized path for half precision staggered
250- using Vector = int4 ;
251241 auto cb_offset = data.cb_norm_offset / 4 ;
252242 norm_t nrm;
253243 array<real, len> v_;
254244
255245 // first load from memory
256- Vector vecTmp = vector_load<Vector >(data.spinor , parity * cb_offset + x);
246+ auto vecTmp = vector_load<store_t , 8 >(data.spinor , parity * cb_offset + x);
257247
258248 // extract norm
259- memcpy (&nrm, &vecTmp.w , sizeof (norm_t ));
260- array<short , 6 > vecTmpShort;
261- memcpy (&vecTmpShort, &vecTmp, sizeof (vecTmpShort));
249+ memcpy (&nrm, &vecTmp[6 ], sizeof (norm_t ));
262250
263251 // now copy into output and scale
264- #pragma unroll
265- // for (int i = 0; i < len; i++) copy_and_scale(v_[i], reinterpret_cast<store_t *>(&vecTmp)[i], nrm);
266- // for (int i = 0; i < len; i++) copy_and_scale(v_[i], elem(vecTmp, i), nrm);
267- for (int i = 0 ; i < len; i++) copy_and_scale (v_[i], vecTmpShort[i], nrm);
252+ copy_and_scale (&v_[0 ], vecTmp, nrm);
268253
269254#pragma unroll
270255 for (int i = 0 ; i < n; i++) { v[i] = complex <real>(v_[2 * i + 0 ], v_[2 * i + 1 ]); }
@@ -284,56 +269,47 @@ namespace quda
284269 {
285270 constexpr int len = 2 * n; // real-valued length
286271
287- if constexpr (!(n == 3 && isHalf<store_t >::value)) {
288- array<real, len> v_;
289-
290- if constexpr (isFixed<store_t >::value) {
291- real scale_inv = store_norm<isFixed<store_t >::value, real, n>(v, data.norm [x + parity * data.cb_norm_offset ]);
292- #pragma unroll
293- for (int i = 0 ; i < n; i++) {
294- v_[2 * i + 0 ] = scale_inv * v[i].real ();
295- v_[2 * i + 1 ] = scale_inv * v[i].imag ();
296- }
297- } else {
272+ array<real, len> v_;
298273#pragma unroll
299- for (int i = 0 ; i < n; i++) {
300- v_[2 * i + 0 ] = v[i].real ();
301- v_[2 * i + 1 ] = v[i].imag ();
302- }
303- }
274+ for (int i = 0 ; i < n; i++) {
275+ v_[2 * i + 0 ] = v[i].real ();
276+ v_[2 * i + 1 ] = v[i].imag ();
277+ }
278+
279+ if constexpr (!(n == 3 && isHalf<store_t >::value)) {
280+ real scale_inv = 0.0 ;
281+ if constexpr (isFixed<store_t >::value)
282+ scale_inv = store_norm<isFixed<store_t >::value, real, n>(v, data.norm [x + parity * data.cb_norm_offset ]);
304283
305284 constexpr int M = len / N;
285+ constexpr int Nrem = len - M * N;
306286#pragma unroll
307287 for (int i = 0 ; i < M; i++) {
308- Vector vecTmp;
288+ array< store_t , N> vecTmp;
309289 // first do scalar copy converting into storage type
310- #pragma unroll
311- // for (int j = 0; j < N; j++) copy_scaled(reinterpret_cast<store_t *>(&vecTmp)[j], v_[i * N + j]);
312- for (int j = 0 ; j < N; j++) copy_scaled (elem (vecTmp, j), v_[i * N + j]);
290+ copy_and_scale<store_t , real, N>(vecTmp, &v_[i * N], scale_inv);
291+ // second do vectorized copy into memory
292+ vector_store (data.spinor + parity * data.cb_offset , data.stride * i + x, vecTmp);
293+ }
294+
295+ if constexpr (Nrem > 0 ) {
296+ array<store_t , Nrem> vecTmp;
297+ // first do copy converting into storage type
298+ copy_and_scale<store_t , real, Nrem>(vecTmp, &v_[M * N], scale_inv);
313299 // second do vectorized copy into memory
314- vector_store (data.spinor , parity * data.cb_offset + x + data.stride * i , vecTmp);
300+ vector_store (data.spinor + parity * data.cb_offset + data.stride * M * N, x , vecTmp);
315301 }
316302 } else {
317303 // specialized path for half precision staggered
318- using Vector = int4 ;
319304 auto cb_offset = data.cb_norm_offset / 4 ;
320305 norm_t norm;
321306 norm_t scale_inv = store_norm<isFixed<store_t >::value, real, n>(v, norm);
322- array<real, len> v_;
323- #pragma unroll
324- for (int i = 0 ; i < n; i++) {
325- v_[2 * i + 0 ] = scale_inv * v[i].real ();
326- v_[2 * i + 1 ] = scale_inv * v[i].imag ();
327- }
328307
329- Vector vecTmp;
330- memcpy (&vecTmp.w , &norm, sizeof (norm_t )); // pack the norm
331- array<short , 6 > vecTmpShort;
332- #pragma unroll
333- // for (int i = 0; i < len; i++) copy_scaled(reinterpret_cast<store_t *>(&vecTmp)[i], v_[i]);
334- // for (int i = 0; i < len; i++) copy_scaled(elem(vecTmp, i), v_[i]);
335- for (int i = 0 ; i < len; i++) copy_scaled (vecTmpShort[i], v_[i]);
336- memcpy (&vecTmp, &vecTmpShort, sizeof (vecTmpShort));
308+ array<store_t , 8 > vecTmp;
309+ memcpy (&vecTmp[6 ], &norm, sizeof (norm_t )); // pack the norm
310+ array<store_t , 6 > vecTmp2;
311+ copy_and_scale<store_t , real, 6 >(vecTmp2, &v_[0 ], scale_inv);
312+ std::memcpy (&vecTmp, &vecTmp2, sizeof (vecTmp2));
337313 // second do vectorized copy into memory
338314 vector_store (data.spinor , parity * cb_offset + x, vecTmp);
339315 }
@@ -349,42 +325,59 @@ namespace quda
349325 @tparam site_unroll Whether we enforce all site components must
350326 be unrolled onto the same thread (required for fixed-point precision)
351327 */
352- template <typename store_t , bool GPU , int nSpin, bool site_unroll > constexpr int n_vector () { return 0 ; }
328+ template <typename store_t , bool GPU > constexpr int n_vector (int , int ) { return 0 ; }
353329
354330 // native ordering
355- template <> constexpr int n_vector<double , true , 4 , false >() { return 2 ; }
356- template <> constexpr int n_vector<double , true , 1 , false >() { return 2 ; }
357-
358- template <> constexpr int n_vector<double , true , 4 , true >() { return 2 ; }
359- template <> constexpr int n_vector<double , true , 1 , true >() { return 2 ; }
360-
361- template <> constexpr int n_vector<float , true , 4 , false >() { return 4 ; }
362- template <> constexpr int n_vector<float , true , 1 , false >() { return 4 ; }
331+ template <> constexpr int n_vector<double , true >(int nSpin, int site_unroll)
332+ {
333+ if (site_unroll)
334+ return nSpin == 4 ? colorspinor::get_vector_order<double >(24 ) : colorspinor::get_vector_order<double >(6 );
335+ else
336+ return colorspinor::get_vector_order<double >(4 );
337+ }
363338
364- template <> constexpr int n_vector<float , true , 4 , true >() { return 4 ; }
365- template <> constexpr int n_vector<float , true , 1 , true >() { return 2 ; }
339+ template <> constexpr int n_vector<float , true >(int nSpin, int site_unroll)
340+ {
341+ if (site_unroll)
342+ return nSpin == 4 ? colorspinor::get_vector_order<float >(24 ) : colorspinor::get_vector_order<float >(6 );
343+ else
344+ return colorspinor::get_vector_order<float >(8 );
345+ }
366346
367- template <> constexpr int n_vector<short , true , 4 , true >() { return QUDA_ORDER_FP ; }
368- template <> constexpr int n_vector<short , true , 1 , true >() { return 2 ; }
347+ template <> constexpr int n_vector<short , true >(int nSpin, int site_unroll)
348+ {
349+ if (site_unroll)
350+ return nSpin == 4 ? colorspinor::get_vector_order<short >(24 ) : colorspinor::get_vector_order<short >(6 );
351+ else
352+ return colorspinor::get_vector_order<short >(16 );
353+ }
369354
370- template <> constexpr int n_vector<int8_t , true , 4 , true >() { return QUDA_ORDER_FP ; }
371- template <> constexpr int n_vector<int8_t , true , 1 , true >() { return 2 ; }
355+ template <> constexpr int n_vector<int8_t , true >(int nSpin, int site_unroll)
356+ {
357+ if (site_unroll)
358+ return nSpin == 4 ? colorspinor::get_vector_order<int8_t >(24 ) : colorspinor::get_vector_order<int8_t >(6 );
359+ else
360+ return colorspinor::get_vector_order<int8_t >(16 );
361+ }
372362
373363 // Just use float-2/float-4 ordering on CPU when not site unrolling
374- template <> constexpr int n_vector<double , false , 4 , false >() { return 2 ; }
375- template <> constexpr int n_vector<double , false , 1 , false >() { return 2 ; }
376- template <> constexpr int n_vector<float , false , 4 , false >() { return 4 ; }
377- template <> constexpr int n_vector<float , false , 1 , false >() { return 4 ; }
378-
379- // AoS ordering is used on CPU uses when we are site unrolling
380- template <> constexpr int n_vector<double , false , 4 , true >() { return 24 ; }
381- template <> constexpr int n_vector<double , false , 1 , true >() { return 6 ; }
382- template <> constexpr int n_vector<float , false , 4 , true >() { return 24 ; }
383- template <> constexpr int n_vector<float , false , 1 , true >() { return 6 ; }
384- template <> constexpr int n_vector<short , false , 4 , true >() { return 24 ; }
385- template <> constexpr int n_vector<short , false , 1 , true >() { return 6 ; }
386- template <> constexpr int n_vector<int8_t , false , 4 , true >() { return 24 ; }
387- template <> constexpr int n_vector<int8_t , false , 1 , true >() { return 6 ; }
364+ template <> constexpr int n_vector<double , false >(int nSpin, int site_unroll)
365+ {
366+ if (site_unroll) {
367+ return nSpin * 6 ;
368+ } else {
369+ return 2 ;
370+ }
371+ }
372+
373+ template <> constexpr int n_vector<float , false >(int nSpin, int site_unroll)
374+ {
375+ if (site_unroll) {
376+ return nSpin * 6 ;
377+ } else {
378+ return 4 ;
379+ }
380+ }
388381
389382 template <template <typename ...> class Functor ,
390383 template <template <typename ...> class , typename store_t , typename y_store_t , int , typename > class Blas ,
0 commit comments