1 | /* |
2 | * Copyright 2019 WebAssembly Community Group participants |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #ifndef wasm_features_h |
18 | #define wasm_features_h |
19 | |
20 | #include <stdint.h> |
21 | #include <string> |
22 | |
23 | #include "compiler-support.h" |
24 | #include "support/utilities.h" |
25 | |
26 | namespace wasm { |
27 | |
28 | struct FeatureSet { |
29 | enum Feature : uint32_t { |
30 | None = 0, |
31 | Atomics = 1 << 0, |
32 | MutableGlobals = 1 << 1, |
33 | TruncSat = 1 << 2, |
34 | SIMD = 1 << 3, |
35 | BulkMemory = 1 << 4, |
36 | SignExt = 1 << 5, |
37 | ExceptionHandling = 1 << 6, |
38 | TailCall = 1 << 7, |
39 | ReferenceTypes = 1 << 8, |
40 | Multivalue = 1 << 9, |
41 | GC = 1 << 10, |
42 | Memory64 = 1 << 11, |
43 | // TODO: Remove this feature when the wasm spec stabilizes. |
44 | GCNNLocals = 1 << 12, |
45 | RelaxedSIMD = 1 << 13, |
46 | ExtendedConst = 1 << 14, |
47 | Strings = 1 << 15, |
48 | MultiMemories = 1 << 16, |
49 | MVP = None, |
50 | // Keep in sync with llvm default features: |
51 | // https://github.com/llvm/llvm-project/blob/c7576cb89d6c95f03968076e902d3adfd1996577/clang/lib/Basic/Targets/WebAssembly.cpp#L150-L153 |
52 | Default = SignExt | MutableGlobals, |
53 | // GCNNLocals are opt-in: merely asking for "All" does not apply them. To |
54 | // get all possible values use AllPossible. See setAll() below for more |
55 | // details. |
56 | All = ((1 << 17) - 1) & ~GCNNLocals, |
57 | AllPossible = (1 << 17) - 1, |
58 | }; |
59 | |
60 | static std::string toString(Feature f) { |
61 | switch (f) { |
62 | case Atomics: |
63 | return "threads" ; |
64 | case MutableGlobals: |
65 | return "mutable-globals" ; |
66 | case TruncSat: |
67 | return "nontrapping-float-to-int" ; |
68 | case SIMD: |
69 | return "simd" ; |
70 | case BulkMemory: |
71 | return "bulk-memory" ; |
72 | case SignExt: |
73 | return "sign-ext" ; |
74 | case ExceptionHandling: |
75 | return "exception-handling" ; |
76 | case TailCall: |
77 | return "tail-call" ; |
78 | case ReferenceTypes: |
79 | return "reference-types" ; |
80 | case Multivalue: |
81 | return "multivalue" ; |
82 | case GC: |
83 | return "gc" ; |
84 | case Memory64: |
85 | return "memory64" ; |
86 | case GCNNLocals: |
87 | return "gc-nn-locals" ; |
88 | case RelaxedSIMD: |
89 | return "relaxed-simd" ; |
90 | case ExtendedConst: |
91 | return "extended-const" ; |
92 | case Strings: |
93 | return "strings" ; |
94 | case MultiMemories: |
95 | return "multi-memories" ; |
96 | default: |
97 | WASM_UNREACHABLE("unexpected feature" ); |
98 | } |
99 | } |
100 | |
101 | std::string toString() const { |
102 | std::string ret; |
103 | uint32_t x = 1; |
104 | while (x & Feature::AllPossible) { |
105 | if (features & x) { |
106 | if (!ret.empty()) { |
107 | ret += ", " ; |
108 | } |
109 | ret += toString(Feature(x)); |
110 | } |
111 | x <<= 1; |
112 | } |
113 | return ret; |
114 | } |
115 | |
116 | FeatureSet() : features(None) {} |
117 | FeatureSet(uint32_t features) : features(features) {} |
118 | operator uint32_t() const { return features; } |
119 | |
120 | bool isMVP() const { return features == MVP; } |
121 | bool has(FeatureSet f) const { return (features & f) == f.features; } |
122 | bool hasAtomics() const { return (features & Atomics) != 0; } |
123 | bool hasMutableGlobals() const { return (features & MutableGlobals) != 0; } |
124 | bool hasTruncSat() const { return (features & TruncSat) != 0; } |
125 | bool hasSIMD() const { return (features & SIMD) != 0; } |
126 | bool hasBulkMemory() const { return (features & BulkMemory) != 0; } |
127 | bool hasSignExt() const { return (features & SignExt) != 0; } |
128 | bool hasExceptionHandling() const { |
129 | return (features & ExceptionHandling) != 0; |
130 | } |
131 | bool hasTailCall() const { return (features & TailCall) != 0; } |
132 | bool hasReferenceTypes() const { return (features & ReferenceTypes) != 0; } |
133 | bool hasMultivalue() const { return (features & Multivalue) != 0; } |
134 | bool hasGC() const { return (features & GC) != 0; } |
135 | bool hasMemory64() const { return (features & Memory64) != 0; } |
136 | bool hasGCNNLocals() const { return (features & GCNNLocals) != 0; } |
137 | bool hasRelaxedSIMD() const { return (features & RelaxedSIMD) != 0; } |
138 | bool hasExtendedConst() const { return (features & ExtendedConst) != 0; } |
139 | bool hasStrings() const { return (features & Strings) != 0; } |
140 | bool hasMultiMemories() const { return (features & MultiMemories) != 0; } |
141 | bool hasAll() const { return (features & AllPossible) != 0; } |
142 | |
143 | void set(FeatureSet f, bool v = true) { |
144 | features = v ? (features | f) : (features & ~f); |
145 | } |
146 | void setAtomics(bool v = true) { set(f: Atomics, v); } |
147 | void setMutableGlobals(bool v = true) { set(f: MutableGlobals, v); } |
148 | void setTruncSat(bool v = true) { set(f: TruncSat, v); } |
149 | void setSIMD(bool v = true) { set(f: SIMD, v); } |
150 | void setBulkMemory(bool v = true) { set(f: BulkMemory, v); } |
151 | void setSignExt(bool v = true) { set(f: SignExt, v); } |
152 | void setExceptionHandling(bool v = true) { set(f: ExceptionHandling, v); } |
153 | void setTailCall(bool v = true) { set(f: TailCall, v); } |
154 | void setReferenceTypes(bool v = true) { set(f: ReferenceTypes, v); } |
155 | void setMultivalue(bool v = true) { set(f: Multivalue, v); } |
156 | void setGC(bool v = true) { set(f: GC, v); } |
157 | void setMemory64(bool v = true) { set(f: Memory64, v); } |
158 | void setGCNNLocals(bool v = true) { set(f: GCNNLocals, v); } |
159 | void setRelaxedSIMD(bool v = true) { set(f: RelaxedSIMD, v); } |
160 | void setExtendedConst(bool v = true) { set(f: ExtendedConst, v); } |
161 | void setStrings(bool v = true) { set(f: Strings, v); } |
162 | void setMultiMemories(bool v = true) { set(f: MultiMemories, v); } |
163 | void setMVP() { features = MVP; } |
164 | void setAll() { |
165 | // Do not set GCNNLocals, which forces the user to opt in to that feature |
166 | // explicitly. That is, wasm-opt -all will enable GC but *not* enable |
167 | // non-nullable locals. To get them, do wasm-opt -all --enable-gc-nn-locals |
168 | // FIXME: When the wasm spec stabilizes, this feature will go away, as the |
169 | // non-nullable locals experiment will either become the standard, |
170 | // or it will go away. |
171 | // Leave the old GCNNLocals value unmodified. This makes things like |
172 | // --enable-gc-nn-locals -all work (that is, if we enable the feature, |
173 | // then -all does not disable it; it simply does not enable it by itself). |
174 | auto oldGCNNLocals = hasGCNNLocals(); |
175 | features = AllPossible; |
176 | setGCNNLocals(oldGCNNLocals); |
177 | } |
178 | |
179 | void enable(const FeatureSet& other) { features |= other.features; } |
180 | void disable(const FeatureSet& other) { |
181 | features = features & ~other.features & AllPossible; |
182 | } |
183 | |
184 | template<typename F> void iterFeatures(F f) const { |
185 | for (uint32_t feature = MVP + 1; feature < AllPossible; feature <<= 1) { |
186 | if (has(f: feature)) { |
187 | f(static_cast<Feature>(feature)); |
188 | } |
189 | } |
190 | } |
191 | |
192 | bool operator<=(const FeatureSet& other) const { |
193 | return !(features & ~other.features); |
194 | } |
195 | |
196 | bool operator==(const FeatureSet& other) const { |
197 | return *this <= other && other <= *this; |
198 | } |
199 | |
200 | bool operator!=(const FeatureSet& other) const { return !(*this == other); } |
201 | |
202 | FeatureSet& operator|=(const FeatureSet& other) { |
203 | features |= other.features; |
204 | return *this; |
205 | } |
206 | |
207 | uint32_t features; |
208 | }; |
209 | |
210 | } // namespace wasm |
211 | |
212 | #endif // wasm_features_h |
213 | |