[llvm-branch-commits] [clang] [llvm] [LLVMOffload] Add blocking to LaunchKernel and Memcpy (PR #216430)
Sophia Herrmann via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Aug 17 11:16:12 PDT 2026
https://github.com/jellytabby updated https://github.com/llvm/llvm-project/pull/216430
>From 928811ed33aec0355242f9072935b36c8c112944 Mon Sep 17 00:00:00 2001
From: Sophia Herrmann <herrmann15 at llnl.gov>
Date: Thu, 13 Aug 2026 16:47:23 -0700
Subject: [PATCH] add blocking semantics to LaunchKernel and Memcpy
---
clang/lib/CodeGen/CGCUDANV.cpp | 4 +-
clang/lib/Driver/ToolChains/Clang.cpp | 1 +
.../languages/kernel/include/LanguageUtils.h | 54 +++++++-
.../languages/kernel/src/LanguageLaunch.cpp | 20 ++-
.../languages/kernel/src/LanguageRuntime.cpp | 25 +++-
.../CUDA/blocking_stream_semantics.cu | 131 ++++++++++++++++++
offload/test/offloading/CUDA/stream_api.cu | 6 +-
.../HIP/blocking_stream_semantics.hip | 125 +++++++++++++++++
offload/test/offloading/HIP/stream_api.hip | 6 +-
9 files changed, 355 insertions(+), 17 deletions(-)
create mode 100644 offload/test/offloading/CUDA/blocking_stream_semantics.cu
create mode 100644 offload/test/offloading/HIP/blocking_stream_semantics.hip
diff --git a/clang/lib/CodeGen/CGCUDANV.cpp b/clang/lib/CodeGen/CGCUDANV.cpp
index 2c6965ce894d9..5ced4b6694a5c 100644
--- a/clang/lib/CodeGen/CGCUDANV.cpp
+++ b/clang/lib/CodeGen/CGCUDANV.cpp
@@ -442,7 +442,9 @@ void CGNVCUDARuntime::emitDeviceStubBodyNew(CodeGenFunction &CGF,
std::string KernelLaunchAPI = "LaunchKernel";
if (CGF.getLangOpts().GPUDefaultStream ==
LangOptions::GPUDefaultStreamKind::PerThread) {
- if (CGF.getLangOpts().HIP)
+ if (CGF.getLangOpts().OffloadViaLLVM)
+ KernelLaunchAPI = KernelLaunchAPI + "";
+ else if (CGF.getLangOpts().HIP)
KernelLaunchAPI = KernelLaunchAPI + "_spt";
else if (CGF.getLangOpts().CUDA)
KernelLaunchAPI = KernelLaunchAPI + "_ptsz";
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 54583fe3abbd8..8b21400ab959f 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -8396,6 +8396,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (IsHIP) {
CmdArgs.push_back("-fcuda-allow-variadic-functions");
+ /// TODO: Why is this not forwarded when IsCUDA?
Args.AddLastArg(CmdArgs, options::OPT_fgpu_default_stream_EQ);
}
diff --git a/offload/languages/kernel/include/LanguageUtils.h b/offload/languages/kernel/include/LanguageUtils.h
index 730857e00461f..e7f95e0d0b485 100644
--- a/offload/languages/kernel/include/LanguageUtils.h
+++ b/offload/languages/kernel/include/LanguageUtils.h
@@ -13,6 +13,11 @@
#include "OffloadAPI.h"
#include "State.h"
#include "Stream.h"
+#include "llvm/ADT/SmallVector.h"
+
+using RuntimeState = llvm::offload::StateTy;
+using ThreadState = llvm::offload::ThreadStateTy;
+using StreamTy = llvm::offload::StreamTy;
/// Convert an ol_result_t to the active language's Error_t.
static inline Error_t convertResult(ol_result_t Result) {
@@ -40,8 +45,7 @@ static inline Error_t convertResult(ol_result_t Result) {
/// Set the last error for the current thread and return it.
static inline Error_t setLastError(Error_t Error) {
// TODO: find a more efficient way to set last error
- return static_cast<Error_t>(
- llvm::offload::ThreadStateTy::setLastError(Error));
+ return static_cast<Error_t>(ThreadState::setLastError(Error));
}
/// Convert an ol_result_t to the active language's Error_t and set it as the
@@ -51,12 +55,54 @@ static inline Error_t convertAndSetLastError(ol_result_t Result) {
}
/// Convert between the language-facing opaque stream and the internal stream.
-static inline Stream_t makeLanguageStream(llvm::offload::StreamTy *Stream) {
+static inline Stream_t makeLanguageStream(StreamTy *Stream) {
return reinterpret_cast<Stream_t>(Stream);
}
static inline llvm::offload::StreamTy *getInternalStream(Stream_t Stream) {
- return reinterpret_cast<llvm::offload::StreamTy *>(Stream);
+ return reinterpret_cast<StreamTy *>(Stream);
+}
+
+/// Wait for blocking streams before executing on the legacy default stream.
+static inline ol_result_t waitOnBlockingStreams(StreamTy *LegacyDefaultStream,
+ ol_device_handle_t Device) {
+ if (!LegacyDefaultStream ||
+ LegacyDefaultStream->Kind != llvm::offload::QueueKind::LegacyDefault)
+ return OL_SUCCESS;
+
+ llvm::SmallVector<ol_event_handle_t, 8> Events;
+ for (StreamTy *BlockingStream : RuntimeState::getBlockingStreams(Device)) {
+ ol_event_handle_t Event = nullptr;
+ ol_result_t Result =
+ olCreateEvent(BlockingStream->Queue, OL_EVENT_FLAGS_NONE, &Event);
+ if (Result != OL_SUCCESS)
+ return Result;
+ Events.push_back(Event);
+ }
+
+ if (Events.empty())
+ return OL_SUCCESS;
+ return olWaitEvents(LegacyDefaultStream->Queue, Events.data(), Events.size());
+}
+
+/// Wait for the legacy default stream to complete before launching a kernel on
+/// a blocking stream.
+static inline ol_result_t waitOnLegacyDefaultStream(StreamTy *SourceStream,
+ ol_device_handle_t Device) {
+ if (!RuntimeState::hasLegacyDefaultStream(Device))
+ return OL_SUCCESS;
+
+ StreamTy *DefaultStream = ThreadState::getDefaultStream();
+ if (!DefaultStream ||
+ DefaultStream->Kind != llvm::offload::QueueKind::LegacyDefault)
+ return OL_SUCCESS;
+
+ ol_event_handle_t Event = nullptr;
+ ol_result_t Result =
+ olCreateEvent(DefaultStream->Queue, OL_EVENT_FLAGS_NONE, &Event);
+ if (Result != OL_SUCCESS)
+ return Result;
+ return olWaitEvents(SourceStream->Queue, &Event, 1);
}
/// Convert a Stream_t to an ol_queue_handle_t.
diff --git a/offload/languages/kernel/src/LanguageLaunch.cpp b/offload/languages/kernel/src/LanguageLaunch.cpp
index 935937f48d67a..f4f4a3be39903 100644
--- a/offload/languages/kernel/src/LanguageLaunch.cpp
+++ b/offload/languages/kernel/src/LanguageLaunch.cpp
@@ -8,6 +8,7 @@
#include "LanguageLaunch.h"
#include "LanguageUtils.h"
+#include "OffloadAPI.h"
#include "State.h"
#include "Stream.h"
#include <cstdio>
@@ -59,8 +60,21 @@ ol_result_t __llvmLaunchKernelImpl(const char *KernelID, dim3 GridDim,
LaunchSizeArgs.GroupSize.z = BlockDim.z;
LaunchSizeArgs.DynSharedMemory = DynamicSharedMem;
- ol_queue_handle_t Queue = Stream ? reinterpret_cast<StreamTy *>(Stream)->Queue
- : ThreadState::getDefaultQueue();
+ StreamTy *LaunchStream = Stream ? reinterpret_cast<StreamTy *>(Stream)
+ : ThreadState::getDefaultStream();
+ if (!LaunchStream || !RuntimeState::isStreamRegistered(LaunchStream) ||
+ LaunchStream->Device != Device)
+ return &InvalidConfigurationError;
+
+ if (LaunchStream->Kind == llvm::offload::QueueKind::LegacyDefault) {
+ ol_result_t Result = waitOnBlockingStreams(LaunchStream, Device);
+ if (Result != OL_SUCCESS)
+ return Result;
+ } else if (LaunchStream->Kind == llvm::offload::QueueKind::ExplicitBlocking) {
+ ol_result_t Result = waitOnLegacyDefaultStream(LaunchStream, Device);
+ if (Result != OL_SUCCESS)
+ return Result;
+ }
struct OffloadKernelArgs {
void **Args;
@@ -76,7 +90,7 @@ ol_result_t __llvmLaunchKernelImpl(const char *KernelID, dim3 GridDim,
if (!OKA->Args[I] || OKA->ArgSizes[I] == 0)
return &InvalidArgumentError;
- return olLaunchKernel(Queue, Device, Kernel, &LaunchSizeArgs,
+ return olLaunchKernel(LaunchStream->Queue, Device, Kernel, &LaunchSizeArgs,
/*Properties=*/nullptr, OKA->NumArgs, OKA->Args,
OKA->ArgSizes);
}
diff --git a/offload/languages/kernel/src/LanguageRuntime.cpp b/offload/languages/kernel/src/LanguageRuntime.cpp
index f0298302b2889..537dcea3bd142 100644
--- a/offload/languages/kernel/src/LanguageRuntime.cpp
+++ b/offload/languages/kernel/src/LanguageRuntime.cpp
@@ -23,6 +23,7 @@
#include "Types.h"
#include "OffloadAPI.h"
+#include "llvm/ADT/SmallVector.h"
#include <cassert>
#include <cstdio>
@@ -45,7 +46,22 @@ Error_t Free(void *DevPtr) {
}
Error_t Memcpy(void *Dst, const void *Src, size_t Size, MemcpyKind Kind) {
- ol_queue_handle_t Queue = ThreadState::getDefaultQueue();
+ ol_device_handle_t Device = nullptr;
+ StreamTy *DefaultStream = nullptr;
+ ol_queue_handle_t Queue = nullptr;
+
+ if (Kind != MemcpyHostToHost) {
+ Device = ThreadState::getDefaultDevice();
+ DefaultStream = ThreadState::getDefaultStream();
+ if (!Device || !DefaultStream)
+ return setLastError(ErrorInvalidDevice);
+
+ ol_result_t Result = waitOnBlockingStreams(DefaultStream, Device);
+ if (Result != OL_SUCCESS)
+ return convertAndSetLastError(Result);
+
+ Queue = DefaultStream->Queue;
+ }
ol_result_t Result;
switch (Kind) {
@@ -55,21 +71,17 @@ Error_t Memcpy(void *Dst, const void *Src, size_t Size, MemcpyKind Kind) {
break;
}
case MemcpyHostToDevice: {
- ol_device_handle_t Device = ThreadState::getDefaultDevice();
ol_device_handle_t Host = RuntimeState::getHostDevice();
Result = olMemcpy(Queue, Dst, Device, const_cast<void *>(Src), Host, Size);
break;
}
case MemcpyDeviceToHost: {
- ol_device_handle_t Device = ThreadState::getDefaultDevice();
ol_device_handle_t Host = RuntimeState::getHostDevice();
Result = olMemcpy(Queue, Dst, Host, const_cast<void *>(Src), Device, Size);
break;
}
case MemcpyDeviceToDevice: {
- ol_device_handle_t Device = ThreadState::getDefaultDevice();
-
Result =
olMemcpy(Queue, Dst, Device, const_cast<void *>(Src), Device, Size);
break;
@@ -81,6 +93,9 @@ Error_t Memcpy(void *Dst, const void *Src, size_t Size, MemcpyKind Kind) {
if (Result != OL_SUCCESS)
return convertAndSetLastError(Result);
+ if (!Queue)
+ return convertAndSetLastError(Result);
+
Result = olSyncQueue(Queue);
return convertAndSetLastError(Result);
}
diff --git a/offload/test/offloading/CUDA/blocking_stream_semantics.cu b/offload/test/offloading/CUDA/blocking_stream_semantics.cu
new file mode 100644
index 0000000000000..83aa3383571f6
--- /dev/null
+++ b/offload/test/offloading/CUDA/blocking_stream_semantics.cu
@@ -0,0 +1,131 @@
+// clang-format off
+// RUN: %clang++ %flags -foffload-via-llvm --offload-arch=native %s -o %t
+// RUN: %t | %fcheck-generic --check-prefix=LEGACY
+// RUN: %clang++ %flags -foffload-via-llvm --offload-arch=native %s -o %t -fopenmp
+// RUN: %t | %fcheck-generic --check-prefix=LEGACY
+// RUN: %clang++ %flags -foffload-via-llvm --offload-arch=native %s -o %t -fgpu-default-stream=per-thread
+// RUN: %t | %fcheck-generic --check-prefix=PERTHREAD
+// clang-format on
+
+// UNSUPPORTED: aarch64-unknown-linux-gnu
+// UNSUPPORTED: x86_64-unknown-linux-gnu
+// UNSUPPORTED: nvptx64-nvidia-cuda-LTO
+// UNSUPPORTED: amdgcn-amd-amdhsa-LTO
+// UNSUPPORTED: amdgpu-amd-amdhsa-LTO
+// UNSUPPORTED: intelgpu
+
+#include <stdio.h>
+
+__global__ void delayedSetValue(int *Out, int Value) {
+ volatile unsigned long long Delay = 0;
+ for (unsigned I = 0; I < 1000000; ++I)
+ Delay += I;
+ if (Delay)
+ *Out = Value;
+}
+
+__global__ void copyValue(int *In, int *Out) { *Out = *In; }
+
+__global__ void waitThenSetValue(int *Gate, int *Out, int Value) {
+ volatile int *VolatileGate = Gate;
+ for (unsigned I = 0; I < 100000000 && *VolatileGate == 0; ++I)
+ ;
+ *Out = Value;
+}
+
+__global__ void copyValueAndRelease(int *In, int *Out, int *Gate) {
+ *Out = *In;
+ volatile int *VolatileGate = Gate;
+ *VolatileGate = 1;
+}
+
+int main(int argc, char **argv) {
+ cudaStream_t BlockingStream = nullptr;
+ if (cudaStreamCreateWithFlags(&BlockingStream, cudaStreamDefault) !=
+ cudaSuccess)
+ return 1;
+ cudaStream_t NonBlockingStream = nullptr;
+ if (cudaStreamCreateWithFlags(&NonBlockingStream, cudaStreamNonBlocking) !=
+ cudaSuccess)
+ return 1;
+
+ int *In = nullptr;
+ int *Out = nullptr;
+ int *Gate = nullptr;
+ if (cudaMalloc(&In, sizeof(int)) != cudaSuccess)
+ return 1;
+ if (cudaMalloc(&Out, sizeof(int)) != cudaSuccess)
+ return 1;
+ if (cudaMalloc(&Gate, sizeof(int)) != cudaSuccess)
+ return 1;
+
+ int Initial = 0;
+ int Result = 0;
+ if (cudaMemcpy(In, &Initial, sizeof(int), cudaMemcpyHostToDevice) !=
+ cudaSuccess)
+ return 1;
+ if (cudaMemcpy(Out, &Initial, sizeof(int), cudaMemcpyHostToDevice) !=
+ cudaSuccess)
+ return 1;
+
+ delayedSetValue<<<1, 1, 0, BlockingStream>>>(In, 99);
+ copyValue<<<1, 1>>>(In, Out);
+ if (cudaMemcpy(&Result, Out, sizeof(int), cudaMemcpyDeviceToHost) !=
+ cudaSuccess)
+ return 1;
+
+ printf("legacy default waited on blocking stream: %d\n", Result);
+ // LEGACY: legacy default waited on blocking stream: 99
+ // PERTHREAD: legacy default waited on blocking stream: 0
+
+ Result = 0;
+ if (cudaMemcpy(Out, &Initial, sizeof(int), cudaMemcpyHostToDevice) !=
+ cudaSuccess)
+ return 1;
+
+ delayedSetValue<<<1, 1>>>(In, 123);
+ copyValue<<<1, 1, 0, BlockingStream>>>(In, Out);
+ if (cudaStreamSynchronize(BlockingStream) != cudaSuccess)
+ return 1;
+ if (cudaMemcpy(&Result, Out, sizeof(int), cudaMemcpyDeviceToHost) !=
+ cudaSuccess)
+ return 1;
+
+ printf("blocking stream waited on legacy default: %d\n", Result);
+ // LEGACY: blocking stream waited on legacy default: 123
+ // PERTHREAD: blocking stream waited on legacy default: 99
+
+ Result = 0;
+ if (cudaMemcpy(In, &Initial, sizeof(int), cudaMemcpyHostToDevice) !=
+ cudaSuccess)
+ return 1;
+ if (cudaMemcpy(Out, &Initial, sizeof(int), cudaMemcpyHostToDevice) !=
+ cudaSuccess)
+ return 1;
+ if (cudaMemcpy(Gate, &Initial, sizeof(int), cudaMemcpyHostToDevice) !=
+ cudaSuccess)
+ return 1;
+
+ waitThenSetValue<<<1, 1>>>(Gate, In, 321);
+ copyValueAndRelease<<<1, 1, 0, NonBlockingStream>>>(In, Out, Gate);
+ if (cudaStreamSynchronize(NonBlockingStream) != cudaSuccess)
+ return 1;
+ if (cudaMemcpy(&Result, Out, sizeof(int), cudaMemcpyDeviceToHost) !=
+ cudaSuccess)
+ return 1;
+
+ printf("nonblocking stream did not wait on legacy default: %d\n", Result);
+ // LEGACY: nonblocking stream did not wait on legacy default: 0
+ // PERTHREAD: nonblocking stream did not wait on legacy default: 0
+
+ if (cudaStreamDestroy(BlockingStream) != cudaSuccess)
+ return 1;
+ if (cudaStreamDestroy(NonBlockingStream) != cudaSuccess)
+ return 1;
+ if (cudaFree(In) != cudaSuccess)
+ return 1;
+ if (cudaFree(Out) != cudaSuccess)
+ return 1;
+ if (cudaFree(Gate) != cudaSuccess)
+ return 1;
+}
diff --git a/offload/test/offloading/CUDA/stream_api.cu b/offload/test/offloading/CUDA/stream_api.cu
index c5b1caaa5315c..0e1c328cc5f1b 100644
--- a/offload/test/offloading/CUDA/stream_api.cu
+++ b/offload/test/offloading/CUDA/stream_api.cu
@@ -70,8 +70,6 @@ int main(int argc, char **argv) {
if (cudaStreamSynchronize(Stream) != cudaSuccess)
return 1;
- if (cudaDeviceSynchronize() != cudaSuccess)
- return 1;
if (cudaMemcpy(&StreamResult, StreamPtr, sizeof(int),
cudaMemcpyDeviceToHost) != cudaSuccess)
return 1;
@@ -86,6 +84,10 @@ int main(int argc, char **argv) {
if (cudaStreamDestroy(Stream) != cudaSuccess)
return 1;
+ if (cudaStreamDestroy(BlockingStream) != cudaSuccess)
+ return 1;
+ if (cudaStreamDestroy(NonBlockingStream) != cudaSuccess)
+ return 1;
print_error("destroyed stream destroy", cudaStreamDestroy(Stream));
// CHECK: destroyed stream destroy value: 4
// CHECK: destroyed stream destroy name: cudaErrorInvalidResourceHandle
diff --git a/offload/test/offloading/HIP/blocking_stream_semantics.hip b/offload/test/offloading/HIP/blocking_stream_semantics.hip
new file mode 100644
index 0000000000000..8c28c7b1b2ee8
--- /dev/null
+++ b/offload/test/offloading/HIP/blocking_stream_semantics.hip
@@ -0,0 +1,125 @@
+// clang-format off
+// RUN: %clang++ %flags -foffload-via-llvm --offload-arch=native %s -o %t
+// RUN: %t | %fcheck-generic --check-prefix=LEGACY
+// RUN: %clang++ %flags -foffload-via-llvm --offload-arch=native %s -o %t -fopenmp
+// RUN: %t | %fcheck-generic --check-prefix=LEGACY
+// RUN: %clang++ %flags -foffload-via-llvm --offload-arch=native %s -o %t -fgpu-default-stream=per-thread
+// RUN: %t | %fcheck-generic --check-prefix=PERTHREAD
+// clang-format on
+
+// UNSUPPORTED: aarch64-unknown-linux-gnu
+// UNSUPPORTED: x86_64-unknown-linux-gnu
+// UNSUPPORTED: nvptx64-nvidia-cuda-LTO
+// UNSUPPORTED: amdgcn-amd-amdhsa-LTO
+// UNSUPPORTED: amdgpu-amd-amdhsa-LTO
+// UNSUPPORTED: intelgpu
+
+#include <stdio.h>
+
+__global__ void delayedSetValue(int *Out, int Value) {
+ volatile unsigned long long Delay = 0;
+ for (unsigned I = 0; I < 1000000; ++I)
+ Delay += I;
+ if (Delay)
+ *Out = Value;
+}
+
+__global__ void copyValue(int *In, int *Out) { *Out = *In; }
+
+__global__ void waitThenSetValue(int *Gate, int *Out, int Value) {
+ volatile int *VolatileGate = Gate;
+ for (unsigned I = 0; I < 100000000 && *VolatileGate == 0; ++I)
+ ;
+ *Out = Value;
+}
+
+__global__ void copyValueAndRelease(int *In, int *Out, int *Gate) {
+ *Out = *In;
+ volatile int *VolatileGate = Gate;
+ *VolatileGate = 1;
+}
+
+int main(int argc, char **argv) {
+ hipStream_t BlockingStream = nullptr;
+ if (hipStreamCreateWithFlags(&BlockingStream, hipStreamDefault) != hipSuccess)
+ return 1;
+ hipStream_t NonBlockingStream = nullptr;
+ if (hipStreamCreateWithFlags(&NonBlockingStream, hipStreamNonBlocking) !=
+ hipSuccess)
+ return 1;
+
+ int *In = nullptr;
+ int *Out = nullptr;
+ int *Gate = nullptr;
+ if (hipMalloc(&In, sizeof(int)) != hipSuccess)
+ return 1;
+ if (hipMalloc(&Out, sizeof(int)) != hipSuccess)
+ return 1;
+ if (hipMalloc(&Gate, sizeof(int)) != hipSuccess)
+ return 1;
+
+ int Initial = 0;
+ int Result = 0;
+ if (hipMemcpy(In, &Initial, sizeof(int), hipMemcpyHostToDevice) != hipSuccess)
+ return 1;
+ if (hipMemcpy(Out, &Initial, sizeof(int), hipMemcpyHostToDevice) !=
+ hipSuccess)
+ return 1;
+
+ delayedSetValue<<<1, 1, 0, BlockingStream>>>(In, 99);
+ copyValue<<<1, 1>>>(In, Out);
+ if (hipMemcpy(&Result, Out, sizeof(int), hipMemcpyDeviceToHost) != hipSuccess)
+ return 1;
+
+ printf("legacy default waited on blocking stream: %d\n", Result);
+ // LEGACY: legacy default waited on blocking stream: 99
+ // PERTHREAD: legacy default waited on blocking stream: 0
+
+ Result = 0;
+ if (hipMemcpy(Out, &Initial, sizeof(int), hipMemcpyHostToDevice) !=
+ hipSuccess)
+ return 1;
+
+ delayedSetValue<<<1, 1>>>(In, 123);
+ copyValue<<<1, 1, 0, BlockingStream>>>(In, Out);
+ if (hipStreamSynchronize(BlockingStream) != hipSuccess)
+ return 1;
+ if (hipMemcpy(&Result, Out, sizeof(int), hipMemcpyDeviceToHost) != hipSuccess)
+ return 1;
+
+ printf("blocking stream waited on legacy default: %d\n", Result);
+ // LEGACY: blocking stream waited on legacy default: 123
+ // PERTHREAD: blocking stream waited on legacy default: 99
+
+ Result = 0;
+ if (hipMemcpy(In, &Initial, sizeof(int), hipMemcpyHostToDevice) != hipSuccess)
+ return 1;
+ if (hipMemcpy(Out, &Initial, sizeof(int), hipMemcpyHostToDevice) !=
+ hipSuccess)
+ return 1;
+ if (hipMemcpy(Gate, &Initial, sizeof(int), hipMemcpyHostToDevice) !=
+ hipSuccess)
+ return 1;
+
+ waitThenSetValue<<<1, 1>>>(Gate, In, 321);
+ copyValueAndRelease<<<1, 1, 0, NonBlockingStream>>>(In, Out, Gate);
+ if (hipStreamSynchronize(NonBlockingStream) != hipSuccess)
+ return 1;
+ if (hipMemcpy(&Result, Out, sizeof(int), hipMemcpyDeviceToHost) != hipSuccess)
+ return 1;
+
+ printf("nonblocking stream did not wait on legacy default: %d\n", Result);
+ // LEGACY: nonblocking stream did not wait on legacy default: 0
+ // PERTHREAD: nonblocking stream did not wait on legacy default: 0
+
+ if (hipStreamDestroy(BlockingStream) != hipSuccess)
+ return 1;
+ if (hipStreamDestroy(NonBlockingStream) != hipSuccess)
+ return 1;
+ if (hipFree(In) != hipSuccess)
+ return 1;
+ if (hipFree(Out) != hipSuccess)
+ return 1;
+ if (hipFree(Gate) != hipSuccess)
+ return 1;
+}
diff --git a/offload/test/offloading/HIP/stream_api.hip b/offload/test/offloading/HIP/stream_api.hip
index fbfca230ee697..3460a6a0c351c 100644
--- a/offload/test/offloading/HIP/stream_api.hip
+++ b/offload/test/offloading/HIP/stream_api.hip
@@ -69,8 +69,6 @@ int main(int argc, char **argv) {
if (hipStreamSynchronize(Stream) != hipSuccess)
return 1;
- if (hipDeviceSynchronize() != hipSuccess)
- return 1;
if (hipMemcpy(&StreamResult, StreamPtr, sizeof(int), hipMemcpyDeviceToHost) !=
hipSuccess)
return 1;
@@ -85,6 +83,10 @@ int main(int argc, char **argv) {
if (hipStreamDestroy(Stream) != hipSuccess)
return 1;
+ if (hipStreamDestroy(BlockingStream) != hipSuccess)
+ return 1;
+ if (hipStreamDestroy(NonBlockingStream) != hipSuccess)
+ return 1;
print_error("destroyed stream destroy", hipStreamDestroy(Stream));
// CHECK: destroyed stream destroy value: 4
// CHECK: destroyed stream destroy name: hipErrorInvalidResourceHandle
More information about the llvm-branch-commits
mailing list