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
52namespace 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
167ALWAYS_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
174ALWAYS_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
181template<typename BottomProvider>
182void 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
195template<typename T>
196inline T* Value::as()
197{
198 if (T::accepts(kind()))
199 return static_cast<T*>(this);
200 return nullptr;
201}
202
203template<typename T>
204inline const T* Value::as() const
205{
206 return const_cast<Value*>(this)->as<T>();
207}
208
209inline bool Value::isConstant() const
210{
211 return B3::isConstant(opcode());
212}
213
214inline bool Value::isInteger() const
215{
216 return type() == Int32 || type() == Int64;
217}
218
219inline bool Value::hasInt32() const
220{
221 return !!as<Const32Value>();
222}
223
224inline int32_t Value::asInt32() const
225{
226 return as<Const32Value>()->value();
227}
228
229inline bool Value::isInt32(int32_t value) const
230{
231 return hasInt32() && asInt32() == value;
232}
233
234inline bool Value::hasInt64() const
235{
236 return !!as<Const64Value>();
237}
238
239inline int64_t Value::asInt64() const
240{
241 return as<Const64Value>()->value();
242}
243
244inline bool Value::isInt64(int64_t value) const
245{
246 return hasInt64() && asInt64() == value;
247}
248
249inline bool Value::hasInt() const
250{
251 return hasInt32() || hasInt64();
252}
253
254inline int64_t Value::asInt() const
255{
256 return hasInt32() ? asInt32() : asInt64();
257}
258
259inline bool Value::isInt(int64_t value) const
260{
261 return hasInt() && asInt() == value;
262}
263
264inline bool Value::hasIntPtr() const
265{
266 if (is64Bit())
267 return hasInt64();
268 return hasInt32();
269}
270
271inline intptr_t Value::asIntPtr() const
272{
273 if (is64Bit())
274 return asInt64();
275 return asInt32();
276}
277
278inline bool Value::isIntPtr(intptr_t value) const
279{
280 return hasIntPtr() && asIntPtr() == value;
281}
282
283inline bool Value::hasDouble() const
284{
285 return !!as<ConstDoubleValue>();
286}
287
288inline double Value::asDouble() const
289{
290 return as<ConstDoubleValue>()->value();
291}
292
293inline bool Value::isEqualToDouble(double value) const
294{
295 return hasDouble() && asDouble() == value;
296}
297
298inline bool Value::hasFloat() const
299{
300 return !!as<ConstFloatValue>();
301}
302
303inline float Value::asFloat() const
304{
305 return as<ConstFloatValue>()->value();
306}
307
308inline bool Value::hasNumber() const
309{
310 return hasInt() || hasDouble() || hasFloat();
311}
312
313inline 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
326template<typename T>
327inline 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
343template<typename T>
344inline 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
360template<typename Functor>
361void 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