1 | /* |
2 | * Copyright (C) 2015-2019 Apple Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #pragma once |
27 | |
28 | #if ENABLE(B3_JIT) |
29 | |
30 | #include "B3ArgumentRegValue.h" |
31 | #include "B3AtomicValue.h" |
32 | #include "B3CCallValue.h" |
33 | #include "B3CheckValue.h" |
34 | #include "B3Const32Value.h" |
35 | #include "B3Const64Value.h" |
36 | #include "B3ConstDoubleValue.h" |
37 | #include "B3ConstFloatValue.h" |
38 | #include "B3ExtractValue.h" |
39 | #include "B3FenceValue.h" |
40 | #include "B3MemoryValue.h" |
41 | #include "B3PatchpointValue.h" |
42 | #include "B3PhiChildren.h" |
43 | #include "B3Procedure.h" |
44 | #include "B3SlotBaseValue.h" |
45 | #include "B3SwitchValue.h" |
46 | #include "B3UpsilonValue.h" |
47 | #include "B3Value.h" |
48 | #include "B3VariableValue.h" |
49 | #include "B3WasmAddressValue.h" |
50 | #include "B3WasmBoundsCheckValue.h" |
51 | #include <wtf/GraphNodeWorklist.h> |
52 | |
53 | namespace JSC { namespace B3 { |
54 | |
55 | #define DISPATCH_ON_KIND(MACRO) \ |
56 | switch (kind().opcode()) { \ |
57 | case FramePointer: \ |
58 | case Nop: \ |
59 | case Phi: \ |
60 | case Jump: \ |
61 | case Oops: \ |
62 | case EntrySwitch: \ |
63 | case Return: \ |
64 | case Identity: \ |
65 | case Opaque: \ |
66 | case Neg: \ |
67 | case Clz: \ |
68 | case Abs: \ |
69 | case Ceil: \ |
70 | case Floor: \ |
71 | case Sqrt: \ |
72 | case SExt8: \ |
73 | case SExt16: \ |
74 | case Trunc: \ |
75 | case SExt32: \ |
76 | case ZExt32: \ |
77 | case FloatToDouble: \ |
78 | case IToD: \ |
79 | case DoubleToFloat: \ |
80 | case IToF: \ |
81 | case BitwiseCast: \ |
82 | case Branch: \ |
83 | case Depend: \ |
84 | case Add: \ |
85 | case Sub: \ |
86 | case Mul: \ |
87 | case Div: \ |
88 | case UDiv: \ |
89 | case Mod: \ |
90 | case UMod: \ |
91 | case BitAnd: \ |
92 | case BitOr: \ |
93 | case BitXor: \ |
94 | case Shl: \ |
95 | case SShr: \ |
96 | case ZShr: \ |
97 | case RotR: \ |
98 | case RotL: \ |
99 | case Equal: \ |
100 | case NotEqual: \ |
101 | case LessThan: \ |
102 | case GreaterThan: \ |
103 | case LessEqual: \ |
104 | case GreaterEqual: \ |
105 | case Above: \ |
106 | case Below: \ |
107 | case AboveEqual: \ |
108 | case BelowEqual: \ |
109 | case EqualOrUnordered: \ |
110 | case Select: \ |
111 | return MACRO(Value); \ |
112 | case ArgumentReg: \ |
113 | return MACRO(ArgumentRegValue); \ |
114 | case Const32: \ |
115 | return MACRO(Const32Value); \ |
116 | case Const64: \ |
117 | return MACRO(Const64Value); \ |
118 | case ConstFloat: \ |
119 | return MACRO(ConstFloatValue); \ |
120 | case ConstDouble: \ |
121 | return MACRO(ConstDoubleValue); \ |
122 | case Fence: \ |
123 | return MACRO(FenceValue); \ |
124 | case SlotBase: \ |
125 | return MACRO(SlotBaseValue); \ |
126 | case Get: \ |
127 | case Set: \ |
128 | return MACRO(VariableValue); \ |
129 | case Load8Z: \ |
130 | case Load8S: \ |
131 | case Load16Z: \ |
132 | case Load16S: \ |
133 | case Load: \ |
134 | case Store8: \ |
135 | case Store16: \ |
136 | case Store: \ |
137 | return MACRO(MemoryValue); \ |
138 | case Switch: \ |
139 | return MACRO(SwitchValue); \ |
140 | case Upsilon: \ |
141 | return MACRO(UpsilonValue); \ |
142 | case Extract: \ |
143 | return MACRO(ExtractValue); \ |
144 | case WasmAddress: \ |
145 | return MACRO(WasmAddressValue); \ |
146 | case WasmBoundsCheck: \ |
147 | return MACRO(WasmBoundsCheckValue); \ |
148 | case AtomicXchgAdd: \ |
149 | case AtomicXchgAnd: \ |
150 | case AtomicXchgOr: \ |
151 | case AtomicXchgSub: \ |
152 | case AtomicXchgXor: \ |
153 | case AtomicXchg: \ |
154 | case AtomicWeakCAS: \ |
155 | case AtomicStrongCAS: \ |
156 | return MACRO(AtomicValue); \ |
157 | case CCall: \ |
158 | return MACRO(CCallValue); \ |
159 | case Check: \ |
160 | case CheckAdd: \ |
161 | case CheckSub: \ |
162 | case CheckMul: \ |
163 | return MACRO(CheckValue); \ |
164 | case Patchpoint: \ |
165 | return MACRO(PatchpointValue); \ |
166 | default: \ |
167 | RELEASE_ASSERT_NOT_REACHED(); \ |
168 | } |
169 | |
170 | ALWAYS_INLINE size_t Value::adjacencyListOffset() const |
171 | { |
172 | #define VALUE_TYPE_SIZE(ValueType) sizeof(ValueType) |
173 | DISPATCH_ON_KIND(VALUE_TYPE_SIZE); |
174 | #undef VALUE_TYPE_SIZE |
175 | } |
176 | |
177 | ALWAYS_INLINE Value* Value::cloneImpl() const |
178 | { |
179 | #define VALUE_TYPE_CLONE(ValueType) allocate<ValueType>(*static_cast<const ValueType*>(this)) |
180 | DISPATCH_ON_KIND(VALUE_TYPE_CLONE); |
181 | #undef VALUE_TYPE_CLONE |
182 | } |
183 | |
184 | template<typename BottomProvider> |
185 | void Value::replaceWithBottom(const BottomProvider& bottomProvider) |
186 | { |
187 | if (m_type == Void) { |
188 | replaceWithNop(); |
189 | return; |
190 | } |
191 | |
192 | if (isConstant()) |
193 | return; |
194 | |
195 | replaceWithIdentity(bottomProvider(m_origin, m_type)); |
196 | } |
197 | |
198 | template<typename T> |
199 | inline T* Value::as() |
200 | { |
201 | if (T::accepts(kind())) |
202 | return static_cast<T*>(this); |
203 | return nullptr; |
204 | } |
205 | |
206 | template<typename T> |
207 | inline const T* Value::as() const |
208 | { |
209 | return const_cast<Value*>(this)->as<T>(); |
210 | } |
211 | |
212 | inline bool Value::isConstant() const |
213 | { |
214 | return B3::isConstant(opcode()); |
215 | } |
216 | |
217 | inline bool Value::isInteger() const |
218 | { |
219 | return type() == Int32 || type() == Int64; |
220 | } |
221 | |
222 | inline bool Value::hasInt32() const |
223 | { |
224 | return !!as<Const32Value>(); |
225 | } |
226 | |
227 | inline int32_t Value::asInt32() const |
228 | { |
229 | return as<Const32Value>()->value(); |
230 | } |
231 | |
232 | inline bool Value::isInt32(int32_t value) const |
233 | { |
234 | return hasInt32() && asInt32() == value; |
235 | } |
236 | |
237 | inline bool Value::hasInt64() const |
238 | { |
239 | return !!as<Const64Value>(); |
240 | } |
241 | |
242 | inline int64_t Value::asInt64() const |
243 | { |
244 | return as<Const64Value>()->value(); |
245 | } |
246 | |
247 | inline bool Value::isInt64(int64_t value) const |
248 | { |
249 | return hasInt64() && asInt64() == value; |
250 | } |
251 | |
252 | inline bool Value::hasInt() const |
253 | { |
254 | return hasInt32() || hasInt64(); |
255 | } |
256 | |
257 | inline int64_t Value::asInt() const |
258 | { |
259 | return hasInt32() ? asInt32() : asInt64(); |
260 | } |
261 | |
262 | inline bool Value::isInt(int64_t value) const |
263 | { |
264 | return hasInt() && asInt() == value; |
265 | } |
266 | |
267 | inline bool Value::hasIntPtr() const |
268 | { |
269 | if (is64Bit()) |
270 | return hasInt64(); |
271 | return hasInt32(); |
272 | } |
273 | |
274 | inline intptr_t Value::asIntPtr() const |
275 | { |
276 | if (is64Bit()) |
277 | return asInt64(); |
278 | return asInt32(); |
279 | } |
280 | |
281 | inline bool Value::isIntPtr(intptr_t value) const |
282 | { |
283 | return hasIntPtr() && asIntPtr() == value; |
284 | } |
285 | |
286 | inline bool Value::hasDouble() const |
287 | { |
288 | return !!as<ConstDoubleValue>(); |
289 | } |
290 | |
291 | inline double Value::asDouble() const |
292 | { |
293 | return as<ConstDoubleValue>()->value(); |
294 | } |
295 | |
296 | inline bool Value::isEqualToDouble(double value) const |
297 | { |
298 | return hasDouble() && asDouble() == value; |
299 | } |
300 | |
301 | inline bool Value::hasFloat() const |
302 | { |
303 | return !!as<ConstFloatValue>(); |
304 | } |
305 | |
306 | inline float Value::asFloat() const |
307 | { |
308 | return as<ConstFloatValue>()->value(); |
309 | } |
310 | |
311 | inline bool Value::hasNumber() const |
312 | { |
313 | return hasInt() || hasDouble() || hasFloat(); |
314 | } |
315 | |
316 | inline bool Value::isNegativeZero() const |
317 | { |
318 | if (hasDouble()) { |
319 | double value = asDouble(); |
320 | return !value && std::signbit(value); |
321 | } |
322 | if (hasFloat()) { |
323 | float value = asFloat(); |
324 | return !value && std::signbit(value); |
325 | } |
326 | return false; |
327 | } |
328 | |
329 | template<typename T> |
330 | inline bool Value::isRepresentableAs() const |
331 | { |
332 | switch (opcode()) { |
333 | case Const32: |
334 | return B3::isRepresentableAs<T>(asInt32()); |
335 | case Const64: |
336 | return B3::isRepresentableAs<T>(asInt64()); |
337 | case ConstDouble: |
338 | return B3::isRepresentableAs<T>(asDouble()); |
339 | case ConstFloat: |
340 | return B3::isRepresentableAs<T>(asFloat()); |
341 | default: |
342 | return false; |
343 | } |
344 | } |
345 | |
346 | template<typename T> |
347 | inline T Value::asNumber() const |
348 | { |
349 | switch (opcode()) { |
350 | case Const32: |
351 | return static_cast<T>(asInt32()); |
352 | case Const64: |
353 | return static_cast<T>(asInt64()); |
354 | case ConstDouble: |
355 | return static_cast<T>(asDouble()); |
356 | case ConstFloat: |
357 | return static_cast<T>(asFloat()); |
358 | default: |
359 | return T(); |
360 | } |
361 | } |
362 | |
363 | template<typename Functor> |
364 | void Value::walk(const Functor& functor, PhiChildren* phiChildren) |
365 | { |
366 | GraphNodeWorklist<Value*> worklist; |
367 | worklist.push(this); |
368 | while (Value* value = worklist.pop()) { |
369 | WalkStatus status = functor(value); |
370 | switch (status) { |
371 | case Continue: |
372 | if (value->opcode() == Phi) { |
373 | if (phiChildren) |
374 | worklist.pushAll(phiChildren->at(value).values()); |
375 | } else |
376 | worklist.pushAll(value->children()); |
377 | break; |
378 | case IgnoreChildren: |
379 | break; |
380 | case Stop: |
381 | return; |
382 | } |
383 | } |
384 | } |
385 | |
386 | } } // namespace JSC::B3 |
387 | |
388 | #endif // ENABLE(B3_JIT) |
389 | |