xref: /petsc/include/petscdevicetypes.h (revision cf906205f1df435953e2a75894dc7795d3ff0aed)
1 #ifndef PETSCDEVICETYPES_H
2 #define PETSCDEVICETYPES_H
3 
4 #include <petscsys.h> /*I <petscdevicetypes.h> I*/
5 
6 // Some overzealous older gcc versions warn that the comparisons below are always true. Neat
7 // that it can detect this, but the tautology *is* the point of the static_assert()!
8 #if defined(__GNUC__) && __GNUC__ >= 6 && !PetscDefined(HAVE_WINDOWS_COMPILERS)
9 #define PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING 1
10 #else
11 #define PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING 0
12 #endif
13 
14 /* SUBMANSEC = Sys */
15 
16 /*E
17   PetscMemType - Memory type of a pointer
18 
19   Developer Note:
20   Encoding of the bitmask in binary: xxxxyyyz
21 
22 $ z = 0                - Host memory
23 $ z = 1                - Device memory
24 $ yyy = 000            - CUDA-related memory
25 $ yyy = 001            - HIP-related memory
26 $ yyy = 010            - SYCL-related memory
27 $ xxxxyyy1 = 0000,0001 - CUDA memory
28 $ xxxxyyy1 = 0001,0001 - CUDA NVSHMEM memory
29 $ xxxxyyy1 = 0000,0011 - HIP memory
30 $ xxxxyyy1 = 0000,0101 - SYCL memory
31 
32   Other types of memory, e.g., CUDA managed memory, can be added when needed.
33 
34   Level: beginner
35 
36   Notes:
37   `PETSC_MEMTYPE_KOKKOS` depends on the Kokkos backend configuration
38 
39   Developer Notes:
40   This enum uses a function (`PetscMemTypeToString()`) to convert to string representation so
41   cannot be used in `PetscOptionsEnum()`.
42 
43 .seealso: `PetscMemTypeToString()`, `VecGetArrayAndMemType()`,
44 `PetscSFBcastWithMemTypeBegin()`, `PetscSFReduceWithMemTypeBegin()`
45 E*/
46 typedef enum {
47   PETSC_MEMTYPE_HOST    = 0,
48   PETSC_MEMTYPE_DEVICE  = 0x01,
49   PETSC_MEMTYPE_CUDA    = 0x01,
50   PETSC_MEMTYPE_NVSHMEM = 0x11,
51   PETSC_MEMTYPE_HIP     = 0x03,
52   PETSC_MEMTYPE_SYCL    = 0x05,
53 } PetscMemType;
54 #if PetscDefined(HAVE_CUDA)
55 #define PETSC_MEMTYPE_KOKKOS PETSC_MEMTYPE_CUDA
56 #elif PetscDefined(HAVE_HIP)
57 #define PETSC_MEMTYPE_KOKKOS PETSC_MEMTYPE_HIP
58 #elif PetscDefined(HAVE_SYCL)
59 #define PETSC_MEMTYPE_KOKKOS PETSC_MEMTYPE_SYCL
60 #else
61 #define PETSC_MEMTYPE_KOKKOS PETSC_MEMTYPE_HOST
62 #endif
63 
64 #define PetscMemTypeHost(m)    (((m)&0x1) == PETSC_MEMTYPE_HOST)
65 #define PetscMemTypeDevice(m)  (((m)&0x1) == PETSC_MEMTYPE_DEVICE)
66 #define PetscMemTypeCUDA(m)    (((m)&0xF) == PETSC_MEMTYPE_CUDA)
67 #define PetscMemTypeHIP(m)     (((m)&0xF) == PETSC_MEMTYPE_HIP)
68 #define PetscMemTypeSYCL(m)    (((m)&0xF) == PETSC_MEMTYPE_SYCL)
69 #define PetscMemTypeNVSHMEM(m) ((m) == PETSC_MEMTYPE_NVSHMEM)
70 
71 #if defined(__cplusplus)
72 #if PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING
73 #pragma GCC diagnostic push
74 #pragma GCC diagnostic ignored "-Wtautological-compare"
75 #endif
76 static_assert(PetscMemTypeHost(PETSC_MEMTYPE_HOST), "");
77 static_assert(!PetscMemTypeHost(PETSC_MEMTYPE_DEVICE), "");
78 static_assert(!PetscMemTypeHost(PETSC_MEMTYPE_CUDA), "");
79 static_assert(!PetscMemTypeHost(PETSC_MEMTYPE_HIP), "");
80 static_assert(!PetscMemTypeHost(PETSC_MEMTYPE_SYCL), "");
81 static_assert(!PetscMemTypeHost(PETSC_MEMTYPE_NVSHMEM), "");
82 
83 static_assert(!PetscMemTypeDevice(PETSC_MEMTYPE_HOST), "");
84 static_assert(PetscMemTypeDevice(PETSC_MEMTYPE_DEVICE), "");
85 static_assert(PetscMemTypeDevice(PETSC_MEMTYPE_CUDA), "");
86 static_assert(PetscMemTypeDevice(PETSC_MEMTYPE_HIP), "");
87 static_assert(PetscMemTypeDevice(PETSC_MEMTYPE_SYCL), "");
88 static_assert(PetscMemTypeDevice(PETSC_MEMTYPE_NVSHMEM), "");
89 
90 static_assert(PetscMemTypeCUDA(PETSC_MEMTYPE_CUDA), "");
91 static_assert(PetscMemTypeCUDA(PETSC_MEMTYPE_NVSHMEM), "");
92 #if PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING
93 #pragma GCC diagnostic pop
94 #endif
95 #endif // __cplusplus
96 
97 PETSC_NODISCARD static inline PETSC_CONSTEXPR_14 const char *PetscMemTypeToString(PetscMemType mtype) {
98 #ifdef __cplusplus
99   static_assert(PETSC_MEMTYPE_CUDA == PETSC_MEMTYPE_DEVICE, "");
100 #endif
101 #define PETSC_CASE_NAME(v) \
102   case v: return PetscStringize(v)
103 
104   switch (mtype) {
105     PETSC_CASE_NAME(PETSC_MEMTYPE_HOST);
106     /* PETSC_CASE_NAME(PETSC_MEMTYPE_DEVICE); same as PETSC_MEMTYPE_CUDA */
107     PETSC_CASE_NAME(PETSC_MEMTYPE_CUDA);
108     PETSC_CASE_NAME(PETSC_MEMTYPE_NVSHMEM);
109     PETSC_CASE_NAME(PETSC_MEMTYPE_HIP);
110     PETSC_CASE_NAME(PETSC_MEMTYPE_SYCL);
111   }
112   PetscUnreachable();
113   return "invalid";
114 #undef PETSC_CASE_NAME
115 }
116 
117 #define PETSC_OFFLOAD_VECKOKKOS_DEPRECATED PETSC_OFFLOAD_VECKOKKOS PETSC_DEPRECATED_ENUM("Use PETSC_OFFLOAD_KOKKOS (since version 3.17.0)")
118 
119 /*E
120   PetscOffloadMask - indicates which memory (CPU, GPU, or none) contains valid data
121 
122 $ PETSC_OFFLOAD_UNALLOCATED - no memory contains valid matrix entries; NEVER used for vectors
123 $ PETSC_OFFLOAD_GPU         - GPU has valid vector/matrix entries
124 $ PETSC_OFFLOAD_CPU         - CPU has valid vector/matrix entries
125 $ PETSC_OFFLOAD_BOTH        - Both GPU and CPU have valid vector/matrix entries and they match
126 $ PETSC_OFFLOAD_KOKKOS      - Reserved for Kokkos matrix and vector. It means the offload is managed by Kokkos, thus this flag itself cannot tell you where the valid data is.
127 
128   Developer Notes:
129   This enum uses a function (`PetscOffloadMaskToString()`) to convert to string representation so
130   cannot be used in `PetscOptionsEnum()`.
131 
132   Level: developer
133 
134 .seealso: `PetscOffloadMaskToString()`, `PetscOffloadMaskToMemType()`, `PetscOffloadMaskToDeviceCopyMode()`
135 E*/
136 typedef enum {
137   PETSC_OFFLOAD_UNALLOCATED          = 0x0,
138   PETSC_OFFLOAD_CPU                  = 0x1,
139   PETSC_OFFLOAD_GPU                  = 0x2,
140   PETSC_OFFLOAD_BOTH                 = 0x3,
141   PETSC_OFFLOAD_VECKOKKOS_DEPRECATED = 0x100,
142   PETSC_OFFLOAD_KOKKOS               = 0x100
143 } PetscOffloadMask;
144 
145 #define PetscOffloadUnallocated(m) ((m) == PETSC_OFFLOAD_UNALLOCATED)
146 #define PetscOffloadHost(m)        (((m)&PETSC_OFFLOAD_CPU) == PETSC_OFFLOAD_CPU)
147 #define PetscOffloadDevice(m)      (((m)&PETSC_OFFLOAD_GPU) == PETSC_OFFLOAD_GPU)
148 #define PetscOffloadBoth(m)        ((m) != PETSC_OFFLOAD_UNALLOCATED)
149 
150 #if defined(__cplusplus)
151 #if PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING
152 #pragma GCC diagnostic push
153 #pragma GCC diagnostic ignored "-Wtautological-compare"
154 #endif
155 static_assert(!PetscOffloadHost(PETSC_OFFLOAD_UNALLOCATED), "");
156 static_assert(PetscOffloadHost(PETSC_OFFLOAD_BOTH), "");
157 static_assert(!PetscOffloadHost(PETSC_OFFLOAD_GPU), "");
158 static_assert(PetscOffloadHost(PETSC_OFFLOAD_BOTH), "");
159 static_assert(!PetscOffloadHost(PETSC_OFFLOAD_KOKKOS), "");
160 
161 static_assert(!PetscOffloadDevice(PETSC_OFFLOAD_UNALLOCATED), "");
162 static_assert(!PetscOffloadDevice(PETSC_OFFLOAD_CPU), "");
163 static_assert(PetscOffloadDevice(PETSC_OFFLOAD_GPU), "");
164 static_assert(PetscOffloadDevice(PETSC_OFFLOAD_BOTH), "");
165 static_assert(!PetscOffloadDevice(PETSC_OFFLOAD_KOKKOS), "");
166 #if PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING
167 #pragma GCC diagnostic pop
168 #endif
169 #endif // __cplusplus
170 
171 PETSC_NODISCARD static inline PETSC_CONSTEXPR_14 const char *PetscOffloadMaskToString(PetscOffloadMask mask) {
172 #define PETSC_CASE_RETURN(v) \
173   case v: return PetscStringize(v)
174 
175   switch (mask) {
176     PETSC_CASE_RETURN(PETSC_OFFLOAD_UNALLOCATED);
177     PETSC_CASE_RETURN(PETSC_OFFLOAD_CPU);
178     PETSC_CASE_RETURN(PETSC_OFFLOAD_GPU);
179     PETSC_CASE_RETURN(PETSC_OFFLOAD_BOTH);
180     PETSC_CASE_RETURN(PETSC_OFFLOAD_KOKKOS);
181   }
182   PetscUnreachable();
183   return "invalid";
184 #undef PETSC_CASE_RETURN
185 }
186 
187 PETSC_NODISCARD static inline PETSC_CONSTEXPR_14 PetscMemType PetscOffloadMaskToMemType(PetscOffloadMask mask) {
188   switch (mask) {
189   case PETSC_OFFLOAD_UNALLOCATED:
190   case PETSC_OFFLOAD_CPU: return PETSC_MEMTYPE_HOST;
191   case PETSC_OFFLOAD_GPU:
192   case PETSC_OFFLOAD_BOTH: return PETSC_MEMTYPE_DEVICE;
193   case PETSC_OFFLOAD_KOKKOS: return PETSC_MEMTYPE_KOKKOS;
194   }
195   PetscUnreachable();
196   return PETSC_MEMTYPE_HOST;
197 }
198 
199 /*E
200   PetscDeviceInitType - Initialization strategy for `PetscDevice`
201 
202 $ PETSC_DEVICE_INIT_NONE  - PetscDevice is never initialized
203 $ PETSC_DEVICE_INIT_LAZY  - PetscDevice is initialized on demand
204 $ PETSC_DEVICE_INIT_EAGER - PetscDevice is initialized as soon as possible
205 
206   Notes:
207   `PETSC_DEVICE_INIT_NONE` implies that any initialization of `PetscDevice` is disallowed and
208   doing so results in an error. Useful to ensure that no accelerator is used in a program.
209 
210   Level: beginner
211 
212 .seealso: `PetscDevice`, `PetscDeviceType`, `PetscDeviceInitialize()`,
213 `PetscDeviceInitialized()`, `PetscDeviceCreate()`
214 E*/
215 typedef enum {
216   PETSC_DEVICE_INIT_NONE,
217   PETSC_DEVICE_INIT_LAZY,
218   PETSC_DEVICE_INIT_EAGER
219 } PetscDeviceInitType;
220 PETSC_EXTERN const char *const PetscDeviceInitTypes[];
221 
222 /*E
223   PetscDeviceType - Kind of accelerator device backend
224 
225 $ PETSC_DEVICE_HOST - Host, no accelerator backend found
226 $ PETSC_DEVICE_CUDA - CUDA enabled GPU
227 $ PETSC_DEVICE_HIP  - ROCM/HIP enabled GPU
228 $ PETSC_DEVICE_SYCL - SYCL enabled device
229 $ PETSC_DEVICE_MAX  - Always 1 greater than the largest valid PetscDeviceType, invalid type, do not use
230 
231   Notes:
232   One can also use the `PETSC_DEVICE_DEFAULT()` routine to get the current default `PetscDeviceType`.
233 
234   Level: beginner
235 
236 .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceCreate()`, `PETSC_DEVICE_DEFAULT()`
237 E*/
238 typedef enum {
239   PETSC_DEVICE_HOST,
240   PETSC_DEVICE_CUDA,
241   PETSC_DEVICE_HIP,
242   PETSC_DEVICE_SYCL,
243   PETSC_DEVICE_MAX
244 } PetscDeviceType;
245 PETSC_EXTERN const char *const PetscDeviceTypes[];
246 
247 /*E
248   PetscDeviceAttribute - Attribute detailing a property or feature of a `PetscDevice`
249 
250 $ PETSC_DEVICE_ATTR_SIZE_T_SHARED_MEM_PER_BLOCK - The maximum amount of shared memory per block in a
251 device kernel
252 $ PETSC_DEVICE_ATTR_MAX                         - Invalid attribute, do not use
253 
254   Level: beginner
255 
256 .seealso: `PetscDevice`, `PetscDeviceGetAttribute()`
257 E*/
258 typedef enum {
259   PETSC_DEVICE_ATTR_SIZE_T_SHARED_MEM_PER_BLOCK,
260   PETSC_DEVICE_ATTR_MAX
261 } PetscDeviceAttribute;
262 PETSC_EXTERN const char *const PetscDeviceAttributes[];
263 
264 /*S
265   PetscDevice - Object to manage an accelerator "device" (usually a GPU)
266 
267   Notes:
268   This object is used to house configuration and state of a device, but does not offer any
269   ability to interact with or drive device computation. This functionality is facilitated
270   instead by the `PetscDeviceContext` object.
271 
272   Level: beginner
273 
274 .seealso: `PetscDeviceType`, `PetscDeviceInitType`, `PetscDeviceCreate()`,
275 `PetscDeviceConfigure()`, `PetscDeviceDestroy()`, `PetscDeviceContext`,
276 `PetscDeviceContextSetDevice()`, `PetscDeviceContextGetDevice()`, `PetscDeviceGetAttribute()`
277 S*/
278 typedef struct _n_PetscDevice *PetscDevice;
279 
280 /*E
281   PetscStreamType - Stream blocking mode, indicates how a stream implementation will interact
282   with the default "NULL" stream, which is usually blocking.
283 
284 $ PETSC_STREAM_GLOBAL_BLOCKING    - Alias for NULL stream. Any stream of this type will block the host for all other streams to finish work before starting its operations.
285 $ PETSC_STREAM_DEFAULT_BLOCKING   - Stream will act independent of other streams, but will still be blocked by actions on the NULL stream.
286 $ PETSC_STREAM_GLOBAL_NONBLOCKING - Stream is truly asynchronous, and is blocked by nothing, not even the NULL stream.
287 $ PETSC_STREAM_MAX                - Always 1 greater than the largest PetscStreamType, do not use
288 
289   Level: intermediate
290 
291 .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextGetStreamType()`
292 E*/
293 typedef enum {
294   PETSC_STREAM_GLOBAL_BLOCKING,
295   PETSC_STREAM_DEFAULT_BLOCKING,
296   PETSC_STREAM_GLOBAL_NONBLOCKING,
297   PETSC_STREAM_MAX
298 } PetscStreamType;
299 PETSC_EXTERN const char *const PetscStreamTypes[];
300 
301 /*E
302   PetscDeviceContextJoinMode - Describes the type of join operation to perform in
303   `PetscDeviceContextJoin()`
304 
305 $ PETSC_DEVICE_CONTEXT_JOIN_DESTROY - Destroy all incoming sub-contexts after join.
306 $ PETSC_DEVICE_CONTEXT_JOIN_SYNC    - Synchronize incoming sub-contexts after join.
307 $ PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC - Do not synchronize incoming sub-contexts after join.
308 
309   Level: beginner
310 
311 .seealso: `PetscDeviceContext`, `PetscDeviceContextFork()`, `PetscDeviceContextJoin()`
312 E*/
313 typedef enum {
314   PETSC_DEVICE_CONTEXT_JOIN_DESTROY,
315   PETSC_DEVICE_CONTEXT_JOIN_SYNC,
316   PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC
317 } PetscDeviceContextJoinMode;
318 PETSC_EXTERN const char *const PetscDeviceContextJoinModes[];
319 
320 /*S
321   PetscDeviceContext - Container to manage stream dependencies and the various solver handles
322   for asynchronous device compute.
323 
324   Level: beginner
325 
326 .seealso: `PetscDevice`, `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`,
327 `PetscDeviceContextDestroy()`,`PetscDeviceContextFork()`, `PetscDeviceContextJoin()`
328 S*/
329 typedef struct _p_PetscDeviceContext *PetscDeviceContext;
330 
331 /*E
332   PetscDeviceCopyMode - Describes the copy direction of a device-aware memcpy
333 
334 $ PETSC_DEVICE_COPY_HTOH - Copy from host memory to host memory
335 $ PETSC_DEVICE_COPY_DTOH - Copy from device memory to host memory
336 $ PETSC_DEVICE_COPY_HTOD - Copy from host memory to device memory
337 $ PETSC_DEVICE_COPY_DTOD - Copy from device memory to device memory
338 $ PETSC_DEVICE_COPY_AUTO - Infer the copy direction from the pointers
339 
340   Level: beginner
341 
342 .seealso: `PetscDeviceArrayCopy()`, `PetscDeviceMemcpy()`
343 E*/
344 typedef enum {
345   PETSC_DEVICE_COPY_HTOH,
346   PETSC_DEVICE_COPY_DTOH,
347   PETSC_DEVICE_COPY_HTOD,
348   PETSC_DEVICE_COPY_DTOD,
349   PETSC_DEVICE_COPY_AUTO,
350 } PetscDeviceCopyMode;
351 PETSC_EXTERN const char *const PetscDeviceCopyModes[];
352 
353 PETSC_NODISCARD static inline PetscDeviceCopyMode PetscOffloadMaskToDeviceCopyMode(PetscOffloadMask dest, PetscOffloadMask src) {
354   PetscDeviceCopyMode mode;
355 
356   PetscFunctionBegin;
357   PetscAssertAbort(dest != PETSC_OFFLOAD_UNALLOCATED, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot copy to unallocated");
358   PetscAssertAbort(src != PETSC_OFFLOAD_UNALLOCATED, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot copy from unallocated");
359 
360   if (PetscOffloadDevice(dest)) {
361     mode = PetscOffloadHost(src) ? PETSC_DEVICE_COPY_HTOD : PETSC_DEVICE_COPY_DTOD;
362   } else {
363     mode = PetscOffloadHost(src) ? PETSC_DEVICE_COPY_HTOH : PETSC_DEVICE_COPY_DTOH;
364   }
365   PetscFunctionReturn(mode);
366 }
367 
368 PETSC_NODISCARD static inline PETSC_CONSTEXPR_14 PetscDeviceCopyMode PetscMemTypeToDeviceCopyMode(PetscMemType dest, PetscMemType src) {
369   if (PetscMemTypeHost(dest)) {
370     return PetscMemTypeHost(src) ? PETSC_DEVICE_COPY_HTOH : PETSC_DEVICE_COPY_DTOH;
371   } else {
372     return PetscMemTypeDevice(src) ? PETSC_DEVICE_COPY_DTOD : PETSC_DEVICE_COPY_HTOD;
373   }
374 }
375 
376 /*E
377   PetscMemoryAccessMode - Describes the intended usage of a memory region
378 
379 + PETSC_MEMORY_ACCESS_READ       - Read only
380 . PETSC_MEMORY_ACCESS_WRITE      - Write only
381 - PETSC_MEMORY_ACCESS_READ_WRITE - Read and write
382 
383   Notes:
384   This `enum` is a bitmask with the following encoding (assuming 2 bit)\:
385 
386 .vb
387   PETSC_MEMORY_ACCESS_READ       = 0b01
388   PETSC_MEMORY_ACCESS_WRITE      = 0b10
389   PETSC_MEMORY_ACCESS_READ_WRITE = 0b11
390 
391   // consequently
392   PETSC_MEMORY_ACCESS_READ | PETSC_MEMORY_ACCESS_WRITE = PETSC_MEMORY_ACCESS_READ_WRITE
393 .ve
394 
395   The following convience macros are also provided\:
396 
397   - `PetscMemoryAccessRead(mode)`\: `true` if `mode` is any kind of read, `false` otherwise
398   - `PetscMemoryAccessWrite(mode)`\: `true` if `mode` is any kind of write, `false` otherwise
399 
400   Developer Notes:
401   This enum uses a function (`PetscMemoryAccessModeToString()`) to convert values to string
402   representation, so cannot be used in `PetscOptionsEnum()`.
403 
404   Level: beginner
405 
406 .seealso: `PetscMemoryAccessModeToString()`, `PetscDevice`, `PetscDeviceContext`
407 E*/
408 typedef enum {
409   PETSC_MEMORY_ACCESS_READ       = 0x1, // 01
410   PETSC_MEMORY_ACCESS_WRITE      = 0x2, // 10
411   PETSC_MEMORY_ACCESS_READ_WRITE = 0x3, // 11
412 } PetscMemoryAccessMode;
413 
414 #define PetscMemoryAccessRead(m)  (((m)&PETSC_MEMORY_ACCESS_READ) == PETSC_MEMORY_ACCESS_READ)
415 #define PetscMemoryAccessWrite(m) (((m)&PETSC_MEMORY_ACCESS_WRITE) == PETSC_MEMORY_ACCESS_WRITE)
416 
417 #if defined(__cplusplus)
418 #if PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING
419 #pragma GCC diagnostic push
420 #pragma GCC diagnostic ignored "-Wtautological-compare"
421 #endif
422 static_assert(PetscMemoryAccessRead(PETSC_MEMORY_ACCESS_READ), "");
423 static_assert(PetscMemoryAccessRead(PETSC_MEMORY_ACCESS_READ_WRITE), "");
424 static_assert(!PetscMemoryAccessRead(PETSC_MEMORY_ACCESS_WRITE), "");
425 static_assert(PetscMemoryAccessWrite(PETSC_MEMORY_ACCESS_WRITE), "");
426 static_assert(PetscMemoryAccessWrite(PETSC_MEMORY_ACCESS_READ_WRITE), "");
427 static_assert(!PetscMemoryAccessWrite(PETSC_MEMORY_ACCESS_READ), "");
428 static_assert((PETSC_MEMORY_ACCESS_READ | PETSC_MEMORY_ACCESS_WRITE) == PETSC_MEMORY_ACCESS_READ_WRITE, "");
429 #if PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING
430 #pragma GCC diagnostic pop
431 #endif
432 #endif
433 
434 PETSC_NODISCARD static inline PETSC_CONSTEXPR_14 const char *PetscMemoryAccessModeToString(PetscMemoryAccessMode mode) {
435 #define PETSC_CASE_RETURN(v) \
436   case v: return PetscStringize(v)
437 
438   switch (mode) {
439     PETSC_CASE_RETURN(PETSC_MEMORY_ACCESS_READ);
440     PETSC_CASE_RETURN(PETSC_MEMORY_ACCESS_WRITE);
441     PETSC_CASE_RETURN(PETSC_MEMORY_ACCESS_READ_WRITE);
442   }
443   PetscUnreachable();
444   return "invalid";
445 #undef PETSC_CASE_RETURN
446 }
447 
448 #undef PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING
449 
450 #endif /* PETSCDEVICETYPES_H */
451