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