//===--- SyncScope.h - Atomic synchronization scopes ------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \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 { OpenCLWorkGroup, OpenCLDevice, OpenCLAllSVMDevices, OpenCLSubGroup, Last = OpenCLSubGroup }; inline llvm::StringRef getAsString(SyncScope S) { switch (S) { 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 }; /// 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.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); } }; inline std::unique_ptr AtomicScopeModel::create(AtomicScopeModelKind K) { switch (K) { case AtomicScopeModelKind::None: return std::unique_ptr{}; case AtomicScopeModelKind::OpenCL: return llvm::make_unique(); } llvm_unreachable("Invalid atomic scope model kind"); } } #endif