xref: /petsc/include/petscdevicetypes.h (revision a68bbae58a07f2fb515cab24a67de1159d72e8a2)
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 {
99 #ifdef __cplusplus
100   static_assert(PETSC_MEMTYPE_CUDA == PETSC_MEMTYPE_DEVICE, "");
101 #endif
102 #define PETSC_CASE_NAME(v) \
103 case v: \
104   return PetscStringize(v)
105 
106   switch (mtype) {
107     PETSC_CASE_NAME(PETSC_MEMTYPE_HOST);
108     /* PETSC_CASE_NAME(PETSC_MEMTYPE_DEVICE); same as PETSC_MEMTYPE_CUDA */
109     PETSC_CASE_NAME(PETSC_MEMTYPE_CUDA);
110     PETSC_CASE_NAME(PETSC_MEMTYPE_NVSHMEM);
111     PETSC_CASE_NAME(PETSC_MEMTYPE_HIP);
112     PETSC_CASE_NAME(PETSC_MEMTYPE_SYCL);
113   }
114   PetscUnreachable();
115   return "invalid";
116 #undef PETSC_CASE_NAME
117 }
118 
119 #define PETSC_OFFLOAD_VECKOKKOS_DEPRECATED PETSC_OFFLOAD_VECKOKKOS PETSC_DEPRECATED_ENUM("Use PETSC_OFFLOAD_KOKKOS (since version 3.17.0)")
120 
121 /*E
122   PetscOffloadMask - indicates which memory (CPU, GPU, or none) contains valid data
123 
124 $ PETSC_OFFLOAD_UNALLOCATED - no memory contains valid matrix entries; NEVER used for vectors
125 $ PETSC_OFFLOAD_GPU         - GPU has valid vector/matrix entries
126 $ PETSC_OFFLOAD_CPU         - CPU has valid vector/matrix entries
127 $ PETSC_OFFLOAD_BOTH        - Both GPU and CPU have valid vector/matrix entries and they match
128 $ 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.
129 
130   Developer Notes:
131   This enum uses a function (`PetscOffloadMaskToString()`) to convert to string representation so
132   cannot be used in `PetscOptionsEnum()`.
133 
134   Level: developer
135 
136 .seealso: `PetscOffloadMaskToString()`, `PetscOffloadMaskToMemType()`, `PetscOffloadMaskToDeviceCopyMode()`
137 E*/
138 typedef enum {
139   PETSC_OFFLOAD_UNALLOCATED          = 0x0,
140   PETSC_OFFLOAD_CPU                  = 0x1,
141   PETSC_OFFLOAD_GPU                  = 0x2,
142   PETSC_OFFLOAD_BOTH                 = 0x3,
143   PETSC_OFFLOAD_VECKOKKOS_DEPRECATED = 0x100,
144   PETSC_OFFLOAD_KOKKOS               = 0x100
145 } PetscOffloadMask;
146 
147 #define PetscOffloadUnallocated(m) ((m) == PETSC_OFFLOAD_UNALLOCATED)
148 #define PetscOffloadHost(m)        (((m)&PETSC_OFFLOAD_CPU) == PETSC_OFFLOAD_CPU)
149 #define PetscOffloadDevice(m)      (((m)&PETSC_OFFLOAD_GPU) == PETSC_OFFLOAD_GPU)
150 #define PetscOffloadBoth(m)        ((m) == PETSC_OFFLOAD_BOTH)
151 
152 #if defined(__cplusplus)
153   #if PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING
154     #pragma GCC diagnostic push
155     #pragma GCC diagnostic ignored "-Wtautological-compare"
156   #endif
157 static_assert(!PetscOffloadHost(PETSC_OFFLOAD_UNALLOCATED), "");
158 static_assert(PetscOffloadHost(PETSC_OFFLOAD_BOTH), "");
159 static_assert(!PetscOffloadHost(PETSC_OFFLOAD_GPU), "");
160 static_assert(PetscOffloadHost(PETSC_OFFLOAD_BOTH), "");
161 static_assert(!PetscOffloadHost(PETSC_OFFLOAD_KOKKOS), "");
162 
163 static_assert(!PetscOffloadDevice(PETSC_OFFLOAD_UNALLOCATED), "");
164 static_assert(!PetscOffloadDevice(PETSC_OFFLOAD_CPU), "");
165 static_assert(PetscOffloadDevice(PETSC_OFFLOAD_GPU), "");
166 static_assert(PetscOffloadDevice(PETSC_OFFLOAD_BOTH), "");
167 static_assert(!PetscOffloadDevice(PETSC_OFFLOAD_KOKKOS), "");
168 
169 static_assert(PetscOffloadBoth(PETSC_OFFLOAD_BOTH), "");
170 static_assert(!PetscOffloadBoth(PETSC_OFFLOAD_CPU), "");
171 static_assert(!PetscOffloadBoth(PETSC_OFFLOAD_GPU), "");
172 static_assert(!PetscOffloadBoth(PETSC_OFFLOAD_GPU), "");
173 static_assert(!PetscOffloadBoth(PETSC_OFFLOAD_KOKKOS), "");
174   #if PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING
175     #pragma GCC diagnostic pop
176   #endif
177 #endif // __cplusplus
178 
179 PETSC_NODISCARD static inline PETSC_CONSTEXPR_14 const char *PetscOffloadMaskToString(PetscOffloadMask mask)
180 {
181 #define PETSC_CASE_RETURN(v) \
182 case v: \
183   return PetscStringize(v)
184 
185   switch (mask) {
186     PETSC_CASE_RETURN(PETSC_OFFLOAD_UNALLOCATED);
187     PETSC_CASE_RETURN(PETSC_OFFLOAD_CPU);
188     PETSC_CASE_RETURN(PETSC_OFFLOAD_GPU);
189     PETSC_CASE_RETURN(PETSC_OFFLOAD_BOTH);
190     PETSC_CASE_RETURN(PETSC_OFFLOAD_KOKKOS);
191   }
192   PetscUnreachable();
193   return "invalid";
194 #undef PETSC_CASE_RETURN
195 }
196 
197 PETSC_NODISCARD static inline PETSC_CONSTEXPR_14 PetscMemType PetscOffloadMaskToMemType(PetscOffloadMask mask)
198 {
199   switch (mask) {
200   case PETSC_OFFLOAD_UNALLOCATED:
201   case PETSC_OFFLOAD_CPU:
202     return PETSC_MEMTYPE_HOST;
203   case PETSC_OFFLOAD_GPU:
204   case PETSC_OFFLOAD_BOTH:
205     return PETSC_MEMTYPE_DEVICE;
206   case PETSC_OFFLOAD_KOKKOS:
207     return PETSC_MEMTYPE_KOKKOS;
208   }
209   PetscUnreachable();
210   return PETSC_MEMTYPE_HOST;
211 }
212 
213 /*E
214   PetscDeviceInitType - Initialization strategy for `PetscDevice`
215 
216 $ PETSC_DEVICE_INIT_NONE  - PetscDevice is never initialized
217 $ PETSC_DEVICE_INIT_LAZY  - PetscDevice is initialized on demand
218 $ PETSC_DEVICE_INIT_EAGER - PetscDevice is initialized as soon as possible
219 
220   Notes:
221   `PETSC_DEVICE_INIT_NONE` implies that any initialization of `PetscDevice` is disallowed and
222   doing so results in an error. Useful to ensure that no accelerator is used in a program.
223 
224   Level: beginner
225 
226 .seealso: `PetscDevice`, `PetscDeviceType`, `PetscDeviceInitialize()`,
227 `PetscDeviceInitialized()`, `PetscDeviceCreate()`
228 E*/
229 typedef enum {
230   PETSC_DEVICE_INIT_NONE,
231   PETSC_DEVICE_INIT_LAZY,
232   PETSC_DEVICE_INIT_EAGER
233 } PetscDeviceInitType;
234 PETSC_EXTERN const char *const PetscDeviceInitTypes[];
235 
236 /*E
237   PetscDeviceType - Kind of accelerator device backend
238 
239 $ PETSC_DEVICE_HOST - Host, no accelerator backend found
240 $ PETSC_DEVICE_CUDA - CUDA enabled GPU
241 $ PETSC_DEVICE_HIP  - ROCM/HIP enabled GPU
242 $ PETSC_DEVICE_SYCL - SYCL enabled device
243 $ PETSC_DEVICE_MAX  - Always 1 greater than the largest valid PetscDeviceType, invalid type, do not use
244 
245   Notes:
246   One can also use the `PETSC_DEVICE_DEFAULT()` routine to get the current default `PetscDeviceType`.
247 
248   Level: beginner
249 
250 .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceCreate()`, `PETSC_DEVICE_DEFAULT()`
251 E*/
252 typedef enum {
253   PETSC_DEVICE_HOST,
254   PETSC_DEVICE_CUDA,
255   PETSC_DEVICE_HIP,
256   PETSC_DEVICE_SYCL,
257   PETSC_DEVICE_MAX
258 } PetscDeviceType;
259 PETSC_EXTERN const char *const PetscDeviceTypes[];
260 
261 /*E
262   PetscDeviceAttribute - Attribute detailing a property or feature of a `PetscDevice`
263 
264 $ PETSC_DEVICE_ATTR_SIZE_T_SHARED_MEM_PER_BLOCK - The maximum amount of shared memory per block in a
265 device kernel
266 $ PETSC_DEVICE_ATTR_MAX                         - Invalid attribute, do not use
267 
268   Level: beginner
269 
270 .seealso: `PetscDevice`, `PetscDeviceGetAttribute()`
271 E*/
272 typedef enum {
273   PETSC_DEVICE_ATTR_SIZE_T_SHARED_MEM_PER_BLOCK,
274   PETSC_DEVICE_ATTR_MAX
275 } PetscDeviceAttribute;
276 PETSC_EXTERN const char *const PetscDeviceAttributes[];
277 
278 /*S
279   PetscDevice - Object to manage an accelerator "device" (usually a GPU)
280 
281   Notes:
282   This object is used to house configuration and state of a device, but does not offer any
283   ability to interact with or drive device computation. This functionality is facilitated
284   instead by the `PetscDeviceContext` object.
285 
286   Level: beginner
287 
288 .seealso: `PetscDeviceType`, `PetscDeviceInitType`, `PetscDeviceCreate()`,
289 `PetscDeviceConfigure()`, `PetscDeviceDestroy()`, `PetscDeviceContext`,
290 `PetscDeviceContextSetDevice()`, `PetscDeviceContextGetDevice()`, `PetscDeviceGetAttribute()`
291 S*/
292 typedef struct _n_PetscDevice *PetscDevice;
293 
294 /*E
295   PetscStreamType - Stream blocking mode, indicates how a stream implementation will interact
296   with the default "NULL" stream, which is usually blocking.
297 
298 $ 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.
299 $ PETSC_STREAM_DEFAULT_BLOCKING   - Stream will act independent of other streams, but will still be blocked by actions on the NULL stream.
300 $ PETSC_STREAM_GLOBAL_NONBLOCKING - Stream is truly asynchronous, and is blocked by nothing, not even the NULL stream.
301 $ PETSC_STREAM_MAX                - Always 1 greater than the largest PetscStreamType, do not use
302 
303   Level: intermediate
304 
305 .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextGetStreamType()`
306 E*/
307 typedef enum {
308   PETSC_STREAM_GLOBAL_BLOCKING,
309   PETSC_STREAM_DEFAULT_BLOCKING,
310   PETSC_STREAM_GLOBAL_NONBLOCKING,
311   PETSC_STREAM_MAX
312 } PetscStreamType;
313 PETSC_EXTERN const char *const PetscStreamTypes[];
314 
315 /*E
316   PetscDeviceContextJoinMode - Describes the type of join operation to perform in
317   `PetscDeviceContextJoin()`
318 
319 $ PETSC_DEVICE_CONTEXT_JOIN_DESTROY - Destroy all incoming sub-contexts after join.
320 $ PETSC_DEVICE_CONTEXT_JOIN_SYNC    - Synchronize incoming sub-contexts after join.
321 $ PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC - Do not synchronize incoming sub-contexts after join.
322 
323   Level: beginner
324 
325 .seealso: `PetscDeviceContext`, `PetscDeviceContextFork()`, `PetscDeviceContextJoin()`
326 E*/
327 typedef enum {
328   PETSC_DEVICE_CONTEXT_JOIN_DESTROY,
329   PETSC_DEVICE_CONTEXT_JOIN_SYNC,
330   PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC
331 } PetscDeviceContextJoinMode;
332 PETSC_EXTERN const char *const PetscDeviceContextJoinModes[];
333 
334 /*S
335   PetscDeviceContext - Container to manage stream dependencies and the various solver handles
336   for asynchronous device compute.
337 
338   Level: beginner
339 
340 .seealso: `PetscDevice`, `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`,
341 `PetscDeviceContextDestroy()`, `PetscDeviceContextFork()`, `PetscDeviceContextJoin()`
342 S*/
343 typedef struct _p_PetscDeviceContext *PetscDeviceContext;
344 
345 /*E
346   PetscDeviceCopyMode - Describes the copy direction of a device-aware memcpy
347 
348 $ PETSC_DEVICE_COPY_HTOH - Copy from host memory to host memory
349 $ PETSC_DEVICE_COPY_DTOH - Copy from device memory to host memory
350 $ PETSC_DEVICE_COPY_HTOD - Copy from host memory to device memory
351 $ PETSC_DEVICE_COPY_DTOD - Copy from device memory to device memory
352 $ PETSC_DEVICE_COPY_AUTO - Infer the copy direction from the pointers
353 
354   Level: beginner
355 
356 .seealso: `PetscDeviceArrayCopy()`, `PetscDeviceMemcpy()`
357 E*/
358 typedef enum {
359   PETSC_DEVICE_COPY_HTOH,
360   PETSC_DEVICE_COPY_DTOH,
361   PETSC_DEVICE_COPY_HTOD,
362   PETSC_DEVICE_COPY_DTOD,
363   PETSC_DEVICE_COPY_AUTO,
364 } PetscDeviceCopyMode;
365 PETSC_EXTERN const char *const PetscDeviceCopyModes[];
366 
367 PETSC_NODISCARD static inline PetscDeviceCopyMode PetscOffloadMaskToDeviceCopyMode(PetscOffloadMask dest, PetscOffloadMask src)
368 {
369   PetscDeviceCopyMode mode;
370 
371   PetscFunctionBegin;
372   PetscAssertAbort(dest != PETSC_OFFLOAD_UNALLOCATED, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot copy to unallocated");
373   PetscAssertAbort(src != PETSC_OFFLOAD_UNALLOCATED, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot copy from unallocated");
374 
375   if (PetscOffloadDevice(dest)) {
376     mode = PetscOffloadHost(src) ? PETSC_DEVICE_COPY_HTOD : PETSC_DEVICE_COPY_DTOD;
377   } else {
378     mode = PetscOffloadHost(src) ? PETSC_DEVICE_COPY_HTOH : PETSC_DEVICE_COPY_DTOH;
379   }
380   PetscFunctionReturn(mode);
381 }
382 
383 PETSC_NODISCARD static inline PETSC_CONSTEXPR_14 PetscDeviceCopyMode PetscMemTypeToDeviceCopyMode(PetscMemType dest, PetscMemType src)
384 {
385   if (PetscMemTypeHost(dest)) {
386     return PetscMemTypeHost(src) ? PETSC_DEVICE_COPY_HTOH : PETSC_DEVICE_COPY_DTOH;
387   } else {
388     return PetscMemTypeDevice(src) ? PETSC_DEVICE_COPY_DTOD : PETSC_DEVICE_COPY_HTOD;
389   }
390 }
391 
392 /*E
393   PetscMemoryAccessMode - Describes the intended usage of a memory region
394 
395 + PETSC_MEMORY_ACCESS_READ       - Read only
396 . PETSC_MEMORY_ACCESS_WRITE      - Write only
397 - PETSC_MEMORY_ACCESS_READ_WRITE - Read and write
398 
399   Notes:
400   This `enum` is a bitmask with the following encoding (assuming 2 bit)\:
401 
402 .vb
403   PETSC_MEMORY_ACCESS_READ       = 0b01
404   PETSC_MEMORY_ACCESS_WRITE      = 0b10
405   PETSC_MEMORY_ACCESS_READ_WRITE = 0b11
406 
407   // consequently
408   PETSC_MEMORY_ACCESS_READ | PETSC_MEMORY_ACCESS_WRITE = PETSC_MEMORY_ACCESS_READ_WRITE
409 .ve
410 
411   The following convenience macros are also provided\:
412 
413   - `PetscMemoryAccessRead(mode)`\: `true` if `mode` is any kind of read, `false` otherwise
414   - `PetscMemoryAccessWrite(mode)`\: `true` if `mode` is any kind of write, `false` otherwise
415 
416   Developer Notes:
417   This enum uses a function (`PetscMemoryAccessModeToString()`) to convert values to string
418   representation, so cannot be used in `PetscOptionsEnum()`.
419 
420   Level: beginner
421 
422 .seealso: `PetscMemoryAccessModeToString()`, `PetscDevice`, `PetscDeviceContext`
423 E*/
424 typedef enum {
425   PETSC_MEMORY_ACCESS_READ       = 0x1, // 01
426   PETSC_MEMORY_ACCESS_WRITE      = 0x2, // 10
427   PETSC_MEMORY_ACCESS_READ_WRITE = 0x3, // 11
428 } PetscMemoryAccessMode;
429 
430 #define PetscMemoryAccessRead(m)  (((m)&PETSC_MEMORY_ACCESS_READ) == PETSC_MEMORY_ACCESS_READ)
431 #define PetscMemoryAccessWrite(m) (((m)&PETSC_MEMORY_ACCESS_WRITE) == PETSC_MEMORY_ACCESS_WRITE)
432 
433 #if defined(__cplusplus)
434   #if PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING
435     #pragma GCC diagnostic push
436     #pragma GCC diagnostic ignored "-Wtautological-compare"
437   #endif
438 static_assert(PetscMemoryAccessRead(PETSC_MEMORY_ACCESS_READ), "");
439 static_assert(PetscMemoryAccessRead(PETSC_MEMORY_ACCESS_READ_WRITE), "");
440 static_assert(!PetscMemoryAccessRead(PETSC_MEMORY_ACCESS_WRITE), "");
441 static_assert(PetscMemoryAccessWrite(PETSC_MEMORY_ACCESS_WRITE), "");
442 static_assert(PetscMemoryAccessWrite(PETSC_MEMORY_ACCESS_READ_WRITE), "");
443 static_assert(!PetscMemoryAccessWrite(PETSC_MEMORY_ACCESS_READ), "");
444 static_assert((PETSC_MEMORY_ACCESS_READ | PETSC_MEMORY_ACCESS_WRITE) == PETSC_MEMORY_ACCESS_READ_WRITE, "");
445   #if PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING
446     #pragma GCC diagnostic pop
447   #endif
448 #endif
449 
450 PETSC_NODISCARD static inline PETSC_CONSTEXPR_14 const char *PetscMemoryAccessModeToString(PetscMemoryAccessMode mode)
451 {
452 #define PETSC_CASE_RETURN(v) \
453 case v: \
454   return PetscStringize(v)
455 
456   switch (mode) {
457     PETSC_CASE_RETURN(PETSC_MEMORY_ACCESS_READ);
458     PETSC_CASE_RETURN(PETSC_MEMORY_ACCESS_WRITE);
459     PETSC_CASE_RETURN(PETSC_MEMORY_ACCESS_READ_WRITE);
460   }
461   PetscUnreachable();
462   return "invalid";
463 #undef PETSC_CASE_RETURN
464 }
465 
466 #undef PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING
467 
468 #endif /* PETSCDEVICETYPES_H */
469