| //===-- 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 |