1 | /* |
2 | * Copyright (C) 2015-2016 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 "B3FenceValue.h" |
39 | #include "B3MemoryValue.h" |
40 | #include "B3PatchpointValue.h" |
41 | #include "B3PhiChildren.h" |
42 | #include "B3Procedure.h" |
43 | #include "B3SlotBaseValue.h" |
44 | #include "B3SwitchValue.h" |
45 | #include "B3UpsilonValue.h" |
46 | #include "B3Value.h" |
47 | #include "B3VariableValue.h" |
48 | #include "B3WasmAddressValue.h" |
49 | #include "B3WasmBoundsCheckValue.h" |
50 | #include <wtf/GraphNodeWorklist.h> |
51 | |
52 | namespace JSC { namespace B3 { |
53 | |
54 | #define DISPATCH_ON_KIND(MACRO) \ |
55 | switch (kind().opcode()) { \ |
56 | case FramePointer: \ |
57 | case Nop: \ |
58 | case Phi: \ |
59 | case Jump: \ |
60 | case Oops: \ |
61 | case EntrySwitch: \ |
62 | case Return: \ |
63 | case Identity: \ |
64 | case Opaque: \ |
65 | case Neg: \ |
66 | case Clz: \ |
67 | case Abs: \ |
68 | case Ceil: \ |
69 | case Floor: \ |
70 | case Sqrt: \ |
71 | case SExt8: \ |
72 | case SExt16: \ |
73 | case Trunc: \ |
74 | case SExt32: \ |
75 | case ZExt32: \ |
76 | case FloatToDouble: \ |
77 | case IToD: \ |
78 | case DoubleToFloat: \ |
79 | case IToF: \ |
80 | case BitwiseCast: \ |
81 | case Branch: \ |
82 | case Depend: \ |
83 | case Add: \ |
84 | case Sub: \ |
85 | case Mul: \ |
86 | case Div: \ |
87 | case UDiv: \ |
88 | case Mod: \ |
89 | case UMod: \ |
90 | case BitAnd: \ |
91 | case BitOr: \ |
92 | case BitXor: \ |
93 | case Shl: \ |
94 | case SShr: \ |
95 | case ZShr: \ |
96 | case RotR: \ |
97 | case RotL: \ |
98 | case Equal: \ |
99 | case NotEqual: \ |
100 | case LessThan: \ |
101 | case GreaterThan: \ |
102 | case LessEqual: \ |
103 | case GreaterEqual: \ |
104 | case Above: \ |
105 | case Below: \ |
106 | case AboveEqual: \ |
107 | case BelowEqual: \ |
108 | case EqualOrUnordered: \ |
109 | case Select: \ |
110 | return MACRO(Value); \ |
111 | case ArgumentReg: \ |
112 | return MACRO(ArgumentRegValue); \ |
113 | case Const32: \ |
114 | return MACRO(Const32Value); \ |
115 | case Const64: \ |
116 | return MACRO(Const64Value); \ |
117 | case ConstFloat: \ |
118 | return MACRO(ConstFloatValue); \ |
119 | case ConstDouble: \ |
120 | return MACRO(ConstDoubleValue); \ |
121 | case Fence: \ |
122 | return MACRO(FenceValue); \ |
123 | case SlotBase: \ |
124 | return MACRO(SlotBaseValue); \ |
125 | case Get: \ |
126 | case Set: \ |
127 | return MACRO(VariableValue); \ |
128 | case Load8Z: \ |
129 | case Load8S: \ |
130 | case Load16Z: \ |
131 | case Load16S: \ |
132 | case Load: \ |
133 | case Store8: \ |
134 | case Store16: \ |
135 | case Store: \ |
136 | return MACRO(MemoryValue); \ |
137 | case Switch: \ |
138 | return MACRO(SwitchValue); \ |
139 | case Upsilon: \ |
140 | return MACRO(UpsilonValue); \ |
141 | case WasmAddress: \ |
142 | return MACRO(WasmAddressValue); \ |
143 | case WasmBoundsCheck: \ |
144 | return MACRO(WasmBoundsCheckValue); \ |
145 | case AtomicXchgAdd: \ |
146 | case AtomicXchgAnd: \ |
147 | case AtomicXchgOr: \ |
148 | case AtomicXchgSub: \ |
149 | case AtomicXchgXor: \ |
150 | case AtomicXchg: \ |
151 | case AtomicWeakCAS: \ |
152 | case AtomicStrongCAS: \ |
153 | return MACRO(AtomicValue); \ |
154 | case CCall: \ |
155 | return MACRO(CCallValue); \ |
156 | case Check: \ |
157 | case CheckAdd: \ |
158 | case CheckSub: \ |
159 | case CheckMul: \ |
160 | return MACRO(CheckValue); \ |
161 | case Patchpoint: \ |
162 | return MACRO(PatchpointValue); \ |
163 | default: \ |
164 | RELEASE_ASSERT_NOT_REACHED(); \ |
165 | } |
166 | |
167 | ALWAYS_INLINE size_t Value::adjacencyListOffset() const |
168 | { |
169 | #define VALUE_TYPE_SIZE(ValueType) sizeof(ValueType) |
170 | DISPATCH_ON_KIND(VALUE_TYPE_SIZE); |
171 | #undef VALUE_TYPE_SIZE |
172 | } |
173 | |
174 | ALWAYS_INLINE Value* Value::cloneImpl() const |
175 | { |
176 | #define VALUE_TYPE_CLONE(ValueType) allocate<ValueType>(*static_cast<const ValueType*>(this)) |
177 | DISPATCH_ON_KIND(VALUE_TYPE_CLONE); |
178 | #undef VALUE_TYPE_CLONE |
179 | } |
180 | |
181 | template<typename BottomProvider> |
182 | void Value::replaceWithBottom(const BottomProvider& bottomProvider) |
183 | { |
184 | if (m_type == Void) { |
185 | replaceWithNop(); |
186 | return; |
187 | } |
188 | |
189 | if (isConstant()) |
190 | return; |
191 | |
192 | replaceWithIdentity(bottomProvider(m_origin, m_type)); |
193 | } |
194 | |
195 | template<typename T> |
196 | inline T* Value::as() |
197 | { |
198 | if (T::accepts(kind())) |
199 | return static_cast<T*>(this); |
200 | return nullptr; |
201 | } |
202 | |
203 | template<typename T> |
204 | inline const T* Value::as() const |
205 | { |
206 | return const_cast<Value*>(this)->as<T>(); |
207 | } |
208 | |
209 | inline bool Value::isConstant() const |
210 | { |
211 | return B3::isConstant(opcode()); |
212 | } |
213 | |
214 | inline bool Value::isInteger() const |
215 | { |
216 | return type() == Int32 || type() == Int64; |
217 | } |
218 | |
219 | inline bool Value::hasInt32() const |
220 | { |
221 | return !!as<Const32Value>(); |
222 | } |
223 | |
224 | inline int32_t Value::asInt32() const |
225 | { |
226 | return as<Const32Value>()->value(); |
227 | } |
228 | |
229 | inline bool Value::isInt32(int32_t value) const |
230 | { |
231 | return hasInt32() && asInt32() == value; |
232 | } |
233 | |
234 | inline bool Value::hasInt64() const |
235 | { |
236 | return !!as<Const64Value>(); |
237 | } |
238 | |
239 | inline int64_t Value::asInt64() const |
240 | { |
241 | return as<Const64Value>()->value(); |
242 | } |
243 | |
244 | inline bool Value::isInt64(int64_t value) const |
245 | { |
246 | return hasInt64() && asInt64() == value; |
247 | } |
248 | |
249 | inline bool Value::hasInt() const |
250 | { |
251 | return hasInt32() || hasInt64(); |
252 | } |
253 | |
254 | inline int64_t Value::asInt() const |
255 | { |
256 | return hasInt32() ? asInt32() : asInt64(); |
257 | } |
258 | |
259 | inline bool Value::isInt(int64_t value) const |
260 | { |
261 | return hasInt() && asInt() == value; |
262 | } |
263 | |
264 | inline bool Value::hasIntPtr() const |
265 | { |
266 | if (is64Bit()) |
267 | return hasInt64(); |
268 | return hasInt32(); |
269 | } |
270 | |
271 | inline intptr_t Value::asIntPtr() const |
272 | { |
273 | if (is64Bit()) |
274 | return asInt64(); |
275 | return asInt32(); |
276 | } |
277 | |
278 | inline bool Value::isIntPtr(intptr_t value) const |
279 | { |
280 | return hasIntPtr() && asIntPtr() == value; |
281 | } |
282 | |
283 | inline bool Value::hasDouble() const |
284 | { |
285 | return !!as<ConstDoubleValue>(); |
286 | } |
287 | |
288 | inline double Value::asDouble() const |
289 | { |
290 | return as<ConstDoubleValue>()->value(); |
291 | } |
292 | |
293 | inline bool Value::isEqualToDouble(double value) const |
294 | { |
295 | return hasDouble() && asDouble() == value; |
296 | } |
297 | |
298 | inline bool Value::hasFloat() const |
299 | { |
300 | return !!as<ConstFloatValue>(); |
301 | } |
302 | |
303 | inline float Value::asFloat() const |
304 | { |
305 | return as<ConstFloatValue>()->value(); |
306 | } |
307 | |
308 | inline bool Value::hasNumber() const |
309 | { |
310 | return hasInt() || hasDouble() || hasFloat(); |
311 | } |
312 | |
313 | inline bool Value::isNegativeZero() const |
314 | { |
315 | if (hasDouble()) { |
316 | double value = asDouble(); |
317 | return !value && std::signbit(value); |
318 | } |
319 | if (hasFloat()) { |
320 | float value = asFloat(); |
321 | return !value && std::signbit(value); |
322 | } |
323 | return false; |
324 | } |
325 | |
326 | template<typename T> |
327 | inline bool Value::isRepresentableAs() const |
328 | { |
329 | switch (opcode()) { |
330 | case Const32: |
331 | return B3::isRepresentableAs<T>(asInt32()); |
332 | case Const64: |
333 | return B3::isRepresentableAs<T>(asInt64()); |
334 | case ConstDouble: |
335 | return B3::isRepresentableAs<T>(asDouble()); |
336 | case ConstFloat: |
337 | return B3::isRepresentableAs<T>(asFloat()); |
338 | default: |
339 | return false; |
340 | } |
341 | } |
342 | |
343 | template<typename T> |
344 | inline T Value::asNumber() const |
345 | { |
346 | switch (opcode()) { |
347 | case Const32: |
348 | return static_cast<T>(asInt32()); |
349 | case Const64: |
350 | return static_cast<T>(asInt64()); |
351 | case ConstDouble: |
352 | return static_cast<T>(asDouble()); |
353 | case ConstFloat: |
354 | return static_cast<T>(asFloat()); |
355 | default: |
356 | return T(); |
357 | } |
358 | } |
359 | |
360 | template<typename Functor> |
361 | void Value::walk(const Functor& functor, PhiChildren* phiChildren) |
362 | { |
363 | GraphNodeWorklist<Value*> worklist; |
364 | worklist.push(this); |
365 | while (Value* value = worklist.pop()) { |
366 | WalkStatus status = functor(value); |
367 | switch (status) { |
368 | case Continue: |
369 | if (value->opcode() == Phi) { |
370 | if (phiChildren) |
371 | worklist.pushAll(phiChildren->at(value).values()); |
372 | } else |
373 | worklist.pushAll(value->children()); |
374 | break; |
375 | case IgnoreChildren: |
376 | break; |
377 | case Stop: |
378 | return; |
379 | } |
380 | } |
381 | } |
382 | |
383 | } } // namespace JSC::B3 |
384 | |
385 | #endif // ENABLE(B3_JIT) |
386 | |