1//===--- OpenCLOptions.cpp---------------------------------------*- 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#include "clang/Basic/OpenCLOptions.h"
10#include "clang/Basic/Diagnostic.h"
11#include "clang/Basic/TargetInfo.h"
12
13namespace clang {
14
15// First feature in a pair requires the second one to be supported.
16static const std::pair<StringRef, StringRef> DependentFeaturesList[] = {
17    {"__opencl_c_read_write_images", "__opencl_c_images"},
18    {"__opencl_c_3d_image_writes", "__opencl_c_images"},
19    {"__opencl_c_pipes", "__opencl_c_generic_address_space"},
20    {"__opencl_c_device_enqueue", "__opencl_c_generic_address_space"},
21    {"__opencl_c_device_enqueue", "__opencl_c_program_scope_global_variables"}};
22
23// Extensions and equivalent feature pairs.
24static const std::pair<StringRef, StringRef> FeatureExtensionMap[] = {
25    {"cl_khr_fp64", "__opencl_c_fp64"},
26    {"cl_khr_3d_image_writes", "__opencl_c_3d_image_writes"}};
27
28bool OpenCLOptions::isKnown(llvm::StringRef Ext) const {
29  return OptMap.find(Ext) != OptMap.end();
30}
31
32bool OpenCLOptions::isAvailableOption(llvm::StringRef Ext,
33                                      const LangOptions &LO) const {
34  if (!isKnown(Ext))
35    return false;
36
37  auto &OptInfo = OptMap.find(Ext)->getValue();
38  if (OptInfo.isCoreIn(LO) || OptInfo.isOptionalCoreIn(LO))
39    return isSupported(Ext, LO);
40
41  return isEnabled(Ext);
42}
43
44bool OpenCLOptions::isEnabled(llvm::StringRef Ext) const {
45  auto I = OptMap.find(Ext);
46  return I != OptMap.end() && I->getValue().Enabled;
47}
48
49bool OpenCLOptions::isWithPragma(llvm::StringRef Ext) const {
50  auto E = OptMap.find(Ext);
51  return E != OptMap.end() && E->second.WithPragma;
52}
53
54bool OpenCLOptions::isSupported(llvm::StringRef Ext,
55                                const LangOptions &LO) const {
56  auto I = OptMap.find(Ext);
57  return I != OptMap.end() && I->getValue().Supported &&
58         I->getValue().isAvailableIn(LO);
59}
60
61bool OpenCLOptions::isSupportedCore(llvm::StringRef Ext,
62                                    const LangOptions &LO) const {
63  auto I = OptMap.find(Ext);
64  return I != OptMap.end() && I->getValue().Supported &&
65         I->getValue().isCoreIn(LO);
66}
67
68bool OpenCLOptions::isSupportedOptionalCore(llvm::StringRef Ext,
69                                            const LangOptions &LO) const {
70  auto I = OptMap.find(Ext);
71  return I != OptMap.end() && I->getValue().Supported &&
72         I->getValue().isOptionalCoreIn(LO);
73}
74
75bool OpenCLOptions::isSupportedCoreOrOptionalCore(llvm::StringRef Ext,
76                                                  const LangOptions &LO) const {
77  return isSupportedCore(Ext, LO) || isSupportedOptionalCore(Ext, LO);
78}
79
80bool OpenCLOptions::isSupportedExtension(llvm::StringRef Ext,
81                                         const LangOptions &LO) const {
82  auto I = OptMap.find(Ext);
83  return I != OptMap.end() && I->getValue().Supported &&
84         I->getValue().isAvailableIn(LO) &&
85         !isSupportedCoreOrOptionalCore(Ext, LO);
86}
87
88void OpenCLOptions::enable(llvm::StringRef Ext, bool V) {
89  OptMap[Ext].Enabled = V;
90}
91
92void OpenCLOptions::acceptsPragma(llvm::StringRef Ext, bool V) {
93  OptMap[Ext].WithPragma = V;
94}
95
96void OpenCLOptions::support(llvm::StringRef Ext, bool V) {
97  assert(!Ext.empty() && "Extension is empty.");
98  assert(Ext[0] != '+' && Ext[0] != '-');
99  OptMap[Ext].Supported = V;
100}
101
102OpenCLOptions::OpenCLOptions() {
103#define OPENCL_GENERIC_EXTENSION(Ext, ...)                                     \
104  OptMap.insert_or_assign(#Ext, OpenCLOptionInfo{__VA_ARGS__});
105#include "clang/Basic/OpenCLExtensions.def"
106}
107
108void OpenCLOptions::addSupport(const llvm::StringMap<bool> &FeaturesMap,
109                               const LangOptions &Opts) {
110  for (const auto &F : FeaturesMap) {
111    const auto &Name = F.getKey();
112    if (F.getValue() && isKnown(Name) && OptMap[Name].isAvailableIn(Opts))
113      support(Name);
114  }
115}
116
117void OpenCLOptions::disableAll() {
118  for (auto &Opt : OptMap)
119    Opt.getValue().Enabled = false;
120}
121
122bool OpenCLOptions::diagnoseUnsupportedFeatureDependencies(
123    const TargetInfo &TI, DiagnosticsEngine &Diags) {
124  auto OpenCLFeaturesMap = TI.getSupportedOpenCLOpts();
125
126  bool IsValid = true;
127  for (auto &FeaturePair : DependentFeaturesList) {
128    auto Feature = FeaturePair.first;
129    auto Dep = FeaturePair.second;
130    if (TI.hasFeatureEnabled(OpenCLFeaturesMap, Feature) &&
131        !TI.hasFeatureEnabled(OpenCLFeaturesMap, Dep)) {
132      IsValid = false;
133      Diags.Report(diag::err_opencl_feature_requires) << Feature << Dep;
134    }
135  }
136  return IsValid;
137}
138
139bool OpenCLOptions::diagnoseFeatureExtensionDifferences(
140    const TargetInfo &TI, DiagnosticsEngine &Diags) {
141  auto OpenCLFeaturesMap = TI.getSupportedOpenCLOpts();
142
143  bool IsValid = true;
144  for (auto &ExtAndFeat : FeatureExtensionMap)
145    if (TI.hasFeatureEnabled(OpenCLFeaturesMap, ExtAndFeat.first) !=
146        TI.hasFeatureEnabled(OpenCLFeaturesMap, ExtAndFeat.second)) {
147      IsValid = false;
148      Diags.Report(diag::err_opencl_extension_and_feature_differs)
149          << ExtAndFeat.first << ExtAndFeat.second;
150    }
151  return IsValid;
152}
153
154} // end namespace clang
155