1//===--- WebAssembly.cpp - Implement WebAssembly target feature support ---===//
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// This file implements WebAssembly TargetInfo objects.
10//
11//===----------------------------------------------------------------------===//
12
13#include "WebAssembly.h"
14#include "Targets.h"
15#include "clang/Basic/Builtins.h"
16#include "clang/Basic/Diagnostic.h"
17#include "clang/Basic/TargetBuiltins.h"
18#include "llvm/ADT/StringSwitch.h"
19
20using namespace clang;
21using namespace clang::targets;
22
23const Builtin::Info WebAssemblyTargetInfo::BuiltinInfo[] = {
24#define BUILTIN(ID, TYPE, ATTRS)                                               \
25  {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
26#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE)                               \
27  {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
28#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER)                                    \
29  {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr},
30#include "clang/Basic/BuiltinsWebAssembly.def"
31};
32
33static constexpr llvm::StringLiteral ValidCPUNames[] = {
34    {"mvp"}, {"bleeding-edge"}, {"generic"}};
35
36StringRef WebAssemblyTargetInfo::getABI() const { return ABI; }
37
38bool WebAssemblyTargetInfo::setABI(const std::string &Name) {
39  if (Name != "mvp" && Name != "experimental-mv")
40    return false;
41
42  ABI = Name;
43  return true;
44}
45
46bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const {
47  return llvm::StringSwitch<bool>(Feature)
48      .Case("simd128", SIMDLevel >= SIMD128)
49      .Case("unimplemented-simd128", SIMDLevel >= UnimplementedSIMD128)
50      .Case("nontrapping-fptoint", HasNontrappingFPToInt)
51      .Case("sign-ext", HasSignExt)
52      .Case("exception-handling", HasExceptionHandling)
53      .Case("bulk-memory", HasBulkMemory)
54      .Case("atomics", HasAtomics)
55      .Case("mutable-globals", HasMutableGlobals)
56      .Case("multivalue", HasMultivalue)
57      .Case("tail-call", HasTailCall)
58      .Case("reference-types", HasReferenceTypes)
59      .Default(false);
60}
61
62bool WebAssemblyTargetInfo::isValidCPUName(StringRef Name) const {
63  return llvm::find(ValidCPUNames, Name) != std::end(ValidCPUNames);
64}
65
66void WebAssemblyTargetInfo::fillValidCPUList(
67    SmallVectorImpl<StringRef> &Values) const {
68  Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames));
69}
70
71void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts,
72                                             MacroBuilder &Builder) const {
73  defineCPUMacros(Builder, "wasm", /*Tuning=*/false);
74  if (SIMDLevel >= SIMD128)
75    Builder.defineMacro("__wasm_simd128__");
76  if (SIMDLevel >= UnimplementedSIMD128)
77    Builder.defineMacro("__wasm_unimplemented_simd128__");
78  if (HasNontrappingFPToInt)
79    Builder.defineMacro("__wasm_nontrapping_fptoint__");
80  if (HasSignExt)
81    Builder.defineMacro("__wasm_sign_ext__");
82  if (HasExceptionHandling)
83    Builder.defineMacro("__wasm_exception_handling__");
84  if (HasBulkMemory)
85    Builder.defineMacro("__wasm_bulk_memory__");
86  if (HasAtomics)
87    Builder.defineMacro("__wasm_atomics__");
88  if (HasMutableGlobals)
89    Builder.defineMacro("__wasm_mutable_globals__");
90  if (HasMultivalue)
91    Builder.defineMacro("__wasm_multivalue__");
92  if (HasTailCall)
93    Builder.defineMacro("__wasm_tail_call__");
94  if (HasReferenceTypes)
95    Builder.defineMacro("__wasm_reference_types__");
96}
97
98void WebAssemblyTargetInfo::setSIMDLevel(llvm::StringMap<bool> &Features,
99                                         SIMDEnum Level, bool Enabled) {
100  if (Enabled) {
101    switch (Level) {
102    case UnimplementedSIMD128:
103      Features["unimplemented-simd128"] = true;
104      LLVM_FALLTHROUGH;
105    case SIMD128:
106      Features["simd128"] = true;
107      LLVM_FALLTHROUGH;
108    case NoSIMD:
109      break;
110    }
111    return;
112  }
113
114  switch (Level) {
115  case NoSIMD:
116  case SIMD128:
117    Features["simd128"] = false;
118    LLVM_FALLTHROUGH;
119  case UnimplementedSIMD128:
120    Features["unimplemented-simd128"] = false;
121    break;
122  }
123}
124
125void WebAssemblyTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
126                                              StringRef Name,
127                                              bool Enabled) const {
128  if (Name == "simd128")
129    setSIMDLevel(Features, SIMD128, Enabled);
130  else if (Name == "unimplemented-simd128")
131    setSIMDLevel(Features, UnimplementedSIMD128, Enabled);
132  else
133    Features[Name] = Enabled;
134}
135
136bool WebAssemblyTargetInfo::initFeatureMap(
137    llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
138    const std::vector<std::string> &FeaturesVec) const {
139  if (CPU == "bleeding-edge") {
140    Features["nontrapping-fptoint"] = true;
141    Features["sign-ext"] = true;
142    Features["bulk-memory"] = true;
143    Features["atomics"] = true;
144    Features["mutable-globals"] = true;
145    Features["tail-call"] = true;
146    setSIMDLevel(Features, SIMD128, true);
147  }
148
149  return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
150}
151
152bool WebAssemblyTargetInfo::handleTargetFeatures(
153    std::vector<std::string> &Features, DiagnosticsEngine &Diags) {
154  for (const auto &Feature : Features) {
155    if (Feature == "+simd128") {
156      SIMDLevel = std::max(SIMDLevel, SIMD128);
157      continue;
158    }
159    if (Feature == "-simd128") {
160      SIMDLevel = std::min(SIMDLevel, SIMDEnum(SIMD128 - 1));
161      continue;
162    }
163    if (Feature == "+unimplemented-simd128") {
164      SIMDLevel = std::max(SIMDLevel, SIMDEnum(UnimplementedSIMD128));
165      continue;
166    }
167    if (Feature == "-unimplemented-simd128") {
168      SIMDLevel = std::min(SIMDLevel, SIMDEnum(UnimplementedSIMD128 - 1));
169      continue;
170    }
171    if (Feature == "+nontrapping-fptoint") {
172      HasNontrappingFPToInt = true;
173      continue;
174    }
175    if (Feature == "-nontrapping-fptoint") {
176      HasNontrappingFPToInt = false;
177      continue;
178    }
179    if (Feature == "+sign-ext") {
180      HasSignExt = true;
181      continue;
182    }
183    if (Feature == "-sign-ext") {
184      HasSignExt = false;
185      continue;
186    }
187    if (Feature == "+exception-handling") {
188      HasExceptionHandling = true;
189      continue;
190    }
191    if (Feature == "-exception-handling") {
192      HasExceptionHandling = false;
193      continue;
194    }
195    if (Feature == "+bulk-memory") {
196      HasBulkMemory = true;
197      continue;
198    }
199    if (Feature == "-bulk-memory") {
200      HasBulkMemory = false;
201      continue;
202    }
203    if (Feature == "+atomics") {
204      HasAtomics = true;
205      continue;
206    }
207    if (Feature == "-atomics") {
208      HasAtomics = false;
209      continue;
210    }
211    if (Feature == "+mutable-globals") {
212      HasMutableGlobals = true;
213      continue;
214    }
215    if (Feature == "-mutable-globals") {
216      HasMutableGlobals = false;
217      continue;
218    }
219    if (Feature == "+multivalue") {
220      HasMultivalue = true;
221      continue;
222    }
223    if (Feature == "-multivalue") {
224      HasMultivalue = false;
225      continue;
226    }
227    if (Feature == "+tail-call") {
228      HasTailCall = true;
229      continue;
230    }
231    if (Feature == "-tail-call") {
232      HasTailCall = false;
233      continue;
234    }
235    if (Feature == "+reference-types") {
236      HasReferenceTypes = true;
237      continue;
238    }
239    if (Feature == "-reference-types") {
240      HasReferenceTypes = false;
241      continue;
242    }
243
244    Diags.Report(diag::err_opt_not_valid_with_opt)
245        << Feature << "-target-feature";
246    return false;
247  }
248  return true;
249}
250
251ArrayRef<Builtin::Info> WebAssemblyTargetInfo::getTargetBuiltins() const {
252  return llvm::makeArrayRef(BuiltinInfo, clang::WebAssembly::LastTSBuiltin -
253                                             Builtin::FirstTSBuiltin);
254}
255
256void WebAssembly32TargetInfo::getTargetDefines(const LangOptions &Opts,
257                                               MacroBuilder &Builder) const {
258  WebAssemblyTargetInfo::getTargetDefines(Opts, Builder);
259  defineCPUMacros(Builder, "wasm32", /*Tuning=*/false);
260}
261
262void WebAssembly64TargetInfo::getTargetDefines(const LangOptions &Opts,
263                                               MacroBuilder &Builder) const {
264  WebAssemblyTargetInfo::getTargetDefines(Opts, Builder);
265  defineCPUMacros(Builder, "wasm64", /*Tuning=*/false);
266}
267