xref: /libCEED/backends/hip-ref/ceed-hip-ref-vector.c (revision bc246734e1a318011d33a38eecea04c89961ac52)
1 // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors.
2 // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
3 //
4 // SPDX-License-Identifier: BSD-2-Clause
5 //
6 // This file is part of CEED:  http://github.com/ceed
7 
8 #include <ceed.h>
9 #include <ceed/backend.h>
10 #include <math.h>
11 #include <stdbool.h>
12 #include <string.h>
13 #include <hip/hip_runtime.h>
14 
15 #include "../hip/ceed-hip-common.h"
16 #include "ceed-hip-ref.h"
17 
18 //------------------------------------------------------------------------------
19 // Check if host/device sync is needed
20 //------------------------------------------------------------------------------
21 static inline int CeedVectorNeedSync_Hip(const CeedVector vec, CeedMemType mem_type, bool *need_sync) {
22   CeedVector_Hip *impl;
23   CeedCallBackend(CeedVectorGetData(vec, &impl));
24 
25   bool has_valid_array = false;
26   CeedCallBackend(CeedVectorHasValidArray(vec, &has_valid_array));
27   switch (mem_type) {
28     case CEED_MEM_HOST:
29       *need_sync = has_valid_array && !impl->h_array;
30       break;
31     case CEED_MEM_DEVICE:
32       *need_sync = has_valid_array && !impl->d_array;
33       break;
34   }
35 
36   return CEED_ERROR_SUCCESS;
37 }
38 
39 //------------------------------------------------------------------------------
40 // Sync host to device
41 //------------------------------------------------------------------------------
42 static inline int CeedVectorSyncH2D_Hip(const CeedVector vec) {
43   Ceed ceed;
44   CeedCallBackend(CeedVectorGetCeed(vec, &ceed));
45   CeedVector_Hip *impl;
46   CeedCallBackend(CeedVectorGetData(vec, &impl));
47 
48   CeedSize length;
49   CeedCallBackend(CeedVectorGetLength(vec, &length));
50   size_t bytes = length * sizeof(CeedScalar);
51 
52   CeedCheck(impl->h_array, ceed, CEED_ERROR_BACKEND, "No valid host data to sync to device");
53 
54   if (impl->d_array_borrowed) {
55     impl->d_array = impl->d_array_borrowed;
56   } else if (impl->d_array_owned) {
57     impl->d_array = impl->d_array_owned;
58   } else {
59     CeedCallHip(ceed, hipMalloc((void **)&impl->d_array_owned, bytes));
60     impl->d_array = impl->d_array_owned;
61   }
62 
63   CeedCallHip(ceed, hipMemcpy(impl->d_array, impl->h_array, bytes, hipMemcpyHostToDevice));
64 
65   return CEED_ERROR_SUCCESS;
66 }
67 
68 //------------------------------------------------------------------------------
69 // Sync device to host
70 //------------------------------------------------------------------------------
71 static inline int CeedVectorSyncD2H_Hip(const CeedVector vec) {
72   Ceed ceed;
73   CeedCallBackend(CeedVectorGetCeed(vec, &ceed));
74   CeedVector_Hip *impl;
75   CeedCallBackend(CeedVectorGetData(vec, &impl));
76 
77   CeedCheck(impl->d_array, ceed, CEED_ERROR_BACKEND, "No valid device data to sync to host");
78 
79   if (impl->h_array_borrowed) {
80     impl->h_array = impl->h_array_borrowed;
81   } else if (impl->h_array_owned) {
82     impl->h_array = impl->h_array_owned;
83   } else {
84     CeedSize length;
85     CeedCallBackend(CeedVectorGetLength(vec, &length));
86     CeedCallBackend(CeedCalloc(length, &impl->h_array_owned));
87     impl->h_array = impl->h_array_owned;
88   }
89 
90   CeedSize length;
91   CeedCallBackend(CeedVectorGetLength(vec, &length));
92   size_t bytes = length * sizeof(CeedScalar);
93   CeedCallHip(ceed, hipMemcpy(impl->h_array, impl->d_array, bytes, hipMemcpyDeviceToHost));
94 
95   return CEED_ERROR_SUCCESS;
96 }
97 
98 //------------------------------------------------------------------------------
99 // Sync arrays
100 //------------------------------------------------------------------------------
101 static int CeedVectorSyncArray_Hip(const CeedVector vec, CeedMemType mem_type) {
102   // Check whether device/host sync is needed
103   bool need_sync = false;
104   CeedCallBackend(CeedVectorNeedSync_Hip(vec, mem_type, &need_sync));
105   if (!need_sync) return CEED_ERROR_SUCCESS;
106 
107   switch (mem_type) {
108     case CEED_MEM_HOST:
109       return CeedVectorSyncD2H_Hip(vec);
110     case CEED_MEM_DEVICE:
111       return CeedVectorSyncH2D_Hip(vec);
112   }
113   return CEED_ERROR_UNSUPPORTED;
114 }
115 
116 //------------------------------------------------------------------------------
117 // Set all pointers as invalid
118 //------------------------------------------------------------------------------
119 static inline int CeedVectorSetAllInvalid_Hip(const CeedVector vec) {
120   CeedVector_Hip *impl;
121   CeedCallBackend(CeedVectorGetData(vec, &impl));
122 
123   impl->h_array = NULL;
124   impl->d_array = NULL;
125 
126   return CEED_ERROR_SUCCESS;
127 }
128 
129 //------------------------------------------------------------------------------
130 // Check if CeedVector has any valid pointers
131 //------------------------------------------------------------------------------
132 static inline int CeedVectorHasValidArray_Hip(const CeedVector vec, bool *has_valid_array) {
133   CeedVector_Hip *impl;
134   CeedCallBackend(CeedVectorGetData(vec, &impl));
135 
136   *has_valid_array = !!impl->h_array || !!impl->d_array;
137 
138   return CEED_ERROR_SUCCESS;
139 }
140 
141 //------------------------------------------------------------------------------
142 // Check if has any array of given type
143 //------------------------------------------------------------------------------
144 static inline int CeedVectorHasArrayOfType_Hip(const CeedVector vec, CeedMemType mem_type, bool *has_array_of_type) {
145   CeedVector_Hip *impl;
146   CeedCallBackend(CeedVectorGetData(vec, &impl));
147 
148   switch (mem_type) {
149     case CEED_MEM_HOST:
150       *has_array_of_type = !!impl->h_array_borrowed || !!impl->h_array_owned;
151       break;
152     case CEED_MEM_DEVICE:
153       *has_array_of_type = !!impl->d_array_borrowed || !!impl->d_array_owned;
154       break;
155   }
156 
157   return CEED_ERROR_SUCCESS;
158 }
159 
160 //------------------------------------------------------------------------------
161 // Check if has borrowed array of given type
162 //------------------------------------------------------------------------------
163 static inline int CeedVectorHasBorrowedArrayOfType_Hip(const CeedVector vec, CeedMemType mem_type, bool *has_borrowed_array_of_type) {
164   CeedVector_Hip *impl;
165   CeedCallBackend(CeedVectorGetData(vec, &impl));
166 
167   switch (mem_type) {
168     case CEED_MEM_HOST:
169       *has_borrowed_array_of_type = !!impl->h_array_borrowed;
170       break;
171     case CEED_MEM_DEVICE:
172       *has_borrowed_array_of_type = !!impl->d_array_borrowed;
173       break;
174   }
175 
176   return CEED_ERROR_SUCCESS;
177 }
178 
179 //------------------------------------------------------------------------------
180 // Set array from host
181 //------------------------------------------------------------------------------
182 static int CeedVectorSetArrayHost_Hip(const CeedVector vec, const CeedCopyMode copy_mode, CeedScalar *array) {
183   CeedVector_Hip *impl;
184   CeedCallBackend(CeedVectorGetData(vec, &impl));
185 
186   switch (copy_mode) {
187     case CEED_COPY_VALUES: {
188       CeedSize length;
189       if (!impl->h_array_owned) {
190         CeedCallBackend(CeedVectorGetLength(vec, &length));
191         CeedCallBackend(CeedMalloc(length, &impl->h_array_owned));
192       }
193       impl->h_array_borrowed = NULL;
194       impl->h_array          = impl->h_array_owned;
195       if (array) {
196         CeedSize length;
197         CeedCallBackend(CeedVectorGetLength(vec, &length));
198         size_t bytes = length * sizeof(CeedScalar);
199         memcpy(impl->h_array, array, bytes);
200       }
201     } break;
202     case CEED_OWN_POINTER:
203       CeedCallBackend(CeedFree(&impl->h_array_owned));
204       impl->h_array_owned    = array;
205       impl->h_array_borrowed = NULL;
206       impl->h_array          = array;
207       break;
208     case CEED_USE_POINTER:
209       CeedCallBackend(CeedFree(&impl->h_array_owned));
210       impl->h_array_borrowed = array;
211       impl->h_array          = array;
212       break;
213   }
214 
215   return CEED_ERROR_SUCCESS;
216 }
217 
218 //------------------------------------------------------------------------------
219 // Set array from device
220 //------------------------------------------------------------------------------
221 static int CeedVectorSetArrayDevice_Hip(const CeedVector vec, const CeedCopyMode copy_mode, CeedScalar *array) {
222   Ceed ceed;
223   CeedCallBackend(CeedVectorGetCeed(vec, &ceed));
224   CeedVector_Hip *impl;
225   CeedCallBackend(CeedVectorGetData(vec, &impl));
226 
227   switch (copy_mode) {
228     case CEED_COPY_VALUES: {
229       CeedSize length;
230       CeedCallBackend(CeedVectorGetLength(vec, &length));
231       size_t bytes = length * sizeof(CeedScalar);
232       if (!impl->d_array_owned) {
233         CeedCallHip(ceed, hipMalloc((void **)&impl->d_array_owned, bytes));
234       }
235       impl->d_array_borrowed = NULL;
236       impl->d_array          = impl->d_array_owned;
237       if (array) {
238         CeedCallHip(ceed, hipMemcpy(impl->d_array, array, bytes, hipMemcpyDeviceToDevice));
239       }
240     } break;
241     case CEED_OWN_POINTER:
242       CeedCallHip(ceed, hipFree(impl->d_array_owned));
243       impl->d_array_owned    = array;
244       impl->d_array_borrowed = NULL;
245       impl->d_array          = array;
246       break;
247     case CEED_USE_POINTER:
248       CeedCallHip(ceed, hipFree(impl->d_array_owned));
249       impl->d_array_owned    = NULL;
250       impl->d_array_borrowed = array;
251       impl->d_array          = array;
252       break;
253   }
254 
255   return CEED_ERROR_SUCCESS;
256 }
257 
258 //------------------------------------------------------------------------------
259 // Set the array used by a vector,
260 //   freeing any previously allocated array if applicable
261 //------------------------------------------------------------------------------
262 static int CeedVectorSetArray_Hip(const CeedVector vec, const CeedMemType mem_type, const CeedCopyMode copy_mode, CeedScalar *array) {
263   Ceed ceed;
264   CeedCallBackend(CeedVectorGetCeed(vec, &ceed));
265   CeedVector_Hip *impl;
266   CeedCallBackend(CeedVectorGetData(vec, &impl));
267 
268   CeedCallBackend(CeedVectorSetAllInvalid_Hip(vec));
269   switch (mem_type) {
270     case CEED_MEM_HOST:
271       return CeedVectorSetArrayHost_Hip(vec, copy_mode, array);
272     case CEED_MEM_DEVICE:
273       return CeedVectorSetArrayDevice_Hip(vec, copy_mode, array);
274   }
275 
276   return CEED_ERROR_UNSUPPORTED;
277 }
278 
279 //------------------------------------------------------------------------------
280 // Set host array to value
281 //------------------------------------------------------------------------------
282 static int CeedHostSetValue_Hip(CeedScalar *h_array, CeedInt length, CeedScalar val) {
283   for (int i = 0; i < length; i++) h_array[i] = val;
284   return CEED_ERROR_SUCCESS;
285 }
286 
287 //------------------------------------------------------------------------------
288 // Set device array to value (impl in .hip file)
289 //------------------------------------------------------------------------------
290 int CeedDeviceSetValue_Hip(CeedScalar *d_array, CeedInt length, CeedScalar val);
291 
292 //------------------------------------------------------------------------------
293 // Set a vector to a value,
294 //------------------------------------------------------------------------------
295 static int CeedVectorSetValue_Hip(CeedVector vec, CeedScalar val) {
296   Ceed ceed;
297   CeedCallBackend(CeedVectorGetCeed(vec, &ceed));
298   CeedVector_Hip *impl;
299   CeedCallBackend(CeedVectorGetData(vec, &impl));
300   CeedSize length;
301   CeedCallBackend(CeedVectorGetLength(vec, &length));
302 
303   // Set value for synced device/host array
304   if (!impl->d_array && !impl->h_array) {
305     if (impl->d_array_borrowed) {
306       impl->d_array = impl->d_array_borrowed;
307     } else if (impl->h_array_borrowed) {
308       impl->h_array = impl->h_array_borrowed;
309     } else if (impl->d_array_owned) {
310       impl->d_array = impl->d_array_owned;
311     } else if (impl->h_array_owned) {
312       impl->h_array = impl->h_array_owned;
313     } else {
314       CeedCallBackend(CeedVectorSetArray(vec, CEED_MEM_DEVICE, CEED_COPY_VALUES, NULL));
315     }
316   }
317   if (impl->d_array) {
318     CeedCallBackend(CeedDeviceSetValue_Hip(impl->d_array, length, val));
319   }
320   if (impl->h_array) {
321     CeedCallBackend(CeedHostSetValue_Hip(impl->h_array, length, val));
322   }
323 
324   return CEED_ERROR_SUCCESS;
325 }
326 
327 //------------------------------------------------------------------------------
328 // Vector Take Array
329 //------------------------------------------------------------------------------
330 static int CeedVectorTakeArray_Hip(CeedVector vec, CeedMemType mem_type, CeedScalar **array) {
331   Ceed ceed;
332   CeedCallBackend(CeedVectorGetCeed(vec, &ceed));
333   CeedVector_Hip *impl;
334   CeedCallBackend(CeedVectorGetData(vec, &impl));
335 
336   // Sync array to requested mem_type
337   CeedCallBackend(CeedVectorSyncArray(vec, mem_type));
338 
339   // Update pointer
340   switch (mem_type) {
341     case CEED_MEM_HOST:
342       (*array)               = impl->h_array_borrowed;
343       impl->h_array_borrowed = NULL;
344       impl->h_array          = NULL;
345       break;
346     case CEED_MEM_DEVICE:
347       (*array)               = impl->d_array_borrowed;
348       impl->d_array_borrowed = NULL;
349       impl->d_array          = NULL;
350       break;
351   }
352 
353   return CEED_ERROR_SUCCESS;
354 }
355 
356 //------------------------------------------------------------------------------
357 // Core logic for array syncronization for GetArray.
358 //   If a different memory type is most up to date, this will perform a copy
359 //------------------------------------------------------------------------------
360 static int CeedVectorGetArrayCore_Hip(const CeedVector vec, const CeedMemType mem_type, CeedScalar **array) {
361   Ceed ceed;
362   CeedCallBackend(CeedVectorGetCeed(vec, &ceed));
363   CeedVector_Hip *impl;
364   CeedCallBackend(CeedVectorGetData(vec, &impl));
365 
366   // Sync array to requested mem_type
367   CeedCallBackend(CeedVectorSyncArray(vec, mem_type));
368 
369   // Update pointer
370   switch (mem_type) {
371     case CEED_MEM_HOST:
372       *array = impl->h_array;
373       break;
374     case CEED_MEM_DEVICE:
375       *array = impl->d_array;
376       break;
377   }
378 
379   return CEED_ERROR_SUCCESS;
380 }
381 
382 //------------------------------------------------------------------------------
383 // Get read-only access to a vector via the specified mem_type
384 //------------------------------------------------------------------------------
385 static int CeedVectorGetArrayRead_Hip(const CeedVector vec, const CeedMemType mem_type, const CeedScalar **array) {
386   return CeedVectorGetArrayCore_Hip(vec, mem_type, (CeedScalar **)array);
387 }
388 
389 //------------------------------------------------------------------------------
390 // Get read/write access to a vector via the specified mem_type
391 //------------------------------------------------------------------------------
392 static int CeedVectorGetArray_Hip(const CeedVector vec, const CeedMemType mem_type, CeedScalar **array) {
393   CeedVector_Hip *impl;
394   CeedCallBackend(CeedVectorGetData(vec, &impl));
395 
396   CeedCallBackend(CeedVectorGetArrayCore_Hip(vec, mem_type, array));
397 
398   CeedCallBackend(CeedVectorSetAllInvalid_Hip(vec));
399   switch (mem_type) {
400     case CEED_MEM_HOST:
401       impl->h_array = *array;
402       break;
403     case CEED_MEM_DEVICE:
404       impl->d_array = *array;
405       break;
406   }
407 
408   return CEED_ERROR_SUCCESS;
409 }
410 
411 //------------------------------------------------------------------------------
412 // Get write access to a vector via the specified mem_type
413 //------------------------------------------------------------------------------
414 static int CeedVectorGetArrayWrite_Hip(const CeedVector vec, const CeedMemType mem_type, CeedScalar **array) {
415   CeedVector_Hip *impl;
416   CeedCallBackend(CeedVectorGetData(vec, &impl));
417 
418   bool has_array_of_type = true;
419   CeedCallBackend(CeedVectorHasArrayOfType_Hip(vec, mem_type, &has_array_of_type));
420   if (!has_array_of_type) {
421     // Allocate if array is not yet allocated
422     CeedCallBackend(CeedVectorSetArray(vec, mem_type, CEED_COPY_VALUES, NULL));
423   } else {
424     // Select dirty array
425     switch (mem_type) {
426       case CEED_MEM_HOST:
427         if (impl->h_array_borrowed) impl->h_array = impl->h_array_borrowed;
428         else impl->h_array = impl->h_array_owned;
429         break;
430       case CEED_MEM_DEVICE:
431         if (impl->d_array_borrowed) impl->d_array = impl->d_array_borrowed;
432         else impl->d_array = impl->d_array_owned;
433     }
434   }
435 
436   return CeedVectorGetArray_Hip(vec, mem_type, array);
437 }
438 
439 //------------------------------------------------------------------------------
440 // Get the norm of a CeedVector
441 //------------------------------------------------------------------------------
442 static int CeedVectorNorm_Hip(CeedVector vec, CeedNormType type, CeedScalar *norm) {
443   Ceed ceed;
444   CeedCallBackend(CeedVectorGetCeed(vec, &ceed));
445   CeedVector_Hip *impl;
446   CeedCallBackend(CeedVectorGetData(vec, &impl));
447   CeedSize length;
448   CeedCallBackend(CeedVectorGetLength(vec, &length));
449   hipblasHandle_t handle;
450   CeedCallBackend(CeedHipGetHipblasHandle(ceed, &handle));
451 
452   // Compute norm
453   const CeedScalar *d_array;
454   CeedCallBackend(CeedVectorGetArrayRead(vec, CEED_MEM_DEVICE, &d_array));
455   switch (type) {
456     case CEED_NORM_1: {
457       if (CEED_SCALAR_TYPE == CEED_SCALAR_FP32) {
458         CeedCallHipblas(ceed, hipblasSasum(handle, length, (float *)d_array, 1, (float *)norm));
459       } else {
460         CeedCallHipblas(ceed, hipblasDasum(handle, length, (double *)d_array, 1, (double *)norm));
461       }
462       break;
463     }
464     case CEED_NORM_2: {
465       if (CEED_SCALAR_TYPE == CEED_SCALAR_FP32) {
466         CeedCallHipblas(ceed, hipblasSnrm2(handle, length, (float *)d_array, 1, (float *)norm));
467       } else {
468         CeedCallHipblas(ceed, hipblasDnrm2(handle, length, (double *)d_array, 1, (double *)norm));
469       }
470       break;
471     }
472     case CEED_NORM_MAX: {
473       CeedInt indx;
474       if (CEED_SCALAR_TYPE == CEED_SCALAR_FP32) {
475         CeedCallHipblas(ceed, hipblasIsamax(handle, length, (float *)d_array, 1, &indx));
476       } else {
477         CeedCallHipblas(ceed, hipblasIdamax(handle, length, (double *)d_array, 1, &indx));
478       }
479       CeedScalar normNoAbs;
480       CeedCallHip(ceed, hipMemcpy(&normNoAbs, impl->d_array + indx - 1, sizeof(CeedScalar), hipMemcpyDeviceToHost));
481       *norm = fabs(normNoAbs);
482       break;
483     }
484   }
485   CeedCallBackend(CeedVectorRestoreArrayRead(vec, &d_array));
486 
487   return CEED_ERROR_SUCCESS;
488 }
489 
490 //------------------------------------------------------------------------------
491 // Take reciprocal of a vector on host
492 //------------------------------------------------------------------------------
493 static int CeedHostReciprocal_Hip(CeedScalar *h_array, CeedInt length) {
494   for (int i = 0; i < length; i++) {
495     if (fabs(h_array[i]) > CEED_EPSILON) h_array[i] = 1. / h_array[i];
496   }
497   return CEED_ERROR_SUCCESS;
498 }
499 
500 //------------------------------------------------------------------------------
501 // Take reciprocal of a vector on device (impl in .cu file)
502 //------------------------------------------------------------------------------
503 int CeedDeviceReciprocal_Hip(CeedScalar *d_array, CeedInt length);
504 
505 //------------------------------------------------------------------------------
506 // Take reciprocal of a vector
507 //------------------------------------------------------------------------------
508 static int CeedVectorReciprocal_Hip(CeedVector vec) {
509   Ceed ceed;
510   CeedCallBackend(CeedVectorGetCeed(vec, &ceed));
511   CeedVector_Hip *impl;
512   CeedCallBackend(CeedVectorGetData(vec, &impl));
513   CeedSize length;
514   CeedCallBackend(CeedVectorGetLength(vec, &length));
515 
516   // Set value for synced device/host array
517   if (impl->d_array) CeedCallBackend(CeedDeviceReciprocal_Hip(impl->d_array, length));
518   if (impl->h_array) CeedCallBackend(CeedHostReciprocal_Hip(impl->h_array, length));
519 
520   return CEED_ERROR_SUCCESS;
521 }
522 
523 //------------------------------------------------------------------------------
524 // Compute x = alpha x on the host
525 //------------------------------------------------------------------------------
526 static int CeedHostScale_Hip(CeedScalar *x_array, CeedScalar alpha, CeedInt length) {
527   for (int i = 0; i < length; i++) x_array[i] *= alpha;
528   return CEED_ERROR_SUCCESS;
529 }
530 
531 //------------------------------------------------------------------------------
532 // Compute x = alpha x on device (impl in .cu file)
533 //------------------------------------------------------------------------------
534 int CeedDeviceScale_Hip(CeedScalar *x_array, CeedScalar alpha, CeedInt length);
535 
536 //------------------------------------------------------------------------------
537 // Compute x = alpha x
538 //------------------------------------------------------------------------------
539 static int CeedVectorScale_Hip(CeedVector x, CeedScalar alpha) {
540   Ceed ceed;
541   CeedCallBackend(CeedVectorGetCeed(x, &ceed));
542   CeedVector_Hip *x_impl;
543   CeedCallBackend(CeedVectorGetData(x, &x_impl));
544   CeedSize length;
545   CeedCallBackend(CeedVectorGetLength(x, &length));
546 
547   // Set value for synced device/host array
548   if (x_impl->d_array) CeedCallBackend(CeedDeviceScale_Hip(x_impl->d_array, alpha, length));
549   if (x_impl->h_array) CeedCallBackend(CeedHostScale_Hip(x_impl->h_array, alpha, length));
550 
551   return CEED_ERROR_SUCCESS;
552 }
553 
554 //------------------------------------------------------------------------------
555 // Compute y = alpha x + y on the host
556 //------------------------------------------------------------------------------
557 static int CeedHostAXPY_Hip(CeedScalar *y_array, CeedScalar alpha, CeedScalar *x_array, CeedInt length) {
558   for (int i = 0; i < length; i++) y_array[i] += alpha * x_array[i];
559   return CEED_ERROR_SUCCESS;
560 }
561 
562 //------------------------------------------------------------------------------
563 // Compute y = alpha x + y on device (impl in .cu file)
564 //------------------------------------------------------------------------------
565 int CeedDeviceAXPY_Hip(CeedScalar *y_array, CeedScalar alpha, CeedScalar *x_array, CeedInt length);
566 
567 //------------------------------------------------------------------------------
568 // Compute y = alpha x + y
569 //------------------------------------------------------------------------------
570 static int CeedVectorAXPY_Hip(CeedVector y, CeedScalar alpha, CeedVector x) {
571   Ceed ceed;
572   CeedCallBackend(CeedVectorGetCeed(y, &ceed));
573   CeedVector_Hip *y_impl, *x_impl;
574   CeedCallBackend(CeedVectorGetData(y, &y_impl));
575   CeedCallBackend(CeedVectorGetData(x, &x_impl));
576   CeedSize length;
577   CeedCallBackend(CeedVectorGetLength(y, &length));
578 
579   // Set value for synced device/host array
580   if (y_impl->d_array) {
581     CeedCallBackend(CeedVectorSyncArray(x, CEED_MEM_DEVICE));
582     CeedCallBackend(CeedDeviceAXPY_Hip(y_impl->d_array, alpha, x_impl->d_array, length));
583   }
584   if (y_impl->h_array) {
585     CeedCallBackend(CeedVectorSyncArray(x, CEED_MEM_HOST));
586     CeedCallBackend(CeedHostAXPY_Hip(y_impl->h_array, alpha, x_impl->h_array, length));
587   }
588 
589   return CEED_ERROR_SUCCESS;
590 }
591 //------------------------------------------------------------------------------
592 // Compute y = alpha x + beta y on the host
593 //------------------------------------------------------------------------------
594 static int CeedHostAXPBY_Hip(CeedScalar *y_array, CeedScalar alpha, CeedScalar beta, CeedScalar *x_array, CeedInt length) {
595   for (int i = 0; i < length; i++) y_array[i] += alpha * x_array[i] + beta * y_array[i];
596   return CEED_ERROR_SUCCESS;
597 }
598 
599 //------------------------------------------------------------------------------
600 // Compute y = alpha x + beta y on device (impl in .cu file)
601 //------------------------------------------------------------------------------
602 int CeedDeviceAXPBY_Hip(CeedScalar *y_array, CeedScalar alpha, CeedScalar beta, CeedScalar *x_array, CeedInt length);
603 
604 //------------------------------------------------------------------------------
605 // Compute y = alpha x + beta y
606 //------------------------------------------------------------------------------
607 static int CeedVectorAXPBY_Hip(CeedVector y, CeedScalar alpha, CeedScalar beta, CeedVector x) {
608   Ceed ceed;
609   CeedCallBackend(CeedVectorGetCeed(y, &ceed));
610   CeedVector_Hip *y_impl, *x_impl;
611   CeedCallBackend(CeedVectorGetData(y, &y_impl));
612   CeedCallBackend(CeedVectorGetData(x, &x_impl));
613   CeedSize length;
614   CeedCallBackend(CeedVectorGetLength(y, &length));
615 
616   // Set value for synced device/host array
617   if (y_impl->d_array) {
618     CeedCallBackend(CeedVectorSyncArray(x, CEED_MEM_DEVICE));
619     CeedCallBackend(CeedDeviceAXPBY_Hip(y_impl->d_array, alpha, beta, x_impl->d_array, length));
620   }
621   if (y_impl->h_array) {
622     CeedCallBackend(CeedVectorSyncArray(x, CEED_MEM_HOST));
623     CeedCallBackend(CeedHostAXPBY_Hip(y_impl->h_array, alpha, beta, x_impl->h_array, length));
624   }
625 
626   return CEED_ERROR_SUCCESS;
627 }
628 
629 //------------------------------------------------------------------------------
630 // Compute the pointwise multiplication w = x .* y on the host
631 //------------------------------------------------------------------------------
632 static int CeedHostPointwiseMult_Hip(CeedScalar *w_array, CeedScalar *x_array, CeedScalar *y_array, CeedInt length) {
633   for (int i = 0; i < length; i++) w_array[i] = x_array[i] * y_array[i];
634   return CEED_ERROR_SUCCESS;
635 }
636 
637 //------------------------------------------------------------------------------
638 // Compute the pointwise multiplication w = x .* y on device (impl in .cu file)
639 //------------------------------------------------------------------------------
640 int CeedDevicePointwiseMult_Hip(CeedScalar *w_array, CeedScalar *x_array, CeedScalar *y_array, CeedInt length);
641 
642 //------------------------------------------------------------------------------
643 // Compute the pointwise multiplication w = x .* y
644 //------------------------------------------------------------------------------
645 static int CeedVectorPointwiseMult_Hip(CeedVector w, CeedVector x, CeedVector y) {
646   Ceed ceed;
647   CeedCallBackend(CeedVectorGetCeed(w, &ceed));
648   CeedVector_Hip *w_impl, *x_impl, *y_impl;
649   CeedCallBackend(CeedVectorGetData(w, &w_impl));
650   CeedCallBackend(CeedVectorGetData(x, &x_impl));
651   CeedCallBackend(CeedVectorGetData(y, &y_impl));
652   CeedSize length;
653   CeedCallBackend(CeedVectorGetLength(w, &length));
654 
655   // Set value for synced device/host array
656   if (!w_impl->d_array && !w_impl->h_array) {
657     CeedCallBackend(CeedVectorSetValue(w, 0.0));
658   }
659   if (w_impl->d_array) {
660     CeedCallBackend(CeedVectorSyncArray(x, CEED_MEM_DEVICE));
661     CeedCallBackend(CeedVectorSyncArray(y, CEED_MEM_DEVICE));
662     CeedCallBackend(CeedDevicePointwiseMult_Hip(w_impl->d_array, x_impl->d_array, y_impl->d_array, length));
663   }
664   if (w_impl->h_array) {
665     CeedCallBackend(CeedVectorSyncArray(x, CEED_MEM_HOST));
666     CeedCallBackend(CeedVectorSyncArray(y, CEED_MEM_HOST));
667     CeedCallBackend(CeedHostPointwiseMult_Hip(w_impl->h_array, x_impl->h_array, y_impl->h_array, length));
668   }
669 
670   return CEED_ERROR_SUCCESS;
671 }
672 
673 //------------------------------------------------------------------------------
674 // Destroy the vector
675 //------------------------------------------------------------------------------
676 static int CeedVectorDestroy_Hip(const CeedVector vec) {
677   Ceed ceed;
678   CeedCallBackend(CeedVectorGetCeed(vec, &ceed));
679   CeedVector_Hip *impl;
680   CeedCallBackend(CeedVectorGetData(vec, &impl));
681 
682   CeedCallHip(ceed, hipFree(impl->d_array_owned));
683   CeedCallBackend(CeedFree(&impl->h_array_owned));
684   CeedCallBackend(CeedFree(&impl));
685 
686   return CEED_ERROR_SUCCESS;
687 }
688 
689 //------------------------------------------------------------------------------
690 // Create a vector of the specified length (does not allocate memory)
691 //------------------------------------------------------------------------------
692 int CeedVectorCreate_Hip(CeedSize n, CeedVector vec) {
693   CeedVector_Hip *impl;
694   Ceed            ceed;
695   CeedCallBackend(CeedVectorGetCeed(vec, &ceed));
696 
697   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "HasValidArray", CeedVectorHasValidArray_Hip));
698   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "HasBorrowedArrayOfType", CeedVectorHasBorrowedArrayOfType_Hip));
699   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "SetArray", CeedVectorSetArray_Hip));
700   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "TakeArray", CeedVectorTakeArray_Hip));
701   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "SetValue", (int (*)())CeedVectorSetValue_Hip));
702   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "SyncArray", CeedVectorSyncArray_Hip));
703   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "GetArray", CeedVectorGetArray_Hip));
704   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "GetArrayRead", CeedVectorGetArrayRead_Hip));
705   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "GetArrayWrite", CeedVectorGetArrayWrite_Hip));
706   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "Norm", CeedVectorNorm_Hip));
707   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "Reciprocal", CeedVectorReciprocal_Hip));
708   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "Scale", (int (*)())CeedVectorScale_Hip));
709   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "AXPY", (int (*)())CeedVectorAXPY_Hip));
710   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "AXPBY", (int (*)())CeedVectorAXPBY_Hip));
711   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "PointwiseMult", CeedVectorPointwiseMult_Hip));
712   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "Destroy", CeedVectorDestroy_Hip));
713 
714   CeedCallBackend(CeedCalloc(1, &impl));
715   CeedCallBackend(CeedVectorSetData(vec, impl));
716 
717   return CEED_ERROR_SUCCESS;
718 }
719 
720 //------------------------------------------------------------------------------
721