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