314 lines
9.3 KiB
C++
314 lines
9.3 KiB
C++
//===--- 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 sync scope values used internally by clang.
|
|
///
|
|
/// The enum values start from 0 and are contiguous. They are mainly used for
|
|
/// enumerating all supported sync scope values and mapping them to LLVM
|
|
/// sync scopes. Their numerical values may be different from the corresponding
|
|
/// sync scope enums used in source languages.
|
|
///
|
|
/// In atomic builtin and expressions, language-specific sync 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 sync scope enums. The language-specific sync 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 {
|
|
SystemScope,
|
|
DeviceScope,
|
|
WorkgroupScope,
|
|
ClusterScope,
|
|
WavefrontScope,
|
|
SingleScope,
|
|
HIPSingleThread,
|
|
HIPWavefront,
|
|
HIPWorkgroup,
|
|
HIPCluster,
|
|
HIPAgent,
|
|
HIPSystem,
|
|
OpenCLWorkGroup,
|
|
OpenCLDevice,
|
|
OpenCLAllSVMDevices,
|
|
OpenCLSubGroup,
|
|
Last = OpenCLSubGroup
|
|
};
|
|
|
|
inline llvm::StringRef getAsString(SyncScope S) {
|
|
switch (S) {
|
|
case SyncScope::SystemScope:
|
|
return "system_scope";
|
|
case SyncScope::DeviceScope:
|
|
return "device_scope";
|
|
case SyncScope::WorkgroupScope:
|
|
return "workgroup_scope";
|
|
case SyncScope::ClusterScope:
|
|
return "cluster_scope";
|
|
case SyncScope::WavefrontScope:
|
|
return "wavefront_scope";
|
|
case SyncScope::SingleScope:
|
|
return "single_scope";
|
|
case SyncScope::HIPSingleThread:
|
|
return "hip_singlethread";
|
|
case SyncScope::HIPWavefront:
|
|
return "hip_wavefront";
|
|
case SyncScope::HIPWorkgroup:
|
|
return "hip_workgroup";
|
|
case SyncScope::HIPCluster:
|
|
return "hip_cluster";
|
|
case SyncScope::HIPAgent:
|
|
return "hip_agent";
|
|
case SyncScope::HIPSystem:
|
|
return "hip_system";
|
|
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 sync scope");
|
|
}
|
|
|
|
/// Defines the kind of atomic scope models.
|
|
enum class AtomicScopeModelKind { None, OpenCL, HIP, Generic };
|
|
|
|
/// Defines the interface for sync scope model.
|
|
class AtomicScopeModel {
|
|
public:
|
|
virtual ~AtomicScopeModel() {}
|
|
/// Maps language specific sync scope values to internal
|
|
/// SyncScope enum.
|
|
virtual SyncScope map(unsigned S) const = 0;
|
|
|
|
/// Check if the compile-time constant sync scope value
|
|
/// is valid.
|
|
virtual bool isValid(unsigned S) const = 0;
|
|
|
|
/// Get all possible sync 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
|
|
/// sync scope value at runtime, it will fall back to a valid
|
|
/// sync 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 sync 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 sync 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 sync scopes");
|
|
static const unsigned Scopes[] = {
|
|
static_cast<unsigned>(WorkGroup), static_cast<unsigned>(Device),
|
|
static_cast<unsigned>(AllSVMDevices), static_cast<unsigned>(SubGroup)};
|
|
return llvm::ArrayRef(Scopes);
|
|
}
|
|
|
|
unsigned getFallBackValue() const override {
|
|
return static_cast<unsigned>(AllSVMDevices);
|
|
}
|
|
};
|
|
|
|
/// Defines the sync scope model for HIP.
|
|
class AtomicScopeHIPModel : public AtomicScopeModel {
|
|
public:
|
|
/// The enum values match the pre-defined macros
|
|
/// __HIP_MEMORY_SCOPE_*, which are used to define memory_scope_*
|
|
/// enums in hip-c.h.
|
|
/// These may be present in pch files or bitcode so preserve existing values
|
|
/// when adding a new ID.
|
|
enum ID {
|
|
SingleThread = 1,
|
|
Wavefront = 2,
|
|
Workgroup = 3,
|
|
Agent = 4,
|
|
System = 5,
|
|
Cluster = 6,
|
|
End,
|
|
Last = End - 1,
|
|
Count = Last
|
|
};
|
|
|
|
AtomicScopeHIPModel() {}
|
|
|
|
SyncScope map(unsigned S) const override {
|
|
switch (static_cast<ID>(S)) {
|
|
case SingleThread:
|
|
return SyncScope::HIPSingleThread;
|
|
case Wavefront:
|
|
return SyncScope::HIPWavefront;
|
|
case Workgroup:
|
|
return SyncScope::HIPWorkgroup;
|
|
case Cluster:
|
|
return SyncScope::HIPCluster;
|
|
case Agent:
|
|
return SyncScope::HIPAgent;
|
|
case System:
|
|
return SyncScope::HIPSystem;
|
|
case End:
|
|
break;
|
|
}
|
|
llvm_unreachable("Invalid language sync scope value");
|
|
}
|
|
|
|
bool isValid(unsigned S) const override {
|
|
return S >= static_cast<unsigned>(SingleThread) &&
|
|
S <= static_cast<unsigned>(Last);
|
|
}
|
|
|
|
ArrayRef<unsigned> getRuntimeValues() const override {
|
|
static const unsigned Scopes[] = {
|
|
static_cast<unsigned>(SingleThread), static_cast<unsigned>(Wavefront),
|
|
static_cast<unsigned>(Workgroup), static_cast<unsigned>(Cluster),
|
|
static_cast<unsigned>(System), static_cast<unsigned>(Agent)};
|
|
static_assert(sizeof(Scopes) / sizeof(Scopes[0]) == Count,
|
|
"Does not include all sync scopes");
|
|
return llvm::ArrayRef(Scopes);
|
|
}
|
|
|
|
unsigned getFallBackValue() const override {
|
|
return static_cast<unsigned>(System);
|
|
}
|
|
};
|
|
|
|
/// Defines the generic atomic scope model.
|
|
class AtomicScopeGenericModel : public AtomicScopeModel {
|
|
public:
|
|
/// The enum values match predefined built-in macros __MEMORY_SCOPE_*.
|
|
/// These may be present in pch files or bitcode so preserve existing values
|
|
/// when adding a new ID.
|
|
enum ID {
|
|
System = 0,
|
|
Device = 1,
|
|
Workgroup = 2,
|
|
Wavefront = 3,
|
|
Single = 4,
|
|
Cluster = 5,
|
|
Count,
|
|
Last = Count - 1
|
|
};
|
|
|
|
AtomicScopeGenericModel() = default;
|
|
|
|
SyncScope map(unsigned S) const override {
|
|
switch (static_cast<ID>(S)) {
|
|
case Device:
|
|
return SyncScope::DeviceScope;
|
|
case System:
|
|
return SyncScope::SystemScope;
|
|
case Workgroup:
|
|
return SyncScope::WorkgroupScope;
|
|
case Cluster:
|
|
return SyncScope::ClusterScope;
|
|
case Wavefront:
|
|
return SyncScope::WavefrontScope;
|
|
case Single:
|
|
return SyncScope::SingleScope;
|
|
case Count:
|
|
break;
|
|
}
|
|
llvm_unreachable("Invalid language sync scope value");
|
|
}
|
|
|
|
bool isValid(unsigned S) const override {
|
|
return S <= static_cast<unsigned>(Last);
|
|
}
|
|
|
|
ArrayRef<unsigned> getRuntimeValues() const override {
|
|
static const unsigned Scopes[] = {
|
|
static_cast<unsigned>(System), static_cast<unsigned>(Device),
|
|
static_cast<unsigned>(Workgroup), static_cast<unsigned>(Cluster),
|
|
static_cast<unsigned>(Wavefront), static_cast<unsigned>(Single)};
|
|
static_assert(sizeof(Scopes) / sizeof(Scopes[0]) == Count,
|
|
"Does not include all sync scopes");
|
|
return llvm::ArrayRef(Scopes);
|
|
}
|
|
|
|
unsigned getFallBackValue() const override {
|
|
return static_cast<unsigned>(System);
|
|
}
|
|
};
|
|
|
|
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>();
|
|
case AtomicScopeModelKind::HIP:
|
|
return std::make_unique<AtomicScopeHIPModel>();
|
|
case AtomicScopeModelKind::Generic:
|
|
return std::make_unique<AtomicScopeGenericModel>();
|
|
}
|
|
llvm_unreachable("Invalid atomic scope model kind");
|
|
}
|
|
} // namespace clang
|
|
|
|
#endif
|