blob: a3c8712723a7a518d035f392f921d57e2459f1f2 [file] [edit]
//===-- State.h - Kernel language persistent state ------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_OFFLOAD_LANGUAGES_KERNEL_INCLUDE_STATE_H
#define LLVM_OFFLOAD_LANGUAGES_KERNEL_INCLUDE_STATE_H
#include "OffloadAPI.h"
#include "Stream.h"
#include "Types.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdint>
#include <mutex>
#define CHECK_FATAL(ResultExpr, ...) \
do { \
ol_result_t CheckFatalResult = (ResultExpr); \
if (CheckFatalResult && CheckFatalResult->Code) { \
llvm::errs() << __VA_ARGS__; \
if (CheckFatalResult->Details) \
llvm::errs() << ": " << CheckFatalResult->Details; \
llvm::errs() << '\n'; \
abort(); \
} \
} while (false)
#define FATAL_UNIMPLEMENTED(...) \
do { \
llvm::errs() << __VA_ARGS__ << '\n'; \
abort(); \
} while (false)
namespace llvm {
namespace offload {
static constexpr unsigned AssumedDeviceCount = 8;
static constexpr unsigned AssumedStreamCount = 8;
/// Opaque host-side key used to identify a registered kernel.
///
/// This is the address emitted in the offload entry table for the kernel
using KernelIDTy = const void *;
/// Per-thread state used by the language runtime entry points.
///
/// Tracks the current thread's default device, optional per-thread queue,
/// last-error code, and pending kernel launch configuration.
struct ThreadStateTy {
~ThreadStateTy();
/// Return the thread-local state for the current host thread.
static ThreadStateTy &get();
/// Return the default queue for the current host thread.
ol_queue_handle_t getDefaultQueue();
/// Return the default stream for the current host thread and device.
StreamTy *getDefaultStream();
/// Return the thread-local default device, or the first discovered device.
ol_device_handle_t getDefaultDevice();
/// Return the thread-local default device and write its number to \p
/// DeviceNo.
ol_device_handle_t getDevice(int *DeviceNo);
/// Set the thread-local default device by device number.
///
/// \returns the selected device, or nullptr if \p DeviceNo is invalid.
ol_device_handle_t setDefaultDevice(int DeviceNo);
/// Return the last language-runtime error code for this thread.
uint32_t getLastError();
/// Set the last language-runtime error code for this thread.
uint32_t setLastError(uint32_t Error);
/// Return the pending kernel launch configuration for this thread.
CallConfigurationTy &getCallConfiguration();
private:
StreamTy *getOrCreateDefaultStream(ol_device_handle_t Device);
void destroyDefaultStreams();
int DefaultDevice = 0;
uint32_t LastError = 0;
DenseMap<ol_device_handle_t, StreamTy *> PerThreadDeviceDefaultStreamMap;
CallConfigurationTy CC = {};
ThreadStateTy();
};
/// Process-wide state shared by CUDA and HIP language entry points.
///
/// Owns the discovered devices, host device, process default queue, and maps
/// from registered binaries and kernels to liboffload handles.
struct StateTy {
~StateTy();
friend struct ThreadStateTy;
/// Return the process-wide state singleton.
static StateTy &get();
/// Return the process-wide state singleton if it has been initialized.
static StateTy *tryGet();
/// Return the host device discovered during runtime initialization.
ol_device_handle_t getHostDevice();
/// Return the shared context that owns the discovered non-host devices.
ol_context_handle_t getContext();
/// Return the number of non-host devices available to kernel languages.
int getDeviceCount();
/// Register \p Kernel for the host-side kernel identifier \p ID.
///
/// \p ID is the opaque kernel key emitted by Clang in the offload entry
/// table. It is later passed to the launch entry point to recover the
/// corresponding liboffload symbol handle.
void registerKernel(const void *ID, ol_symbol_handle_t Kernel);
/// Remove any registered kernel handle for the host-side kernel key \p ID.
void unregisterKernel(const void *ID);
/// Return the registered kernel handle for the host-side kernel key \p ID.
ol_symbol_handle_t getKernel(const void *ID);
/// Register \p Program for the binary image identifier \p ID.
///
/// \p ID is the device image start address from the offload binary
/// descriptor. It keys the loaded program so later function registration
/// can look up the program that owns each kernel symbol.
void registerProgram(const void *ID, ol_program_handle_t Program);
/// Remove and return the loaded program handle for binary image key \p ID.
ol_program_handle_t unregisterProgram(const void *ID);
/// Return the loaded program handle for binary image key \p ID.
ol_program_handle_t getProgram(const void *ID);
/// Return all streams currently known for \p Device.
SmallPtrSet<StreamTy *, 8> getDeviceStreams(ol_device_handle_t Device);
/// Return all explicitly created blocking streams for \p Device.
SmallPtrSet<StreamTy *, 8> getBlockingStreams(ol_device_handle_t Device);
/// Return true if \p Device has an existing legacy default stream.
bool hasLegacyDefaultStream(ol_device_handle_t Device);
/// Create a stream for \p Device and register it with the process state.
ol_result_t createStream(ol_device_handle_t Device, QueueKind Kind,
StreamTy **Stream);
/// Destroy \p Stream after removing it from the process state.
ol_result_t destroyStream(StreamTy *Stream);
/// Return true if \p Stream is currently registered with the process state.
bool isStreamRegistered(StreamTy *Stream);
private:
static bool addDevices(ol_device_handle_t Device, void *Payload);
ArrayRef<ol_device_handle_t> getDevices() const;
void addDevice(ol_device_handle_t Device);
void setHostDevice(ol_device_handle_t Device);
StreamTy *getOrCreateDefaultStream(ol_device_handle_t Device);
void destroyDefaultStreams();
/// Inserts the Stream into the DeviceStreamsMap and the
/// DeviceBlockingStreamsMap
void addStream(StreamTy *Stream);
/// Removes the Stream from DeviceStreamsMap and DeviceBlockingStreamsMap
void removeStream(StreamTy *Stream);
void destroyRegisteredStreams();
void destroyRegisteredPrograms();
DenseMap<const void *, ol_program_handle_t> BinaryRegisterMap;
DenseMap<KernelIDTy, ol_symbol_handle_t> KernelMap;
SmallVector<ol_device_handle_t, AssumedDeviceCount> Devices;
DenseMap<ol_device_handle_t, StreamTy *> DeviceDefaultStreamsMap;
DenseMap<ol_device_handle_t, SmallPtrSet<StreamTy *, AssumedStreamCount>>
DeviceStreamsMap;
DenseMap<ol_device_handle_t, SmallPtrSet<StreamTy *, AssumedStreamCount>>
DeviceBlockingStreamsMap;
ol_context_handle_t Context = nullptr;
ol_device_handle_t HostDevice = nullptr;
std::mutex DeviceDefaultStreamsMapLock;
std::mutex DeviceStreamsMapLock;
std::mutex DeviceBlockingStreamsMapLock;
StateTy();
};
} // namespace offload
} // namespace llvm
#endif // LLVM_OFFLOAD_LANGUAGES_KERNEL_INCLUDE_STATE_H