#pragma once #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif //===--- SyncScope.h - Atomic synchronization scopes ------------*- C++ -*-===// // // 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 // //===----------------------------------------------------------------------===// /// /// \file /// Provides definitions for the atomic synchronization scopes. /// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_BASIC_SYNCSCOPE_H #define LLVM_CLANG_BASIC_SYNCSCOPE_H #include "clang/Basic/LangOptions.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include namespace clang { /// Defines synch scope values used internally by clang. /// /// The enum values start from 0 and are contiguous. They are mainly used for /// enumerating all supported synch scope values and mapping them to LLVM /// synch scopes. Their numerical values may be different from the corresponding /// synch scope enums used in source languages. /// /// In atomic builtin and expressions, language-specific synch scope enums are /// used. Currently only OpenCL memory scope enums are supported and assumed /// to be used by all languages. However, in the future, other languages may /// define their own set of synch scope enums. The language-specific synch scope /// values are represented by class AtomicScopeModel and its derived classes. /// /// To add a new enum value: /// Add the enum value to enum class SyncScope. /// Update enum value Last if necessary. /// Update getAsString. /// enum class SyncScope { HIPSingleThread, HIPWavefront, HIPWorkgroup, HIPAgent, HIPSystem, OpenCLWorkGroup, OpenCLDevice, OpenCLAllSVMDevices, OpenCLSubGroup, Last = OpenCLSubGroup }; inline llvm::StringRef getAsString(SyncScope S) { switch (S) { case SyncScope::HIPSingleThread: return "hip_singlethread"; case SyncScope::HIPWavefront: return "hip_wavefront"; case SyncScope::HIPWorkgroup: return "hip_workgroup"; case SyncScope::HIPAgent: return "hip_agent"; case SyncScope::HIPSystem: return "hip_system"; case SyncScope::OpenCLWorkGroup: return "opencl_workgroup"; case SyncScope::OpenCLDevice: return "opencl_device"; case SyncScope::OpenCLAllSVMDevices: return "opencl_allsvmdevices"; case SyncScope::OpenCLSubGroup: return "opencl_subgroup"; } llvm_unreachable("Invalid synch scope"); } /// Defines the kind of atomic scope models. enum class AtomicScopeModelKind { None, OpenCL, HIP }; /// Defines the interface for synch scope model. class AtomicScopeModel { public: virtual ~AtomicScopeModel() {} /// Maps language specific synch scope values to internal /// SyncScope enum. virtual SyncScope map(unsigned S) const = 0; /// Check if the compile-time constant synch scope value /// is valid. virtual bool isValid(unsigned S) const = 0; /// Get all possible synch scope values that might be /// encountered at runtime for the current language. virtual ArrayRef getRuntimeValues() const = 0; /// If atomic builtin function is called with invalid /// synch scope value at runtime, it will fall back to a valid /// synch scope value returned by this function. virtual unsigned getFallBackValue() const = 0; /// Create an atomic scope model by AtomicScopeModelKind. /// \return an empty std::unique_ptr for AtomicScopeModelKind::None. static std::unique_ptr create(AtomicScopeModelKind K); }; /// Defines the synch scope model for OpenCL. class AtomicScopeOpenCLModel : public AtomicScopeModel { public: /// The enum values match the pre-defined macros /// __OPENCL_MEMORY_SCOPE_*, which are used to define memory_scope_* /// enums in opencl-c-base.h. enum ID { WorkGroup = 1, Device = 2, AllSVMDevices = 3, SubGroup = 4, Last = SubGroup }; AtomicScopeOpenCLModel() {} SyncScope map(unsigned S) const override { switch (static_cast(S)) { case WorkGroup: return SyncScope::OpenCLWorkGroup; case Device: return SyncScope::OpenCLDevice; case AllSVMDevices: return SyncScope::OpenCLAllSVMDevices; case SubGroup: return SyncScope::OpenCLSubGroup; } llvm_unreachable("Invalid language synch scope value"); } bool isValid(unsigned S) const override { return S >= static_cast(WorkGroup) && S <= static_cast(Last); } ArrayRef getRuntimeValues() const override { static_assert(Last == SubGroup, "Does not include all synch scopes"); static const unsigned Scopes[] = { static_cast(WorkGroup), static_cast(Device), static_cast(AllSVMDevices), static_cast(SubGroup)}; return llvm::makeArrayRef(Scopes); } unsigned getFallBackValue() const override { return static_cast(AllSVMDevices); } }; /// Defines the synch scope model for HIP. class AtomicScopeHIPModel : public AtomicScopeModel { public: /// The enum values match the pre-defined macros /// __HIP_MEMORY_SCOPE_*, which are used to define memory_scope_* /// enums in hip-c.h. enum ID { SingleThread = 1, Wavefront = 2, Workgroup = 3, Agent = 4, System = 5, Last = System }; AtomicScopeHIPModel() {} SyncScope map(unsigned S) const override { switch (static_cast(S)) { case SingleThread: return SyncScope::HIPSingleThread; case Wavefront: return SyncScope::HIPWavefront; case Workgroup: return SyncScope::HIPWorkgroup; case Agent: return SyncScope::HIPAgent; case System: return SyncScope::HIPSystem; } llvm_unreachable("Invalid language synch scope value"); } bool isValid(unsigned S) const override { return S >= static_cast(SingleThread) && S <= static_cast(Last); } ArrayRef getRuntimeValues() const override { static_assert(Last == System, "Does not include all synch scopes"); static const unsigned Scopes[] = { static_cast(SingleThread), static_cast(Wavefront), static_cast(Workgroup), static_cast(Agent), static_cast(System)}; return llvm::makeArrayRef(Scopes); } unsigned getFallBackValue() const override { return static_cast(System); } }; inline std::unique_ptr AtomicScopeModel::create(AtomicScopeModelKind K) { switch (K) { case AtomicScopeModelKind::None: return std::unique_ptr{}; case AtomicScopeModelKind::OpenCL: return std::make_unique(); case AtomicScopeModelKind::HIP: return std::make_unique(); } llvm_unreachable("Invalid atomic scope model kind"); } } // namespace clang #endif #ifdef __GNUC__ #pragma GCC diagnostic pop #endif