Actual source code: petscdevicetypes.h
1: #pragma once
3: #include <petscsys.h>
5: // Some overzealous older gcc versions warn that the comparisons below are always true. Neat
6: // that it can detect this, but the tautology *is* the point of the static_assert()!
7: #if defined(__GNUC__) && __GNUC__ >= 6 && !PetscDefined(HAVE_WINDOWS_COMPILERS)
8: #define PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING 1
9: #else
10: #define PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING 0
11: #endif
13: /* SUBMANSEC = Sys */
15: /*E
16: PetscMemType - Memory type of a pointer
18: Level: intermediate
20: Notes:
21: `PETSC_MEMTYPE_KOKKOS` depends on the Kokkos backend configuration
23: Developer Notes:
24: This enum uses a function (`PetscMemTypeToString()`) to convert to string representation so
25: cannot be used in `PetscOptionsEnum()`.
27: Developer Note:
28: Encoding of the bitmask in binary: xxxxyyyz
29: .vb
30: z = 0 - Host memory
31: z = 1 - Device memory
32: yyy = 000 - CUDA-related memory
33: yyy = 001 - HIP-related memory
34: yyy = 010 - SYCL-related memory
35: xxxxyyy1 = 0000,0001 - CUDA memory
36: xxxxyyy1 = 0001,0001 - CUDA NVSHMEM memory
37: xxxxyyy1 = 0000,0011 - HIP memory
38: xxxxyyy1 = 0000,0101 - SYCL memory
39: .ve
41: Other types of memory, e.g., CUDA managed memory, can be added when needed.
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
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)
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), "");
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), "");
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
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)
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: }
119: #define PETSC_OFFLOAD_VECKOKKOS_DEPRECATED PETSC_OFFLOAD_VECKOKKOS PETSC_DEPRECATED_ENUM(3, 17, 0, "PETSC_OFFLOAD_KOKKOS", )
121: /*E
122: PetscOffloadMask - indicates which memory (CPU, GPU, or none) contains valid data
124: Values:
125: + `PETSC_OFFLOAD_UNALLOCATED` - no memory contains valid matrix entries; NEVER used for vectors
126: . `PETSC_OFFLOAD_GPU` - GPU has valid vector/matrix entries
127: . `PETSC_OFFLOAD_CPU` - CPU has valid vector/matrix entries
128: . `PETSC_OFFLOAD_BOTH` - Both GPU and CPU have valid vector/matrix entries and they match
129: - `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.
131: Level: developer
133: Developer Notes:
134: This enum uses a function (`PetscOffloadMaskToString()`) to convert to string representation so
135: cannot be used in `PetscOptionsEnum()`.
137: .seealso: `PetscOffloadMaskToString()`, `PetscOffloadMaskToMemType()`, `PetscOffloadMaskToDeviceCopyMode()`
138: E*/
139: typedef enum {
140: PETSC_OFFLOAD_UNALLOCATED = 0x0,
141: PETSC_OFFLOAD_CPU = 0x1,
142: PETSC_OFFLOAD_GPU = 0x2,
143: PETSC_OFFLOAD_BOTH = 0x3,
144: PETSC_OFFLOAD_VECKOKKOS_DEPRECATED = 0x100,
145: PETSC_OFFLOAD_KOKKOS = 0x100
146: } PetscOffloadMask;
148: #define PetscOffloadUnallocated(m) ((m) == PETSC_OFFLOAD_UNALLOCATED)
149: #define PetscOffloadHost(m) (((m)&PETSC_OFFLOAD_CPU) == PETSC_OFFLOAD_CPU)
150: #define PetscOffloadDevice(m) (((m)&PETSC_OFFLOAD_GPU) == PETSC_OFFLOAD_GPU)
151: #define PetscOffloadBoth(m) ((m) == PETSC_OFFLOAD_BOTH)
153: #if defined(__cplusplus)
154: #if PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING
155: #pragma GCC diagnostic push
156: #pragma GCC diagnostic ignored "-Wtautological-compare"
157: #endif
158: static_assert(!PetscOffloadHost(PETSC_OFFLOAD_UNALLOCATED), "");
159: static_assert(PetscOffloadHost(PETSC_OFFLOAD_BOTH), "");
160: static_assert(!PetscOffloadHost(PETSC_OFFLOAD_GPU), "");
161: static_assert(PetscOffloadHost(PETSC_OFFLOAD_BOTH), "");
162: static_assert(!PetscOffloadHost(PETSC_OFFLOAD_KOKKOS), "");
164: static_assert(!PetscOffloadDevice(PETSC_OFFLOAD_UNALLOCATED), "");
165: static_assert(!PetscOffloadDevice(PETSC_OFFLOAD_CPU), "");
166: static_assert(PetscOffloadDevice(PETSC_OFFLOAD_GPU), "");
167: static_assert(PetscOffloadDevice(PETSC_OFFLOAD_BOTH), "");
168: static_assert(!PetscOffloadDevice(PETSC_OFFLOAD_KOKKOS), "");
170: static_assert(PetscOffloadBoth(PETSC_OFFLOAD_BOTH), "");
171: static_assert(!PetscOffloadBoth(PETSC_OFFLOAD_CPU), "");
172: static_assert(!PetscOffloadBoth(PETSC_OFFLOAD_GPU), "");
173: static_assert(!PetscOffloadBoth(PETSC_OFFLOAD_GPU), "");
174: static_assert(!PetscOffloadBoth(PETSC_OFFLOAD_KOKKOS), "");
175: #if PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING
176: #pragma GCC diagnostic pop
177: #endif
178: #endif // __cplusplus
180: PETSC_NODISCARD static inline PETSC_CONSTEXPR_14 const char *PetscOffloadMaskToString(PetscOffloadMask mask)
181: {
182: #define PETSC_CASE_RETURN(v) \
183: case v: \
184: return PetscStringize(v)
186: switch (mask) {
187: PETSC_CASE_RETURN(PETSC_OFFLOAD_UNALLOCATED);
188: PETSC_CASE_RETURN(PETSC_OFFLOAD_CPU);
189: PETSC_CASE_RETURN(PETSC_OFFLOAD_GPU);
190: PETSC_CASE_RETURN(PETSC_OFFLOAD_BOTH);
191: PETSC_CASE_RETURN(PETSC_OFFLOAD_KOKKOS);
192: }
193: PetscUnreachable();
194: return "invalid";
195: #undef PETSC_CASE_RETURN
196: }
198: PETSC_NODISCARD static inline PETSC_CONSTEXPR_14 PetscMemType PetscOffloadMaskToMemType(PetscOffloadMask mask)
199: {
200: switch (mask) {
201: case PETSC_OFFLOAD_UNALLOCATED:
202: case PETSC_OFFLOAD_CPU:
203: return PETSC_MEMTYPE_HOST;
204: case PETSC_OFFLOAD_GPU:
205: case PETSC_OFFLOAD_BOTH:
206: return PETSC_MEMTYPE_DEVICE;
207: case PETSC_OFFLOAD_KOKKOS:
208: return PETSC_MEMTYPE_KOKKOS;
209: }
210: PetscUnreachable();
211: return PETSC_MEMTYPE_HOST;
212: }
214: /*E
215: PetscDeviceInitType - Initialization strategy for `PetscDevice`
217: Values:
218: + `PETSC_DEVICE_INIT_NONE` - PetscDevice is never initialized
219: . `PETSC_DEVICE_INIT_LAZY` - PetscDevice is initialized on demand
220: - `PETSC_DEVICE_INIT_EAGER` - PetscDevice is initialized as soon as possible
222: Level: beginner
224: Notes:
225: `PETSC_DEVICE_INIT_NONE` implies that any initialization of `PetscDevice` is disallowed and
226: doing so results in an error. Useful to ensure that no accelerator is used in a program.
228: .seealso: `PetscDevice`, `PetscDeviceType`, `PetscDeviceInitialize()`,
229: `PetscDeviceInitialized()`, `PetscDeviceCreate()`
230: E*/
231: typedef enum {
232: PETSC_DEVICE_INIT_NONE,
233: PETSC_DEVICE_INIT_LAZY,
234: PETSC_DEVICE_INIT_EAGER
235: } PetscDeviceInitType;
236: PETSC_EXTERN const char *const PetscDeviceInitTypes[];
238: /*E
239: PetscDeviceType - Kind of accelerator device backend
241: Values:
242: + `PETSC_DEVICE_HOST` - Host, no accelerator backend found
243: . `PETSC_DEVICE_CUDA` - CUDA enabled GPU
244: . `PETSC_DEVICE_HIP` - ROCM/HIP enabled GPU
245: . `PETSC_DEVICE_SYCL` - SYCL enabled device
246: - `PETSC_DEVICE_MAX` - Always 1 greater than the largest valid `PetscDeviceType`, invalid type, do not use
248: Level: beginner
250: Notes:
251: One can also use the `PETSC_DEVICE_DEFAULT()` routine to get the current default `PetscDeviceType`.
253: .seealso: `PetscDevice`, `PetscDeviceInitType`, `PetscDeviceCreate()`, `PETSC_DEVICE_DEFAULT()`
254: E*/
255: typedef enum {
256: PETSC_DEVICE_HOST,
257: PETSC_DEVICE_CUDA,
258: PETSC_DEVICE_HIP,
259: PETSC_DEVICE_SYCL,
260: PETSC_DEVICE_MAX
261: } PetscDeviceType;
262: PETSC_EXTERN const char *const PetscDeviceTypes[];
264: /*E
265: PetscDeviceAttribute - Attribute detailing a property or feature of a `PetscDevice`
267: Values:
268: + `PETSC_DEVICE_ATTR_SIZE_T_SHARED_MEM_PER_BLOCK` - The maximum amount of shared memory per block in a device kernel
269: - `PETSC_DEVICE_ATTR_MAX` - Invalid attribute, do not use
271: Level: beginner
273: .seealso: `PetscDevice`, `PetscDeviceGetAttribute()`
274: E*/
275: typedef enum {
276: PETSC_DEVICE_ATTR_SIZE_T_SHARED_MEM_PER_BLOCK,
277: PETSC_DEVICE_ATTR_MAX
278: } PetscDeviceAttribute;
279: PETSC_EXTERN const char *const PetscDeviceAttributes[];
281: /*S
282: PetscDevice - Object to manage an accelerator "device" (usually a GPU)
284: Level: beginner
286: Notes:
287: This object is used to house configuration and state of a device, but does not offer any
288: ability to interact with or drive device computation. This functionality is facilitated
289: instead by the `PetscDeviceContext` object.
291: .seealso: `PetscDeviceType`, `PetscDeviceInitType`, `PetscDeviceCreate()`,
292: `PetscDeviceConfigure()`, `PetscDeviceDestroy()`, `PetscDeviceContext`,
293: `PetscDeviceContextSetDevice()`, `PetscDeviceContextGetDevice()`, `PetscDeviceGetAttribute()`
294: S*/
295: typedef struct _n_PetscDevice *PetscDevice;
297: /*E
298: PetscStreamType - Stream blocking mode, indicates how a stream implementation will interact
299: with the default `NULL` stream, which is usually blocking.
301: Values:
302: + `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.
303: . `PETSC_STREAM_DEFAULT_BLOCKING` - Stream will act independent of other streams, but will still be blocked by actions on the `NULL` stream.
304: . `PETSC_STREAM_GLOBAL_NONBLOCKING` - Stream is truly asynchronous, and is blocked by nothing, not even the `NULL` stream.
305: - `PETSC_STREAM_MAX` - Always 1 greater than the largest `PetscStreamType`, do not use
307: Level: intermediate
309: .seealso: `PetscDeviceContextSetStreamType()`, `PetscDeviceContextGetStreamType()`
310: E*/
311: typedef enum {
312: PETSC_STREAM_GLOBAL_BLOCKING,
313: PETSC_STREAM_DEFAULT_BLOCKING,
314: PETSC_STREAM_GLOBAL_NONBLOCKING,
315: PETSC_STREAM_MAX
316: } PetscStreamType;
317: PETSC_EXTERN const char *const PetscStreamTypes[];
319: /*E
320: PetscDeviceContextJoinMode - Describes the type of join operation to perform in
321: `PetscDeviceContextJoin()`
323: Values:
324: + `PETSC_DEVICE_CONTEXT_JOIN_DESTROY` - Destroy all incoming sub-contexts after join.
325: . `PETSC_DEVICE_CONTEXT_JOIN_SYNC` - Synchronize incoming sub-contexts after join.
326: - `PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC` - Do not synchronize incoming sub-contexts after join.
328: Level: beginner
330: .seealso: `PetscDeviceContext`, `PetscDeviceContextFork()`, `PetscDeviceContextJoin()`
331: E*/
332: typedef enum {
333: PETSC_DEVICE_CONTEXT_JOIN_DESTROY,
334: PETSC_DEVICE_CONTEXT_JOIN_SYNC,
335: PETSC_DEVICE_CONTEXT_JOIN_NO_SYNC
336: } PetscDeviceContextJoinMode;
337: PETSC_EXTERN const char *const PetscDeviceContextJoinModes[];
339: /*S
340: PetscDeviceContext - Container to manage stream dependencies and the various solver handles
341: for asynchronous device compute.
343: Level: beginner
345: .seealso: `PetscDevice`, `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`,
346: `PetscDeviceContextDestroy()`, `PetscDeviceContextFork()`, `PetscDeviceContextJoin()`
347: S*/
348: typedef struct _p_PetscDeviceContext *PetscDeviceContext;
350: /*E
351: PetscDeviceCopyMode - Describes the copy direction of a device-aware `memcpy`
353: Values:
354: + `PETSC_DEVICE_COPY_HTOH` - Copy from host memory to host memory
355: . `PETSC_DEVICE_COPY_DTOH` - Copy from device memory to host memory
356: . `PETSC_DEVICE_COPY_HTOD` - Copy from host memory to device memory
357: . `PETSC_DEVICE_COPY_DTOD` - Copy from device memory to device memory
358: - `PETSC_DEVICE_COPY_AUTO` - Infer the copy direction from the pointers
360: Level: beginner
362: .seealso: `PetscDeviceArrayCopy()`, `PetscDeviceMemcpy()`
363: E*/
364: typedef enum {
365: PETSC_DEVICE_COPY_HTOH,
366: PETSC_DEVICE_COPY_DTOH,
367: PETSC_DEVICE_COPY_HTOD,
368: PETSC_DEVICE_COPY_DTOD,
369: PETSC_DEVICE_COPY_AUTO,
370: } PetscDeviceCopyMode;
371: PETSC_EXTERN const char *const PetscDeviceCopyModes[];
373: PETSC_NODISCARD static inline PetscDeviceCopyMode PetscOffloadMaskToDeviceCopyMode(PetscOffloadMask dest, PetscOffloadMask src)
374: {
375: PetscDeviceCopyMode mode;
377: PetscFunctionBegin;
378: PetscAssertAbort(dest != PETSC_OFFLOAD_UNALLOCATED, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot copy to unallocated");
379: PetscAssertAbort(src != PETSC_OFFLOAD_UNALLOCATED, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot copy from unallocated");
381: if (PetscOffloadDevice(dest)) {
382: mode = PetscOffloadHost(src) ? PETSC_DEVICE_COPY_HTOD : PETSC_DEVICE_COPY_DTOD;
383: } else {
384: mode = PetscOffloadHost(src) ? PETSC_DEVICE_COPY_HTOH : PETSC_DEVICE_COPY_DTOH;
385: }
386: PetscFunctionReturn(mode);
387: }
389: PETSC_NODISCARD static inline PETSC_CONSTEXPR_14 PetscDeviceCopyMode PetscMemTypeToDeviceCopyMode(PetscMemType dest, PetscMemType src)
390: {
391: if (PetscMemTypeHost(dest)) {
392: return PetscMemTypeHost(src) ? PETSC_DEVICE_COPY_HTOH : PETSC_DEVICE_COPY_DTOH;
393: } else {
394: return PetscMemTypeDevice(src) ? PETSC_DEVICE_COPY_DTOD : PETSC_DEVICE_COPY_HTOD;
395: }
396: }
398: /*E
399: PetscMemoryAccessMode - Describes the intended usage of a memory region
401: Values:
402: + `PETSC_MEMORY_ACCESS_READ` - Read only
403: . `PETSC_MEMORY_ACCESS_WRITE` - Write only
404: - `PETSC_MEMORY_ACCESS_READ_WRITE` - Read and write
406: Level: beginner
408: Notes:
409: This `enum` is a bitmask with the following encoding (assuming 2 bit)\:
411: .vb
412: PETSC_MEMORY_ACCESS_READ = 0b01
413: PETSC_MEMORY_ACCESS_WRITE = 0b10
414: PETSC_MEMORY_ACCESS_READ_WRITE = 0b11
416: // consequently
417: PETSC_MEMORY_ACCESS_READ | PETSC_MEMORY_ACCESS_WRITE = PETSC_MEMORY_ACCESS_READ_WRITE
418: .ve
420: The following convenience macros are also provided\:
422: + `PetscMemoryAccessRead(mode)` - `true` if `mode` is any kind of read, `false` otherwise
423: - `PetscMemoryAccessWrite(mode)` - `true` if `mode` is any kind of write, `false` otherwise
425: Developer Notes:
426: This enum uses a function (`PetscMemoryAccessModeToString()`) to convert values to string
427: representation, so cannot be used in `PetscOptionsEnum()`.
429: .seealso: `PetscMemoryAccessModeToString()`, `PetscDevice`, `PetscDeviceContext`
430: E*/
431: typedef enum {
432: PETSC_MEMORY_ACCESS_READ = 0x1, // 01
433: PETSC_MEMORY_ACCESS_WRITE = 0x2, // 10
434: PETSC_MEMORY_ACCESS_READ_WRITE = 0x3, // 11
435: } PetscMemoryAccessMode;
437: #define PetscMemoryAccessRead(m) (((m)&PETSC_MEMORY_ACCESS_READ) == PETSC_MEMORY_ACCESS_READ)
438: #define PetscMemoryAccessWrite(m) (((m)&PETSC_MEMORY_ACCESS_WRITE) == PETSC_MEMORY_ACCESS_WRITE)
440: #if defined(__cplusplus)
441: #if PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING
442: #pragma GCC diagnostic push
443: #pragma GCC diagnostic ignored "-Wtautological-compare"
444: #endif
445: static_assert(PetscMemoryAccessRead(PETSC_MEMORY_ACCESS_READ), "");
446: static_assert(PetscMemoryAccessRead(PETSC_MEMORY_ACCESS_READ_WRITE), "");
447: static_assert(!PetscMemoryAccessRead(PETSC_MEMORY_ACCESS_WRITE), "");
448: static_assert(PetscMemoryAccessWrite(PETSC_MEMORY_ACCESS_WRITE), "");
449: static_assert(PetscMemoryAccessWrite(PETSC_MEMORY_ACCESS_READ_WRITE), "");
450: static_assert(!PetscMemoryAccessWrite(PETSC_MEMORY_ACCESS_READ), "");
451: static_assert((PETSC_MEMORY_ACCESS_READ | PETSC_MEMORY_ACCESS_WRITE) == PETSC_MEMORY_ACCESS_READ_WRITE, "");
452: #if PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING
453: #pragma GCC diagnostic pop
454: #endif
455: #endif
457: PETSC_NODISCARD static inline PETSC_CONSTEXPR_14 const char *PetscMemoryAccessModeToString(PetscMemoryAccessMode mode)
458: {
459: #define PETSC_CASE_RETURN(v) \
460: case v: \
461: return PetscStringize(v)
463: switch (mode) {
464: PETSC_CASE_RETURN(PETSC_MEMORY_ACCESS_READ);
465: PETSC_CASE_RETURN(PETSC_MEMORY_ACCESS_WRITE);
466: PETSC_CASE_RETURN(PETSC_MEMORY_ACCESS_READ_WRITE);
467: }
468: PetscUnreachable();
469: return "invalid";
470: #undef PETSC_CASE_RETURN
471: }
473: #undef PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING