// Tests multiple kernels running concurrently. Runs two kernels, which // increment a global atomic counter and wait for the counter to reach 2. // // RUN: mlir-opt %s \ // RUN: | mlir-opt -gpu-lower-to-nvvm-pipeline="cubin-format=%gpu_compilation_format allow-pattern-rollback=0" \ // RUN: | env CUDA_MODULE_LOADING=EAGER mlir-runner \ // RUN: --shared-libs=%mlir_cuda_runtime \ // RUN: --shared-libs=%mlir_runner_utils \ // RUN: --entry-point-result=void // CUDA_MODULE_LOADING=EAGER avoids an implicit context synchronization on first // use of each kernel. It is technically not needed for this test, because // there is only one kernel. module attributes {gpu.container_module} { gpu.module @kernels { gpu.func @kernel(%memref: memref) kernel { %c0 = arith.constant 0 : i32 %c1 = arith.constant 1 : i32 %c2 = arith.constant 2 : i32 %block = memref.atomic_rmw addi %c1, %memref[] : (i32, memref) -> i32 scf.while: () -> () { %value = memref.atomic_rmw addi %c0, %memref[] : (i32, memref) -> i32 %cond = arith.cmpi slt, %value, %c2 : i32 scf.condition(%cond) } do { scf.yield } gpu.return } } func.func @main() { %c0 = arith.constant 0 : i32 %c1 = arith.constant 1 : index %memref = gpu.alloc host_shared () : memref memref.store %c0, %memref[] : memref %0 = gpu.wait async %1 = gpu.wait async %2 = gpu.launch_func async [%0] @kernels::@kernel blocks in (%c1, %c1, %c1) threads in (%c1, %c1, %c1) args(%memref: memref) %3 = gpu.launch_func async [%1] @kernels::@kernel blocks in (%c1, %c1, %c1) threads in (%c1, %c1, %c1) args(%memref: memref) gpu.wait [%2, %3] return } }