1//===--- SyncScope.h - Atomic synchronization scopes ------------*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9/// 10/// \file 11/// \brief Provides definitions for the atomic synchronization scopes. 12/// 13//===----------------------------------------------------------------------===// 14 15#ifndef LLVM_CLANG_BASIC_SYNCSCOPE_H 16#define LLVM_CLANG_BASIC_SYNCSCOPE_H 17 18#include "clang/Basic/LangOptions.h" 19#include "llvm/ADT/ArrayRef.h" 20#include "llvm/ADT/StringRef.h" 21#include <memory> 22 23namespace clang { 24 25/// \brief Defines synch scope values used internally by clang. 26/// 27/// The enum values start from 0 and are contiguous. They are mainly used for 28/// enumerating all supported synch scope values and mapping them to LLVM 29/// synch scopes. Their numerical values may be different from the corresponding 30/// synch scope enums used in source languages. 31/// 32/// In atomic builtin and expressions, language-specific synch scope enums are 33/// used. Currently only OpenCL memory scope enums are supported and assumed 34/// to be used by all languages. However, in the future, other languages may 35/// define their own set of synch scope enums. The language-specific synch scope 36/// values are represented by class AtomicScopeModel and its derived classes. 37/// 38/// To add a new enum value: 39/// Add the enum value to enum class SyncScope. 40/// Update enum value Last if necessary. 41/// Update getAsString. 42/// 43enum class SyncScope { 44 OpenCLWorkGroup, 45 OpenCLDevice, 46 OpenCLAllSVMDevices, 47 OpenCLSubGroup, 48 Last = OpenCLSubGroup 49}; 50 51inline llvm::StringRef getAsString(SyncScope S) { 52 switch (S) { 53 case SyncScope::OpenCLWorkGroup: 54 return "opencl_workgroup"; 55 case SyncScope::OpenCLDevice: 56 return "opencl_device"; 57 case SyncScope::OpenCLAllSVMDevices: 58 return "opencl_allsvmdevices"; 59 case SyncScope::OpenCLSubGroup: 60 return "opencl_subgroup"; 61 } 62 llvm_unreachable("Invalid synch scope"); 63} 64 65/// \brief Defines the kind of atomic scope models. 66enum class AtomicScopeModelKind { None, OpenCL }; 67 68/// \brief Defines the interface for synch scope model. 69class AtomicScopeModel { 70public: 71 virtual ~AtomicScopeModel() {} 72 /// \brief Maps language specific synch scope values to internal 73 /// SyncScope enum. 74 virtual SyncScope map(unsigned S) const = 0; 75 76 /// \brief Check if the compile-time constant synch scope value 77 /// is valid. 78 virtual bool isValid(unsigned S) const = 0; 79 80 /// \brief Get all possible synch scope values that might be 81 /// encountered at runtime for the current language. 82 virtual ArrayRef<unsigned> getRuntimeValues() const = 0; 83 84 /// \brief If atomic builtin function is called with invalid 85 /// synch scope value at runtime, it will fall back to a valid 86 /// synch scope value returned by this function. 87 virtual unsigned getFallBackValue() const = 0; 88 89 /// \brief Create an atomic scope model by AtomicScopeModelKind. 90 /// \return an empty std::unique_ptr for AtomicScopeModelKind::None. 91 static std::unique_ptr<AtomicScopeModel> create(AtomicScopeModelKind K); 92}; 93 94/// \brief Defines the synch scope model for OpenCL. 95class AtomicScopeOpenCLModel : public AtomicScopeModel { 96public: 97 /// The enum values match the pre-defined macros 98 /// __OPENCL_MEMORY_SCOPE_*, which are used to define memory_scope_* 99 /// enums in opencl-c.h. 100 enum ID { 101 WorkGroup = 1, 102 Device = 2, 103 AllSVMDevices = 3, 104 SubGroup = 4, 105 Last = SubGroup 106 }; 107 108 AtomicScopeOpenCLModel() {} 109 110 SyncScope map(unsigned S) const override { 111 switch (static_cast<ID>(S)) { 112 case WorkGroup: 113 return SyncScope::OpenCLWorkGroup; 114 case Device: 115 return SyncScope::OpenCLDevice; 116 case AllSVMDevices: 117 return SyncScope::OpenCLAllSVMDevices; 118 case SubGroup: 119 return SyncScope::OpenCLSubGroup; 120 } 121 llvm_unreachable("Invalid language synch scope value"); 122 } 123 124 bool isValid(unsigned S) const override { 125 return S >= static_cast<unsigned>(WorkGroup) && 126 S <= static_cast<unsigned>(Last); 127 } 128 129 ArrayRef<unsigned> getRuntimeValues() const override { 130 static_assert(Last == SubGroup, "Does not include all synch scopes"); 131 static const unsigned Scopes[] = { 132 static_cast<unsigned>(WorkGroup), static_cast<unsigned>(Device), 133 static_cast<unsigned>(AllSVMDevices), static_cast<unsigned>(SubGroup)}; 134 return llvm::makeArrayRef(Scopes); 135 } 136 137 unsigned getFallBackValue() const override { 138 return static_cast<unsigned>(AllSVMDevices); 139 } 140}; 141 142inline std::unique_ptr<AtomicScopeModel> 143AtomicScopeModel::create(AtomicScopeModelKind K) { 144 switch (K) { 145 case AtomicScopeModelKind::None: 146 return std::unique_ptr<AtomicScopeModel>{}; 147 case AtomicScopeModelKind::OpenCL: 148 return llvm::make_unique<AtomicScopeOpenCLModel>(); 149 } 150 llvm_unreachable("Invalid atomic scope model kind"); 151} 152} 153 154#endif 155