xref: /libCEED/backends/hip-ref/ceed-hip-ref-vector.c (revision a3b195ef6dd39c849072dd5df2f934c50a4df099)
1 // Copyright (c) 2017-2025, 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   bool            has_valid_array = false;
24 
25   CeedCallBackend(CeedVectorGetData(vec, &impl));
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   return CEED_ERROR_SUCCESS;
36 }
37 
38 //------------------------------------------------------------------------------
39 // Sync host to device
40 //------------------------------------------------------------------------------
41 static inline int CeedVectorSyncH2D_Hip(const CeedVector vec) {
42   CeedSize        length;
43   size_t          bytes;
44   CeedVector_Hip *impl;
45 
46   CeedCallBackend(CeedVectorGetData(vec, &impl));
47 
48   CeedCheck(impl->h_array, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, "No valid host data to sync to device");
49 
50   CeedCallBackend(CeedVectorGetLength(vec, &length));
51   bytes = length * sizeof(CeedScalar);
52   if (impl->d_array_borrowed) {
53     impl->d_array = impl->d_array_borrowed;
54   } else if (impl->d_array_owned) {
55     impl->d_array = impl->d_array_owned;
56   } else {
57     CeedCallHip(CeedVectorReturnCeed(vec), hipMalloc((void **)&impl->d_array_owned, bytes));
58     impl->d_array = impl->d_array_owned;
59   }
60   CeedCallHip(CeedVectorReturnCeed(vec), hipMemcpy(impl->d_array, impl->h_array, bytes, hipMemcpyHostToDevice));
61   return CEED_ERROR_SUCCESS;
62 }
63 
64 //------------------------------------------------------------------------------
65 // Sync device to host
66 //------------------------------------------------------------------------------
67 static inline int CeedVectorSyncD2H_Hip(const CeedVector vec) {
68   CeedSize        length;
69   size_t          bytes;
70   CeedVector_Hip *impl;
71 
72   CeedCallBackend(CeedVectorGetData(vec, &impl));
73 
74   CeedCheck(impl->d_array, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, "No valid device data to sync to host");
75 
76   if (impl->h_array_borrowed) {
77     impl->h_array = impl->h_array_borrowed;
78   } else if (impl->h_array_owned) {
79     impl->h_array = impl->h_array_owned;
80   } else {
81     CeedSize length;
82 
83     CeedCallBackend(CeedVectorGetLength(vec, &length));
84     CeedCallBackend(CeedCalloc(length, &impl->h_array_owned));
85     impl->h_array = impl->h_array_owned;
86   }
87 
88   CeedCallBackend(CeedVectorGetLength(vec, &length));
89   bytes = length * sizeof(CeedScalar);
90   CeedCallHip(CeedVectorReturnCeed(vec), hipMemcpy(impl->h_array, impl->d_array, bytes, hipMemcpyDeviceToHost));
91   return CEED_ERROR_SUCCESS;
92 }
93 
94 //------------------------------------------------------------------------------
95 // Sync arrays
96 //------------------------------------------------------------------------------
97 static int CeedVectorSyncArray_Hip(const CeedVector vec, CeedMemType mem_type) {
98   bool            need_sync = false;
99   CeedVector_Hip *impl;
100 
101   // Sync for unified memory
102   CeedCallBackend(CeedVectorGetData(vec, &impl));
103   if (impl->has_unified_addressing && !impl->h_array_borrowed) {
104     CeedCallHip(CeedVectorReturnCeed(vec), hipDeviceSynchronize());
105     return CEED_ERROR_SUCCESS;
106   }
107 
108   // Check whether device/host sync is needed
109   CeedCallBackend(CeedVectorNeedSync_Hip(vec, mem_type, &need_sync));
110   if (!need_sync) return CEED_ERROR_SUCCESS;
111 
112   switch (mem_type) {
113     case CEED_MEM_HOST:
114       return CeedVectorSyncD2H_Hip(vec);
115     case CEED_MEM_DEVICE:
116       return CeedVectorSyncH2D_Hip(vec);
117   }
118   return CEED_ERROR_UNSUPPORTED;
119 }
120 
121 //------------------------------------------------------------------------------
122 // Set all pointers as invalid
123 //------------------------------------------------------------------------------
124 static inline int CeedVectorSetAllInvalid_Hip(const CeedVector vec) {
125   CeedVector_Hip *impl;
126 
127   CeedCallBackend(CeedVectorGetData(vec, &impl));
128   impl->h_array = NULL;
129   impl->d_array = NULL;
130   return CEED_ERROR_SUCCESS;
131 }
132 
133 //------------------------------------------------------------------------------
134 // Check if CeedVector has any valid pointer
135 //------------------------------------------------------------------------------
136 static inline int CeedVectorHasValidArray_Hip(const CeedVector vec, bool *has_valid_array) {
137   CeedVector_Hip *impl;
138 
139   CeedCallBackend(CeedVectorGetData(vec, &impl));
140   *has_valid_array = impl->h_array || impl->d_array;
141   return CEED_ERROR_SUCCESS;
142 }
143 
144 //------------------------------------------------------------------------------
145 // Check if has array of given type
146 //------------------------------------------------------------------------------
147 static inline int CeedVectorHasArrayOfType_Hip(const CeedVector vec, CeedMemType mem_type, bool *has_array_of_type) {
148   CeedVector_Hip *impl;
149 
150   CeedCallBackend(CeedVectorGetData(vec, &impl));
151   switch (mem_type) {
152     case CEED_MEM_HOST:
153       *has_array_of_type = impl->h_array_borrowed || impl->h_array_owned;
154       break;
155     case CEED_MEM_DEVICE:
156       *has_array_of_type = impl->d_array_borrowed || impl->d_array_owned;
157       break;
158   }
159   return CEED_ERROR_SUCCESS;
160 }
161 
162 //------------------------------------------------------------------------------
163 // Check if has borrowed array of given type
164 //------------------------------------------------------------------------------
165 static inline int CeedVectorHasBorrowedArrayOfType_Hip(const CeedVector vec, CeedMemType mem_type, bool *has_borrowed_array_of_type) {
166   CeedVector_Hip *impl;
167 
168   CeedCallBackend(CeedVectorGetData(vec, &impl));
169 
170   // Use device memory for unified memory
171   mem_type = impl->has_unified_addressing && !impl->h_array_borrowed ? CEED_MEM_DEVICE : mem_type;
172 
173   switch (mem_type) {
174     case CEED_MEM_HOST:
175       *has_borrowed_array_of_type = impl->h_array_borrowed;
176       break;
177     case CEED_MEM_DEVICE:
178       *has_borrowed_array_of_type = impl->d_array_borrowed;
179       break;
180   }
181   return CEED_ERROR_SUCCESS;
182 }
183 
184 //------------------------------------------------------------------------------
185 // Set array from host
186 //------------------------------------------------------------------------------
187 static int CeedVectorSetArrayHost_Hip(const CeedVector vec, const CeedCopyMode copy_mode, CeedScalar *array) {
188   CeedSize        length;
189   CeedVector_Hip *impl;
190 
191   CeedCallBackend(CeedVectorGetData(vec, &impl));
192   CeedCallBackend(CeedVectorGetLength(vec, &length));
193 
194   CeedCallBackend(CeedSetHostCeedScalarArray(array, copy_mode, length, (const CeedScalar **)&impl->h_array_owned,
195                                              (const CeedScalar **)&impl->h_array_borrowed, (const CeedScalar **)&impl->h_array));
196   return CEED_ERROR_SUCCESS;
197 }
198 
199 //------------------------------------------------------------------------------
200 // Set array from device
201 //------------------------------------------------------------------------------
202 static int CeedVectorSetArrayDevice_Hip(const CeedVector vec, const CeedCopyMode copy_mode, CeedScalar *array) {
203   CeedSize        length;
204   Ceed            ceed;
205   CeedVector_Hip *impl;
206 
207   CeedCallBackend(CeedVectorGetCeed(vec, &ceed));
208   CeedCallBackend(CeedVectorGetData(vec, &impl));
209   CeedCallBackend(CeedVectorGetLength(vec, &length));
210 
211   CeedCallBackend(CeedSetDeviceCeedScalarArray_Hip(ceed, array, copy_mode, length, (const CeedScalar **)&impl->d_array_owned,
212                                                    (const CeedScalar **)&impl->d_array_borrowed, (const CeedScalar **)&impl->d_array));
213   CeedCallBackend(CeedDestroy(&ceed));
214   return CEED_ERROR_SUCCESS;
215 }
216 
217 //------------------------------------------------------------------------------
218 // Set array with unified memory
219 //------------------------------------------------------------------------------
220 static int CeedVectorSetArrayUnifiedHostToDevice_Hip(const CeedVector vec, const CeedCopyMode copy_mode, CeedScalar *array) {
221   CeedSize        length;
222   Ceed            ceed;
223   CeedVector_Hip *impl;
224 
225   CeedCallBackend(CeedVectorGetCeed(vec, &ceed));
226   CeedCallBackend(CeedVectorGetData(vec, &impl));
227   CeedCallBackend(CeedVectorGetLength(vec, &length));
228 
229   switch (copy_mode) {
230     case CEED_COPY_VALUES:
231     case CEED_OWN_POINTER:
232       if (!impl->d_array) {
233         if (impl->d_array_borrowed) {
234           impl->d_array = impl->d_array_borrowed;
235         } else {
236           if (!impl->d_array_owned) CeedCallHip(ceed, hipMalloc((void **)&impl->d_array_owned, sizeof(CeedScalar) * length));
237           impl->d_array = impl->d_array_owned;
238         }
239       }
240       if (array) CeedCallHip(ceed, hipMemcpy(impl->d_array, array, sizeof(CeedScalar) * length, hipMemcpyHostToDevice));
241       if (copy_mode == CEED_OWN_POINTER) CeedCallBackend(CeedFree(&array));
242       break;
243     case CEED_USE_POINTER:
244       CeedCallHip(ceed, hipFree(impl->d_array_owned));
245       CeedCallBackend(CeedFree(&impl->h_array_owned));
246       impl->h_array_owned    = NULL;
247       impl->h_array_borrowed = array;
248       impl->d_array          = impl->h_array_borrowed;
249   }
250   CeedCallBackend(CeedDestroy(&ceed));
251   return CEED_ERROR_SUCCESS;
252 }
253 
254 //------------------------------------------------------------------------------
255 // Set the array used by a vector,
256 //   freeing any previously allocated array if applicable
257 //------------------------------------------------------------------------------
258 static int CeedVectorSetArray_Hip(const CeedVector vec, const CeedMemType mem_type, const CeedCopyMode copy_mode, CeedScalar *array) {
259   CeedVector_Hip *impl;
260 
261   CeedCallBackend(CeedVectorGetData(vec, &impl));
262   CeedCallBackend(CeedVectorSetAllInvalid_Hip(vec));
263   switch (mem_type) {
264     case CEED_MEM_HOST:
265       if (impl->has_unified_addressing) {
266         return CeedVectorSetArrayUnifiedHostToDevice_Hip(vec, copy_mode, array);
267       } else {
268         return CeedVectorSetArrayHost_Hip(vec, copy_mode, array);
269       }
270     case CEED_MEM_DEVICE:
271       return CeedVectorSetArrayDevice_Hip(vec, copy_mode, array);
272   }
273   return CEED_ERROR_UNSUPPORTED;
274 }
275 
276 //------------------------------------------------------------------------------
277 // Copy host array to value strided
278 //------------------------------------------------------------------------------
279 static int CeedHostCopyStrided_Hip(CeedScalar *h_array, CeedSize start, CeedSize stop, CeedSize step, CeedScalar *h_copy_array) {
280   for (CeedSize i = start; i < stop; i += step) h_copy_array[i] = h_array[i];
281   return CEED_ERROR_SUCCESS;
282 }
283 
284 //------------------------------------------------------------------------------
285 // Copy device array to value strided (impl in .hip.cpp file)
286 //------------------------------------------------------------------------------
287 int CeedDeviceCopyStrided_Hip(CeedScalar *d_array, CeedSize start, CeedSize stop, CeedSize step, CeedScalar *d_copy_array);
288 
289 //------------------------------------------------------------------------------
290 // Copy a vector to a value strided
291 //------------------------------------------------------------------------------
292 static int CeedVectorCopyStrided_Hip(CeedVector vec, CeedSize start, CeedSize stop, CeedSize step, CeedVector vec_copy) {
293   CeedSize        length;
294   CeedVector_Hip *impl;
295 
296   CeedCallBackend(CeedVectorGetData(vec, &impl));
297   {
298     CeedSize length_vec, length_copy;
299 
300     CeedCallBackend(CeedVectorGetLength(vec, &length_vec));
301     CeedCallBackend(CeedVectorGetLength(vec_copy, &length_copy));
302     length = length_vec < length_copy ? length_vec : length_copy;
303   }
304   if (stop == -1) stop = length;
305   // Set value for synced device/host array
306   if (impl->d_array) {
307     CeedScalar *copy_array;
308 
309     CeedCallBackend(CeedVectorGetArray(vec_copy, CEED_MEM_DEVICE, &copy_array));
310 #if (HIP_VERSION >= 60000000)
311     hipblasHandle_t handle;
312     Ceed            ceed;
313 
314     CeedCallBackend(CeedVectorGetCeed(vec, &ceed));
315     CeedCallBackend(CeedGetHipblasHandle_Hip(ceed, &handle));
316 #if defined(CEED_SCALAR_IS_FP32)
317     CeedCallHipblas(ceed, hipblasScopy_64(handle, (int64_t)(stop - start), impl->d_array + start, (int64_t)step, copy_array + start, (int64_t)step));
318 #else  /* CEED_SCALAR */
319     CeedCallHipblas(ceed, hipblasDcopy_64(handle, (int64_t)(stop - start), impl->d_array + start, (int64_t)step, copy_array + start, (int64_t)step));
320 #endif /* CEED_SCALAR */
321 #else  /* HIP_VERSION */
322     CeedCallBackend(CeedDeviceCopyStrided_Hip(impl->d_array, start, stop, step, copy_array));
323 #endif /* HIP_VERSION */
324     CeedCallBackend(CeedVectorRestoreArray(vec_copy, &copy_array));
325     impl->h_array = NULL;
326     CeedCallBackend(CeedDestroy(&ceed));
327   } else if (impl->h_array) {
328     CeedScalar *copy_array;
329 
330     CeedCallBackend(CeedVectorGetArray(vec_copy, CEED_MEM_HOST, &copy_array));
331     CeedCallBackend(CeedHostCopyStrided_Hip(impl->h_array, start, stop, step, copy_array));
332     CeedCallBackend(CeedVectorRestoreArray(vec_copy, &copy_array));
333     impl->d_array = NULL;
334   } else {
335     return CeedError(CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, "CeedVector must have valid data set");
336   }
337   return CEED_ERROR_SUCCESS;
338 }
339 
340 //------------------------------------------------------------------------------
341 // Set host array to value
342 //------------------------------------------------------------------------------
343 static int CeedHostSetValue_Hip(CeedScalar *h_array, CeedSize length, CeedScalar val) {
344   for (CeedSize i = 0; i < length; i++) h_array[i] = val;
345   return CEED_ERROR_SUCCESS;
346 }
347 
348 //------------------------------------------------------------------------------
349 // Set device array to value (impl in .hip file)
350 //------------------------------------------------------------------------------
351 int CeedDeviceSetValue_Hip(CeedScalar *d_array, CeedSize length, CeedScalar val);
352 
353 //------------------------------------------------------------------------------
354 // Set a vector to a value
355 //------------------------------------------------------------------------------
356 static int CeedVectorSetValue_Hip(CeedVector vec, CeedScalar val) {
357   CeedSize        length;
358   CeedVector_Hip *impl;
359   Ceed_Hip       *hip_data;
360 
361   CeedCallBackend(CeedVectorGetData(vec, &impl));
362   CeedCallBackend(CeedGetData(CeedVectorReturnCeed(vec), &hip_data));
363   CeedCallBackend(CeedVectorGetLength(vec, &length));
364   // Set value for synced device/host array
365   if (!impl->d_array && !impl->h_array) {
366     if (impl->d_array_borrowed) {
367       impl->d_array = impl->d_array_borrowed;
368     } else if (impl->h_array_borrowed) {
369       impl->h_array = impl->h_array_borrowed;
370     } else if (impl->d_array_owned) {
371       impl->d_array = impl->d_array_owned;
372     } else if (impl->h_array_owned) {
373       impl->h_array = impl->h_array_owned;
374     } else {
375       CeedCallBackend(CeedVectorSetArray(vec, CEED_MEM_DEVICE, CEED_COPY_VALUES, NULL));
376     }
377   }
378   if (impl->d_array) {
379     if (val == 0 && !impl->h_array_borrowed) {
380       CeedCallHip(CeedVectorReturnCeed(vec), hipMemset(impl->d_array, 0, length * sizeof(CeedScalar)));
381     } else {
382       CeedCallBackend(CeedDeviceSetValue_Hip(impl->d_array, length, val));
383     }
384     impl->h_array = NULL;
385   } else if (impl->h_array) {
386     CeedCallBackend(CeedHostSetValue_Hip(impl->h_array, length, val));
387     impl->d_array = NULL;
388   }
389   return CEED_ERROR_SUCCESS;
390 }
391 
392 //------------------------------------------------------------------------------
393 // Set host array to value strided
394 //------------------------------------------------------------------------------
395 static int CeedHostSetValueStrided_Hip(CeedScalar *h_array, CeedSize start, CeedSize stop, CeedSize step, CeedScalar val) {
396   for (CeedSize i = start; i < stop; i += step) h_array[i] = val;
397   return CEED_ERROR_SUCCESS;
398 }
399 
400 //------------------------------------------------------------------------------
401 // Set device array to value strided (impl in .hip.cpp file)
402 //------------------------------------------------------------------------------
403 int CeedDeviceSetValueStrided_Hip(CeedScalar *d_array, CeedSize start, CeedSize stop, CeedSize step, CeedScalar val);
404 
405 //------------------------------------------------------------------------------
406 // Set a vector to a value strided
407 //------------------------------------------------------------------------------
408 static int CeedVectorSetValueStrided_Hip(CeedVector vec, CeedSize start, CeedSize stop, CeedSize step, CeedScalar val) {
409   CeedSize        length;
410   CeedVector_Hip *impl;
411 
412   CeedCallBackend(CeedVectorGetData(vec, &impl));
413   CeedCallBackend(CeedVectorGetLength(vec, &length));
414   // Set value for synced device/host array
415   if (stop == -1) stop = length;
416   if (impl->d_array) {
417     CeedCallBackend(CeedDeviceSetValueStrided_Hip(impl->d_array, start, stop, step, val));
418     impl->h_array = NULL;
419   } else if (impl->h_array) {
420     CeedCallBackend(CeedHostSetValueStrided_Hip(impl->h_array, start, stop, step, val));
421     impl->d_array = NULL;
422   } else {
423     return CeedError(CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, "CeedVector must have valid data set");
424   }
425   return CEED_ERROR_SUCCESS;
426 }
427 
428 //------------------------------------------------------------------------------
429 // Vector Take Array
430 //------------------------------------------------------------------------------
431 static int CeedVectorTakeArray_Hip(CeedVector vec, CeedMemType mem_type, CeedScalar **array) {
432   CeedVector_Hip *impl;
433 
434   CeedCallBackend(CeedVectorGetData(vec, &impl));
435 
436   // Sync array to requested mem_type
437   CeedCallBackend(CeedVectorSyncArray(vec, mem_type));
438 
439   // Update pointer
440   switch (mem_type) {
441     case CEED_MEM_HOST:
442       (*array)               = impl->h_array_borrowed;
443       impl->h_array_borrowed = NULL;
444       impl->h_array          = NULL;
445       break;
446     case CEED_MEM_DEVICE:
447       (*array)               = impl->d_array_borrowed;
448       impl->d_array_borrowed = NULL;
449       impl->d_array          = NULL;
450       break;
451   }
452   return CEED_ERROR_SUCCESS;
453 }
454 
455 //------------------------------------------------------------------------------
456 // Core logic for array synchronization for GetArray.
457 //   If a different memory type is most up to date, this will perform a copy
458 //------------------------------------------------------------------------------
459 static int CeedVectorGetArrayCore_Hip(const CeedVector vec, CeedMemType mem_type, CeedScalar **array) {
460   CeedVector_Hip *impl;
461 
462   CeedCallBackend(CeedVectorGetData(vec, &impl));
463 
464   // Use device memory for unified memory
465   mem_type = impl->has_unified_addressing && !impl->h_array_borrowed ? CEED_MEM_DEVICE : mem_type;
466 
467   // Sync array to requested mem_type
468   CeedCallBackend(CeedVectorSyncArray(vec, mem_type));
469 
470   // Update pointer
471   switch (mem_type) {
472     case CEED_MEM_HOST:
473       *array = impl->h_array;
474       break;
475     case CEED_MEM_DEVICE:
476       *array = impl->d_array;
477       break;
478   }
479   return CEED_ERROR_SUCCESS;
480 }
481 
482 //------------------------------------------------------------------------------
483 // Get read-only access to a vector via the specified mem_type
484 //------------------------------------------------------------------------------
485 static int CeedVectorGetArrayRead_Hip(const CeedVector vec, const CeedMemType mem_type, const CeedScalar **array) {
486   return CeedVectorGetArrayCore_Hip(vec, mem_type, (CeedScalar **)array);
487 }
488 
489 //------------------------------------------------------------------------------
490 // Get read/write access to a vector via the specified mem_type
491 //------------------------------------------------------------------------------
492 static int CeedVectorGetArray_Hip(const CeedVector vec, CeedMemType mem_type, CeedScalar **array) {
493   CeedVector_Hip *impl;
494 
495   CeedCallBackend(CeedVectorGetData(vec, &impl));
496 
497   // Use device memory for unified memory
498   mem_type = impl->has_unified_addressing && !impl->h_array_borrowed ? CEED_MEM_DEVICE : mem_type;
499 
500   // 'Get' array and set only 'get'ed array as valid
501   CeedCallBackend(CeedVectorGetArrayCore_Hip(vec, mem_type, array));
502   CeedCallBackend(CeedVectorSetAllInvalid_Hip(vec));
503   switch (mem_type) {
504     case CEED_MEM_HOST:
505       impl->h_array = *array;
506       if (impl->has_unified_addressing) impl->d_array = *array;
507       break;
508     case CEED_MEM_DEVICE:
509       impl->d_array = *array;
510       break;
511   }
512   return CEED_ERROR_SUCCESS;
513 }
514 
515 //------------------------------------------------------------------------------
516 // Get write access to a vector via the specified mem_type
517 //------------------------------------------------------------------------------
518 static int CeedVectorGetArrayWrite_Hip(const CeedVector vec, CeedMemType mem_type, CeedScalar **array) {
519   bool            has_array_of_type = true;
520   CeedVector_Hip *impl;
521   Ceed_Hip       *hip_data;
522 
523   CeedCallBackend(CeedVectorGetData(vec, &impl));
524   CeedCallBackend(CeedGetData(CeedVectorReturnCeed(vec), &hip_data));
525 
526   // Use device memory for unified memory
527   mem_type = impl->has_unified_addressing && !impl->h_array_borrowed ? CEED_MEM_DEVICE : mem_type;
528 
529   CeedCallBackend(CeedVectorHasArrayOfType_Hip(vec, mem_type, &has_array_of_type));
530   if (!has_array_of_type) {
531     // Allocate if array is not yet allocated
532     CeedCallBackend(CeedVectorSetArray(vec, mem_type, CEED_COPY_VALUES, NULL));
533   } else {
534     // Select dirty array
535     switch (mem_type) {
536       case CEED_MEM_HOST:
537         if (impl->h_array_borrowed) impl->h_array = impl->h_array_borrowed;
538         else impl->h_array = impl->h_array_owned;
539         break;
540       case CEED_MEM_DEVICE:
541         if (impl->d_array_borrowed) impl->d_array = impl->d_array_borrowed;
542         else impl->d_array = impl->d_array_owned;
543     }
544   }
545   return CeedVectorGetArray_Hip(vec, mem_type, array);
546 }
547 
548 //------------------------------------------------------------------------------
549 // Get the norm of a CeedVector
550 //------------------------------------------------------------------------------
551 static int CeedVectorNorm_Hip(CeedVector vec, CeedNormType type, CeedScalar *norm) {
552   Ceed     ceed;
553   CeedSize length;
554 #if (HIP_VERSION < 60000000)
555   CeedSize num_calls;
556 #endif /* HIP_VERSION */
557   const CeedScalar *d_array;
558   CeedVector_Hip   *impl;
559   hipblasHandle_t   handle;
560   Ceed_Hip         *hip_data;
561 
562   CeedCallBackend(CeedVectorGetCeed(vec, &ceed));
563   CeedCallBackend(CeedGetData(ceed, &hip_data));
564   CeedCallBackend(CeedVectorGetData(vec, &impl));
565   CeedCallBackend(CeedVectorGetLength(vec, &length));
566   CeedCallBackend(CeedGetHipblasHandle_Hip(ceed, &handle));
567 
568 #if (HIP_VERSION < 60000000)
569   // With ROCm 6, we can use the 64-bit integer interface. Prior to that,
570   // we need to check if the vector is too long to handle with int32,
571   // and if so, divide it into subsections for repeated hipBLAS calls.
572   num_calls = length / INT_MAX;
573   if (length % INT_MAX > 0) num_calls += 1;
574 #endif /* HIP_VERSION */
575 
576   // Compute norm
577   CeedCallBackend(CeedVectorGetArrayRead(vec, CEED_MEM_DEVICE, &d_array));
578   switch (type) {
579     case CEED_NORM_1: {
580       *norm = 0.0;
581 #if defined(CEED_SCALAR_IS_FP32)
582 #if (HIP_VERSION >= 60000000)  // We have ROCm 6, and can use 64-bit integers
583       CeedCallHipblas(ceed, hipblasSasum_64(handle, (int64_t)length, (float *)d_array, 1, (float *)norm));
584 #else  /* HIP_VERSION */
585       float  sub_norm = 0.0;
586       float *d_array_start;
587 
588       for (CeedInt i = 0; i < num_calls; i++) {
589         d_array_start             = (float *)d_array + (CeedSize)(i)*INT_MAX;
590         CeedSize remaining_length = length - (CeedSize)(i)*INT_MAX;
591         CeedInt  sub_length       = (i == num_calls - 1) ? (CeedInt)(remaining_length) : INT_MAX;
592 
593         CeedCallHipblas(ceed, hipblasSasum(handle, (CeedInt)sub_length, (float *)d_array_start, 1, &sub_norm));
594         *norm += sub_norm;
595       }
596 #endif /* HIP_VERSION */
597 #else  /* CEED_SCALAR */
598 #if (HIP_VERSION >= 60000000)
599       CeedCallHipblas(ceed, hipblasDasum_64(handle, (int64_t)length, (double *)d_array, 1, (double *)norm));
600 #else  /* HIP_VERSION */
601       double  sub_norm = 0.0;
602       double *d_array_start;
603 
604       for (CeedInt i = 0; i < num_calls; i++) {
605         d_array_start             = (double *)d_array + (CeedSize)(i)*INT_MAX;
606         CeedSize remaining_length = length - (CeedSize)(i)*INT_MAX;
607         CeedInt  sub_length       = (i == num_calls - 1) ? (CeedInt)(remaining_length) : INT_MAX;
608 
609         CeedCallHipblas(ceed, hipblasDasum(handle, (CeedInt)sub_length, (double *)d_array_start, 1, &sub_norm));
610         *norm += sub_norm;
611       }
612 #endif /* HIP_VERSION */
613 #endif /* CEED_SCALAR */
614       break;
615     }
616     case CEED_NORM_2: {
617 #if defined(CEED_SCALAR_IS_FP32)
618 #if (HIP_VERSION >= 60000000)
619       CeedCallHipblas(ceed, hipblasSnrm2_64(handle, (int64_t)length, (float *)d_array, 1, (float *)norm));
620 #else  /* HIP_VERSION */
621       float  sub_norm = 0.0, norm_sum = 0.0;
622       float *d_array_start;
623 
624       for (CeedInt i = 0; i < num_calls; i++) {
625         d_array_start             = (float *)d_array + (CeedSize)(i)*INT_MAX;
626         CeedSize remaining_length = length - (CeedSize)(i)*INT_MAX;
627         CeedInt  sub_length       = (i == num_calls - 1) ? (CeedInt)(remaining_length) : INT_MAX;
628 
629         CeedCallHipblas(ceed, hipblasSnrm2(handle, (CeedInt)sub_length, (float *)d_array_start, 1, &sub_norm));
630         norm_sum += sub_norm * sub_norm;
631       }
632       *norm = sqrt(norm_sum);
633 #endif /* HIP_VERSION */
634 #else  /* CEED_SCALAR */
635 #if (HIP_VERSION >= 60000000)
636       CeedCallHipblas(ceed, hipblasDnrm2_64(handle, (int64_t)length, (double *)d_array, 1, (double *)norm));
637 #else  /* HIP_VERSION */
638       double  sub_norm = 0.0, norm_sum = 0.0;
639       double *d_array_start;
640 
641       for (CeedInt i = 0; i < num_calls; i++) {
642         d_array_start             = (double *)d_array + (CeedSize)(i)*INT_MAX;
643         CeedSize remaining_length = length - (CeedSize)(i)*INT_MAX;
644         CeedInt  sub_length       = (i == num_calls - 1) ? (CeedInt)(remaining_length) : INT_MAX;
645 
646         CeedCallHipblas(ceed, hipblasDnrm2(handle, (CeedInt)sub_length, (double *)d_array_start, 1, &sub_norm));
647         norm_sum += sub_norm * sub_norm;
648       }
649       *norm = sqrt(norm_sum);
650 #endif /* HIP_VERSION */
651 #endif /* CEED_SCALAR */
652       break;
653     }
654     case CEED_NORM_MAX: {
655 #if defined(CEED_SCALAR_IS_FP32)
656 #if (HIP_VERSION >= 60000000)
657       int64_t    index;
658       CeedScalar norm_no_abs;
659 
660       CeedCallHipblas(ceed, hipblasIsamax_64(handle, (int64_t)length, (float *)d_array, 1, &index));
661       CeedCallHip(ceed, hipMemcpy(&norm_no_abs, impl->d_array + index - 1, sizeof(CeedScalar), hipMemcpyDeviceToHost));
662       *norm = fabs(norm_no_abs);
663 #else  /* HIP_VERSION */
664       CeedInt index;
665       float   sub_max = 0.0, current_max = 0.0;
666       float  *d_array_start;
667 
668       for (CeedInt i = 0; i < num_calls; i++) {
669         d_array_start             = (float *)d_array + (CeedSize)(i)*INT_MAX;
670         CeedSize remaining_length = length - (CeedSize)(i)*INT_MAX;
671         CeedInt  sub_length       = (i == num_calls - 1) ? (CeedInt)(remaining_length) : INT_MAX;
672 
673         CeedCallHipblas(ceed, hipblasIsamax(handle, (CeedInt)sub_length, (float *)d_array_start, 1, &index));
674         if (hip_data->has_unified_addressing) {
675           CeedCallHip(ceed, hipDeviceSynchronize());
676           sub_max = fabs(d_array[index - 1]);
677         } else {
678           CeedCallHip(ceed, hipMemcpy(&sub_max, d_array_start + index - 1, sizeof(CeedScalar), hipMemcpyDeviceToHost));
679         }
680         if (fabs(sub_max) > current_max) current_max = fabs(sub_max);
681       }
682       *norm = current_max;
683 #endif /* HIP_VERSION */
684 #else  /* CEED_SCALAR */
685 #if (HIP_VERSION >= 60000000)
686       int64_t    index;
687       CeedScalar norm_no_abs;
688 
689       CeedCallHipblas(ceed, hipblasIdamax_64(handle, (int64_t)length, (double *)d_array, 1, &index));
690       if (hip_data->has_unified_addressing) {
691         CeedCallHip(ceed, hipDeviceSynchronize());
692         norm_no_abs = fabs(d_array[index - 1]);
693       } else {
694         CeedCallHip(ceed, hipMemcpy(&norm_no_abs, impl->d_array + index - 1, sizeof(CeedScalar), hipMemcpyDeviceToHost));
695       }
696       *norm = fabs(norm_no_abs);
697 #else  /* HIP_VERSION */
698       CeedInt index;
699       double  sub_max = 0.0, current_max = 0.0;
700       double *d_array_start;
701 
702       for (CeedInt i = 0; i < num_calls; i++) {
703         d_array_start             = (double *)d_array + (CeedSize)(i)*INT_MAX;
704         CeedSize remaining_length = length - (CeedSize)(i)*INT_MAX;
705         CeedInt  sub_length       = (i == num_calls - 1) ? (CeedInt)(remaining_length) : INT_MAX;
706 
707         CeedCallHipblas(ceed, hipblasIdamax(handle, (CeedInt)sub_length, (double *)d_array_start, 1, &index));
708         if (hip_data->has_unified_addressing) {
709           CeedCallHip(ceed, hipDeviceSynchronize());
710           sub_max = fabs(d_array[index - 1]);
711         } else {
712           CeedCallHip(ceed, hipMemcpy(&sub_max, d_array_start + index - 1, sizeof(CeedScalar), hipMemcpyDeviceToHost));
713         }
714         if (fabs(sub_max) > current_max) current_max = fabs(sub_max);
715       }
716       *norm = current_max;
717 #endif /* HIP_VERSION */
718 #endif /* CEED_SCALAR */
719       break;
720     }
721   }
722   CeedCallBackend(CeedVectorRestoreArrayRead(vec, &d_array));
723   CeedCallBackend(CeedDestroy(&ceed));
724   return CEED_ERROR_SUCCESS;
725 }
726 
727 //------------------------------------------------------------------------------
728 // Take reciprocal of a vector on host
729 //------------------------------------------------------------------------------
730 static int CeedHostReciprocal_Hip(CeedScalar *h_array, CeedSize length) {
731   for (CeedSize i = 0; i < length; i++) {
732     if (fabs(h_array[i]) > CEED_EPSILON) h_array[i] = 1. / h_array[i];
733   }
734   return CEED_ERROR_SUCCESS;
735 }
736 
737 //------------------------------------------------------------------------------
738 // Take reciprocal of a vector on device (impl in .hip.cpp file)
739 //------------------------------------------------------------------------------
740 int CeedDeviceReciprocal_Hip(CeedScalar *d_array, CeedSize length);
741 
742 //------------------------------------------------------------------------------
743 // Take reciprocal of a vector
744 //------------------------------------------------------------------------------
745 static int CeedVectorReciprocal_Hip(CeedVector vec) {
746   CeedSize        length;
747   CeedVector_Hip *impl;
748 
749   CeedCallBackend(CeedVectorGetData(vec, &impl));
750   CeedCallBackend(CeedVectorGetLength(vec, &length));
751   // Set value for synced device/host array
752   if (impl->d_array) CeedCallBackend(CeedDeviceReciprocal_Hip(impl->d_array, length));
753   if (impl->h_array) CeedCallBackend(CeedHostReciprocal_Hip(impl->h_array, length));
754   return CEED_ERROR_SUCCESS;
755 }
756 
757 //------------------------------------------------------------------------------
758 // Compute x = alpha x on the host
759 //------------------------------------------------------------------------------
760 static int CeedHostScale_Hip(CeedScalar *x_array, CeedScalar alpha, CeedSize length) {
761   for (CeedSize i = 0; i < length; i++) x_array[i] *= alpha;
762   return CEED_ERROR_SUCCESS;
763 }
764 
765 //------------------------------------------------------------------------------
766 // Compute x = alpha x on device (impl in .hip.cpp file)
767 //------------------------------------------------------------------------------
768 int CeedDeviceScale_Hip(CeedScalar *x_array, CeedScalar alpha, CeedSize length);
769 
770 //------------------------------------------------------------------------------
771 // Compute x = alpha x
772 //------------------------------------------------------------------------------
773 static int CeedVectorScale_Hip(CeedVector x, CeedScalar alpha) {
774   CeedSize        length;
775   CeedVector_Hip *impl;
776 
777   CeedCallBackend(CeedVectorGetData(x, &impl));
778   CeedCallBackend(CeedVectorGetLength(x, &length));
779   // Set value for synced device/host array
780   if (impl->d_array) {
781 #if (HIP_VERSION >= 60000000)
782     hipblasHandle_t handle;
783 
784     CeedCallBackend(CeedGetHipblasHandle_Hip(CeedVectorReturnCeed(x), &handle));
785 #if defined(CEED_SCALAR_IS_FP32)
786     CeedCallHipblas(CeedVectorReturnCeed(x), hipblasSscal_64(handle, (int64_t)length, &alpha, impl->d_array, 1));
787 #else  /* CEED_SCALAR */
788     CeedCallHipblas(CeedVectorReturnCeed(x), hipblasDscal_64(handle, (int64_t)length, &alpha, impl->d_array, 1));
789 #endif /* CEED_SCALAR */
790 #else  /* HIP_VERSION */
791     CeedCallBackend(CeedDeviceScale_Hip(impl->d_array, alpha, length));
792 #endif /* HIP_VERSION */
793     impl->h_array = NULL;
794   }
795   if (impl->h_array) {
796     CeedCallBackend(CeedHostScale_Hip(impl->h_array, alpha, length));
797     impl->d_array = NULL;
798   }
799   return CEED_ERROR_SUCCESS;
800 }
801 
802 //------------------------------------------------------------------------------
803 // Compute y = alpha x + y on the host
804 //------------------------------------------------------------------------------
805 static int CeedHostAXPY_Hip(CeedScalar *y_array, CeedScalar alpha, CeedScalar *x_array, CeedSize length) {
806   for (CeedSize i = 0; i < length; i++) y_array[i] += alpha * x_array[i];
807   return CEED_ERROR_SUCCESS;
808 }
809 
810 //------------------------------------------------------------------------------
811 // Compute y = alpha x + y on device (impl in .hip.cpp file)
812 //------------------------------------------------------------------------------
813 int CeedDeviceAXPY_Hip(CeedScalar *y_array, CeedScalar alpha, CeedScalar *x_array, CeedSize length);
814 
815 //------------------------------------------------------------------------------
816 // Compute y = alpha x + y
817 //------------------------------------------------------------------------------
818 static int CeedVectorAXPY_Hip(CeedVector y, CeedScalar alpha, CeedVector x) {
819   CeedSize        length;
820   CeedVector_Hip *y_impl, *x_impl;
821 
822   CeedCallBackend(CeedVectorGetData(y, &y_impl));
823   CeedCallBackend(CeedVectorGetData(x, &x_impl));
824   CeedCallBackend(CeedVectorGetLength(y, &length));
825   // Set value for synced device/host array
826   if (y_impl->d_array) {
827     CeedCallBackend(CeedVectorSyncArray(x, CEED_MEM_DEVICE));
828 #if (HIP_VERSION >= 60000000)
829     hipblasHandle_t handle;
830 
831     CeedCallBackend(CeedGetHipblasHandle_Hip(CeedVectorReturnCeed(y), &handle));
832 #if defined(CEED_SCALAR_IS_FP32)
833     CeedCallHipblas(CeedVectorReturnCeed(y), hipblasSaxpy_64(handle, (int64_t)length, &alpha, x_impl->d_array, 1, y_impl->d_array, 1));
834 #else  /* CEED_SCALAR */
835     CeedCallHipblas(CeedVectorReturnCeed(y), hipblasDaxpy_64(handle, (int64_t)length, &alpha, x_impl->d_array, 1, y_impl->d_array, 1));
836 #endif /* CEED_SCALAR */
837 #else  /* HIP_VERSION */
838     CeedCallBackend(CeedDeviceAXPY_Hip(y_impl->d_array, alpha, x_impl->d_array, length));
839 #endif /* HIP_VERSION */
840     y_impl->h_array = NULL;
841   } else if (y_impl->h_array) {
842     CeedCallBackend(CeedVectorSyncArray(x, CEED_MEM_HOST));
843     CeedCallBackend(CeedHostAXPY_Hip(y_impl->h_array, alpha, x_impl->h_array, length));
844     y_impl->d_array = NULL;
845   }
846   return CEED_ERROR_SUCCESS;
847 }
848 
849 //------------------------------------------------------------------------------
850 // Compute y = alpha x + beta y on the host
851 //------------------------------------------------------------------------------
852 static int CeedHostAXPBY_Hip(CeedScalar *y_array, CeedScalar alpha, CeedScalar beta, CeedScalar *x_array, CeedSize length) {
853   for (CeedSize i = 0; i < length; i++) y_array[i] = alpha * x_array[i] + beta * y_array[i];
854   return CEED_ERROR_SUCCESS;
855 }
856 
857 //------------------------------------------------------------------------------
858 // Compute y = alpha x + beta y on device (impl in .hip.cpp file)
859 //------------------------------------------------------------------------------
860 int CeedDeviceAXPBY_Hip(CeedScalar *y_array, CeedScalar alpha, CeedScalar beta, CeedScalar *x_array, CeedSize length);
861 
862 //------------------------------------------------------------------------------
863 // Compute y = alpha x + beta y
864 //------------------------------------------------------------------------------
865 static int CeedVectorAXPBY_Hip(CeedVector y, CeedScalar alpha, CeedScalar beta, CeedVector x) {
866   CeedSize        length;
867   CeedVector_Hip *y_impl, *x_impl;
868 
869   CeedCallBackend(CeedVectorGetData(y, &y_impl));
870   CeedCallBackend(CeedVectorGetData(x, &x_impl));
871   CeedCallBackend(CeedVectorGetLength(y, &length));
872   // Set value for synced device/host array
873   if (y_impl->d_array) {
874     CeedCallBackend(CeedVectorSyncArray(x, CEED_MEM_DEVICE));
875     CeedCallBackend(CeedDeviceAXPBY_Hip(y_impl->d_array, alpha, beta, x_impl->d_array, length));
876   }
877   if (y_impl->h_array) {
878     CeedCallBackend(CeedVectorSyncArray(x, CEED_MEM_HOST));
879     CeedCallBackend(CeedHostAXPBY_Hip(y_impl->h_array, alpha, beta, x_impl->h_array, length));
880   }
881   return CEED_ERROR_SUCCESS;
882 }
883 
884 //------------------------------------------------------------------------------
885 // Compute the pointwise multiplication w = x .* y on the host
886 //------------------------------------------------------------------------------
887 static int CeedHostPointwiseMult_Hip(CeedScalar *w_array, CeedScalar *x_array, CeedScalar *y_array, CeedSize length) {
888   for (CeedSize i = 0; i < length; i++) w_array[i] = x_array[i] * y_array[i];
889   return CEED_ERROR_SUCCESS;
890 }
891 
892 //------------------------------------------------------------------------------
893 // Compute the pointwise multiplication w = x .* y on device (impl in .hip.cpp file)
894 //------------------------------------------------------------------------------
895 int CeedDevicePointwiseMult_Hip(CeedScalar *w_array, CeedScalar *x_array, CeedScalar *y_array, CeedSize length);
896 
897 //------------------------------------------------------------------------------
898 // Compute the pointwise multiplication w = x .* y
899 //------------------------------------------------------------------------------
900 static int CeedVectorPointwiseMult_Hip(CeedVector w, CeedVector x, CeedVector y) {
901   CeedSize        length;
902   CeedVector_Hip *w_impl, *x_impl, *y_impl;
903 
904   CeedCallBackend(CeedVectorGetData(w, &w_impl));
905   CeedCallBackend(CeedVectorGetData(x, &x_impl));
906   CeedCallBackend(CeedVectorGetData(y, &y_impl));
907   CeedCallBackend(CeedVectorGetLength(w, &length));
908 
909   // Set value for synced device/host array
910   if (!w_impl->d_array && !w_impl->h_array) {
911     CeedCallBackend(CeedVectorSetValue(w, 0.0));
912   }
913   if (w_impl->d_array) {
914     CeedCallBackend(CeedVectorSyncArray(x, CEED_MEM_DEVICE));
915     CeedCallBackend(CeedVectorSyncArray(y, CEED_MEM_DEVICE));
916     CeedCallBackend(CeedDevicePointwiseMult_Hip(w_impl->d_array, x_impl->d_array, y_impl->d_array, length));
917   }
918   if (w_impl->h_array) {
919     CeedCallBackend(CeedVectorSyncArray(x, CEED_MEM_HOST));
920     CeedCallBackend(CeedVectorSyncArray(y, CEED_MEM_HOST));
921     CeedCallBackend(CeedHostPointwiseMult_Hip(w_impl->h_array, x_impl->h_array, y_impl->h_array, length));
922   }
923   return CEED_ERROR_SUCCESS;
924 }
925 
926 //------------------------------------------------------------------------------
927 // Destroy the vector
928 //------------------------------------------------------------------------------
929 static int CeedVectorDestroy_Hip(const CeedVector vec) {
930   CeedVector_Hip *impl;
931 
932   CeedCallBackend(CeedVectorGetData(vec, &impl));
933   CeedCallHip(CeedVectorReturnCeed(vec), hipFree(impl->d_array_owned));
934   CeedCallBackend(CeedFree(&impl->h_array_owned));
935   CeedCallBackend(CeedFree(&impl));
936   return CEED_ERROR_SUCCESS;
937 }
938 
939 //------------------------------------------------------------------------------
940 // Create a vector of the specified length (does not allocate memory)
941 //------------------------------------------------------------------------------
942 int CeedVectorCreate_Hip(CeedSize n, CeedVector vec) {
943   CeedVector_Hip *impl;
944   Ceed_Hip       *hip_impl;
945   Ceed            ceed;
946 
947   CeedCallBackend(CeedVectorGetCeed(vec, &ceed));
948   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "HasValidArray", CeedVectorHasValidArray_Hip));
949   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "HasBorrowedArrayOfType", CeedVectorHasBorrowedArrayOfType_Hip));
950   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "SetArray", CeedVectorSetArray_Hip));
951   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "TakeArray", CeedVectorTakeArray_Hip));
952   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "CopyStrided", CeedVectorCopyStrided_Hip));
953   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "SetValue", CeedVectorSetValue_Hip));
954   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "SetValueStrided", CeedVectorSetValueStrided_Hip));
955   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "SyncArray", CeedVectorSyncArray_Hip));
956   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "GetArray", CeedVectorGetArray_Hip));
957   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "GetArrayRead", CeedVectorGetArrayRead_Hip));
958   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "GetArrayWrite", CeedVectorGetArrayWrite_Hip));
959   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "Norm", CeedVectorNorm_Hip));
960   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "Reciprocal", CeedVectorReciprocal_Hip));
961   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "Scale", CeedVectorScale_Hip));
962   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "AXPY", CeedVectorAXPY_Hip));
963   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "AXPBY", CeedVectorAXPBY_Hip));
964   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "PointwiseMult", CeedVectorPointwiseMult_Hip));
965   CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "Destroy", CeedVectorDestroy_Hip));
966   CeedCallBackend(CeedCalloc(1, &impl));
967   CeedCallBackend(CeedGetData(ceed, &hip_impl));
968   CeedCallBackend(CeedDestroy(&ceed));
969   impl->has_unified_addressing = hip_impl->has_unified_addressing;
970   CeedCallBackend(CeedVectorSetData(vec, impl));
971   return CEED_ERROR_SUCCESS;
972 }
973 
974 //------------------------------------------------------------------------------
975