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 "B3HeapRange.h"
31#include "B3Kind.h"
32#include "B3Origin.h"
33#include "B3Type.h"
34#include <wtf/HashTable.h>
35
36namespace JSC { namespace B3 {
37
38class Procedure;
39class Value;
40
41// ValueKeys are useful for CSE. They abstractly describe the value that a Value returns when it
42// executes. Any Value that has the same ValueKey is guaranteed to return the same value, provided
43// that they return a non-empty ValueKey. Operations that have effects, or that can have their
44// behavior affected by other operations' effects, will return an empty ValueKey. You have to use
45// other mechanisms for doing CSE for impure operations.
46
47class ValueKey {
48public:
49 ValueKey()
50 {
51 }
52
53 ValueKey(Kind kind, Type type)
54 : m_kind(kind)
55 , m_type(type)
56 {
57 }
58
59 ValueKey(Kind, Type, Value* child);
60
61 ValueKey(Kind, Type, Value* left, Value* right);
62
63 ValueKey(Kind, Type, Value* a, Value* b, Value* c);
64
65 ValueKey(Kind kind, Type type, int64_t value)
66 : m_kind(kind)
67 , m_type(type)
68 {
69 u.value = value;
70 }
71
72 ValueKey(Kind kind, Type type, double value)
73 : m_kind(kind)
74 , m_type(type)
75 {
76 u.doubleValue = value;
77 }
78
79 ValueKey(Kind kind, Type type, float value)
80 : m_kind(kind)
81 , m_type(type)
82 {
83 u.floatValue = value;
84 }
85
86 static ValueKey intConstant(Type type, int64_t value);
87
88 Kind kind() const { return m_kind; }
89 Opcode opcode() const { return kind().opcode(); }
90 Type type() const { return m_type; }
91 unsigned childIndex(unsigned index) const { return u.indices[index]; }
92 Value* child(Procedure&, unsigned index) const;
93 int64_t value() const { return u.value; }
94 double doubleValue() const { return u.doubleValue; }
95 double floatValue() const { return u.floatValue; }
96
97 bool operator==(const ValueKey& other) const
98 {
99 return m_kind == other.m_kind
100 && m_type == other.m_type
101 && u == other.u;
102 }
103
104 bool operator!=(const ValueKey& other) const
105 {
106 return !(*this == other);
107 }
108
109 unsigned hash() const
110 {
111 return m_kind.hash() + m_type + WTF::IntHash<int32_t>::hash(u.indices[0]) + u.indices[1] + u.indices[2];
112 }
113
114 explicit operator bool() const { return *this != ValueKey(); }
115
116 void dump(PrintStream&) const;
117
118 bool canMaterialize() const
119 {
120 if (!*this)
121 return false;
122 switch (opcode()) {
123 case CheckAdd:
124 case CheckSub:
125 case CheckMul:
126 return false;
127 default:
128 return true;
129 }
130 }
131
132 bool isConstant() const
133 {
134 return B3::isConstant(opcode());
135 }
136
137 // Attempts to materialize the Value for this ValueKey. May return nullptr if the value cannot
138 // be materialized. This happens for CheckAdd and friends. You can use canMaterialize() to check
139 // if your key is materializable.
140 Value* materialize(Procedure&, Origin) const;
141
142 ValueKey(WTF::HashTableDeletedValueType)
143 : m_type { Int32 }
144 {
145 }
146
147 bool isHashTableDeletedValue() const
148 {
149 return *this == ValueKey(WTF::HashTableDeletedValue);
150 }
151
152private:
153 Kind m_kind;
154 Type m_type { Void };
155 union U {
156 unsigned indices[3];
157 int64_t value;
158 double doubleValue;
159 float floatValue;
160
161 U()
162 {
163 indices[0] = 0;
164 indices[1] = 0;
165 indices[2] = 0;
166 }
167
168 bool operator==(const U& other) const
169 {
170 return indices[0] == other.indices[0]
171 && indices[1] == other.indices[1]
172 && indices[2] == other.indices[2];
173 }
174 } u;
175};
176
177struct ValueKeyHash {
178 static unsigned hash(const ValueKey& key) { return key.hash(); }
179 static bool equal(const ValueKey& a, const ValueKey& b) { return a == b; }
180 static const bool safeToCompareToEmptyOrDeleted = true;
181};
182
183} } // namespace JSC::B3
184
185namespace WTF {
186
187template<typename T> struct DefaultHash;
188template<> struct DefaultHash<JSC::B3::ValueKey> {
189 typedef JSC::B3::ValueKeyHash Hash;
190};
191
192template<typename T> struct HashTraits;
193template<> struct HashTraits<JSC::B3::ValueKey> : public SimpleClassHashTraits<JSC::B3::ValueKey> {
194 static const bool emptyValueIsZero = false;
195};
196
197} // namespace WTF
198
199#endif // ENABLE(B3_JIT)
200