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