reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
//===--- 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 <memory>

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<unsigned> 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<AtomicScopeModel> 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<ID>(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<unsigned>(WorkGroup) &&
           S <= static_cast<unsigned>(Last);
  }

  ArrayRef<unsigned> getRuntimeValues() const override {
    static_assert(Last == SubGroup, "Does not include all synch scopes");
    static const unsigned Scopes[] = {
        static_cast<unsigned>(WorkGroup), static_cast<unsigned>(Device),
        static_cast<unsigned>(AllSVMDevices), static_cast<unsigned>(SubGroup)};
    return llvm::makeArrayRef(Scopes);
  }

  unsigned getFallBackValue() const override {
    return static_cast<unsigned>(AllSVMDevices);
  }
};

inline std::unique_ptr<AtomicScopeModel>
AtomicScopeModel::create(AtomicScopeModelKind K) {
  switch (K) {
  case AtomicScopeModelKind::None:
    return std::unique_ptr<AtomicScopeModel>{};
  case AtomicScopeModelKind::OpenCL:
    return std::make_unique<AtomicScopeOpenCLModel>();
  }
  llvm_unreachable("Invalid atomic scope model kind");
}
}

#endif