1 #pragma once 2 3 #include <petscsys.h> /*I <petscdevicetypes.h> I*/ 4 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 12 13 /* SUBMANSEC = Sys */ 14 15 /*E 16 PetscMemType - Memory type of a pointer 17 18 Level: intermediate 19 20 Notes: 21 `PETSC_MEMTYPE_KOKKOS` depends on the Kokkos backend configuration 22 23 Developer Notes: 24 This enum uses a function (`PetscMemTypeToString()`) to convert to string representation so 25 cannot be used in `PetscOptionsEnum()`. 26 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 40 41 Other types of memory, e.g., CUDA managed memory, can be added when needed. 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(3, 17, 0, "PETSC_OFFLOAD_KOKKOS", ) 120 121 /*E 122 PetscOffloadMask - indicates which memory (CPU, GPU, or none) contains valid data 123 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. 130 131 Level: developer 132 133 Developer Notes: 134 This enum uses a function (`PetscOffloadMaskToString()`) to convert to string representation so 135 cannot be used in `PetscOptionsEnum()`. 136 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; 147 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) 152 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), ""); 163 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), ""); 169 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 179 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) 185 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 } 197 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 } 213 214 /*E 215 PetscDeviceInitType - Initialization strategy for `PetscDevice` 216 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 221 222 Level: beginner 223 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. 227 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[]; 237 238 /*E 239 PetscDeviceType - Kind of accelerator device backend 240 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 247 248 Level: beginner 249 250 Notes: 251 One can also use the `PETSC_DEVICE_DEFAULT()` routine to get the current default `PetscDeviceType`. 252 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[]; 263 264 /*E 265 PetscDeviceAttribute - Attribute detailing a property or feature of a `PetscDevice` 266 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 270 271 Level: beginner 272 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[]; 280 281 /*S 282 PetscDevice - Object to manage an accelerator "device" (usually a GPU) 283 284 Level: beginner 285 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. 290 291 .seealso: `PetscDeviceType`, `PetscDeviceInitType`, `PetscDeviceCreate()`, 292 `PetscDeviceConfigure()`, `PetscDeviceDestroy()`, `PetscDeviceContext`, 293 `PetscDeviceContextSetDevice()`, `PetscDeviceContextGetDevice()`, `PetscDeviceGetAttribute()` 294 S*/ 295 typedef struct _n_PetscDevice *PetscDevice; 296 297 /*E 298 PetscStreamType - Stream blocking mode, indicates how a stream implementation will interact 299 with the default `NULL` stream, which is usually blocking. 300 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 306 307 Level: intermediate 308 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[]; 318 319 /*E 320 PetscDeviceContextJoinMode - Describes the type of join operation to perform in 321 `PetscDeviceContextJoin()` 322 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. 327 328 Level: beginner 329 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[]; 338 339 /*S 340 PetscDeviceContext - Container to manage stream dependencies and the various solver handles 341 for asynchronous device compute. 342 343 Level: beginner 344 345 .seealso: `PetscDevice`, `PetscDeviceContextCreate()`, `PetscDeviceContextSetDevice()`, 346 `PetscDeviceContextDestroy()`, `PetscDeviceContextFork()`, `PetscDeviceContextJoin()` 347 S*/ 348 typedef struct _p_PetscDeviceContext *PetscDeviceContext; 349 350 /*E 351 PetscDeviceCopyMode - Describes the copy direction of a device-aware `memcpy` 352 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 359 360 Level: beginner 361 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[]; 372 373 PETSC_NODISCARD static inline PetscDeviceCopyMode PetscOffloadMaskToDeviceCopyMode(PetscOffloadMask dest, PetscOffloadMask src) 374 { 375 PetscDeviceCopyMode mode; 376 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"); 380 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 } 388 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 } 397 398 /*E 399 PetscMemoryAccessMode - Describes the intended usage of a memory region 400 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 405 406 Level: beginner 407 408 Notes: 409 This `enum` is a bitmask with the following encoding (assuming 2 bit)\: 410 411 .vb 412 PETSC_MEMORY_ACCESS_READ = 0b01 413 PETSC_MEMORY_ACCESS_WRITE = 0b10 414 PETSC_MEMORY_ACCESS_READ_WRITE = 0b11 415 416 // consequently 417 PETSC_MEMORY_ACCESS_READ | PETSC_MEMORY_ACCESS_WRITE = PETSC_MEMORY_ACCESS_READ_WRITE 418 .ve 419 420 The following convenience macros are also provided\: 421 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 424 425 Developer Notes: 426 This enum uses a function (`PetscMemoryAccessModeToString()`) to convert values to string 427 representation, so cannot be used in `PetscOptionsEnum()`. 428 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; 436 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) 439 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 456 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) 462 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 } 472 473 #undef PETSC_SHOULD_SILENCE_GCC_TAUTOLOGICAL_COMPARE_WARNING 474