1/*
2 * Copyright (C) 2016-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#ifndef B3Kind_h
27#define B3Kind_h
28
29#if ENABLE(B3_JIT)
30
31#include "B3Opcode.h"
32#include <wtf/HashTable.h>
33#include <wtf/PrintStream.h>
34
35namespace JSC { namespace B3 {
36
37// A Kind is a terse summary of what a Value does. There is a fixed number of possible
38// Kinds. Kind is a tuple of Opcode (see B3Opcode.h) and some extra bits. Most opcodes don't
39// get any extra bits, and those bits must remain zero if the Kind's opcode field is set to
40// one of those opcodes. The purpose of Kind is to be like an opcode in other IRs, but to
41// be multidimensional. For example, a Load has many dimensions of customization that we may
42// eventually implement. A Load can have different alignments, alignment failure modes,
43// temporality modes, trapping modes, ordering modes, etc. It's fine to put such flags into
44// subclasses of Value, but in some cases that would be overkill, particularly since if you
45// did that for a pure value then you'd also have to thread it through ValueKey. It's much
46// easier to put it in Kind, and then your extra bit will get carried around by everyone who
47// knows how to carry around Kinds. Most importantly, putting flags into Kind allows you to
48// use them as part of B3::Value's dynamic cast facility. For example we could have a
49// trapping Load that uses a Value subclass that has a stackmap while non-trapping Loads
50// continue to use the normal MemoryValue.
51//
52// Note that any code in the compiler that transcribes IR (like a strength reduction that
53// replaces an Add with a different Add, or even with a different opcode entirely) will
54// probably drop unknown bits by default. This is definitely not correct for many bits (like
55// isChill for Div/Mod and all of the envisioned Load/Store flags), so if you add a new bit
56// you will probably have to audit the compiler to make sure that phases that transcribe
57// your opcode do the right thing with your bit.
58
59class Kind {
60public:
61 Kind(Opcode opcode)
62 : m_opcode(opcode)
63 , m_isChill(false)
64 , m_traps(false)
65 {
66 }
67
68 Kind()
69 : Kind(Oops)
70 {
71 }
72
73 Opcode opcode() const { return m_opcode; }
74 void setOpcode(Opcode opcode) { m_opcode = opcode; }
75
76 bool hasExtraBits() const { return m_isChill || m_traps; }
77
78 // Chill bit. This applies to division-based arithmetic ops, which may trap on some
79 // platforms or exhibit bizarre behavior when passed certain inputs. The non-chill
80 // version will behave as unpredictably as it wants. For example, it's legal to
81 // constant-fold Div(x, 0) to any value or to replace it with any effectful operation.
82 // But when it's chill, that means that the semantics when it would have trapped are
83 // the JS semantics. For example, Div<Chill>(@a, @b) means:
84 //
85 // ((a | 0) / (b | 0)) | 0
86 //
87 // And Mod<Chill>(a, b) means:
88 //
89 // ((a | 0) % (b | 0)) | 0
90 //
91 // Note that Div<Chill> matches exactly how ARM handles integer division.
92 bool hasIsChill() const
93 {
94 switch (m_opcode) {
95 case Div:
96 case Mod:
97 return true;
98 default:
99 return false;
100 }
101 }
102 bool isChill() const
103 {
104 return m_isChill;
105 }
106 void setIsChill(bool isChill)
107 {
108 ASSERT(hasIsChill());
109 m_isChill = isChill;
110 }
111
112 // Traps bit. This applies to memory access ops. It means that the instruction could
113 // trap as part of some check it performs, and that we mean to make this observable. This
114 // currently only applies to memory accesses (loads and stores). You don't get to find out where
115 // in the Procedure the trap happened. If you try to work it out using Origin, you'll have a bad
116 // time because the instruction selector is too sloppy with Origin().
117 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=162688
118 bool hasTraps() const
119 {
120 switch (m_opcode) {
121 case Load8Z:
122 case Load8S:
123 case Load16Z:
124 case Load16S:
125 case Load:
126 case Store8:
127 case Store16:
128 case Store:
129 return true;
130 default:
131 return false;
132 }
133 }
134 bool traps() const
135 {
136 return m_traps;
137 }
138 void setTraps(bool traps)
139 {
140 ASSERT(hasTraps());
141 m_traps = traps;
142 }
143
144 // Rules for adding new properties:
145 // - Put the accessors here.
146 // - hasBlah() should check if the opcode allows for your property.
147 // - blah() returns a default value if !hasBlah()
148 // - setBlah() asserts if !hasBlah()
149 // - Try not to increase the size of Kind too much. But it wouldn't be the end of the
150 // world if it bloated to 64 bits.
151
152 bool operator==(const Kind& other) const
153 {
154 return m_opcode == other.m_opcode
155 && m_isChill == other.m_isChill
156 && m_traps == other.m_traps;
157 }
158
159 bool operator!=(const Kind& other) const
160 {
161 return !(*this == other);
162 }
163
164 void dump(PrintStream&) const;
165
166 unsigned hash() const
167 {
168 // It's almost certainly more important that this hash function is cheap to compute than
169 // anything else. We can live with some kind hash collisions.
170 return m_opcode + (static_cast<unsigned>(m_isChill) << 16) + (static_cast<unsigned>(m_traps) << 7);
171 }
172
173 Kind(WTF::HashTableDeletedValueType)
174 : m_opcode(Oops)
175 , m_isChill(true)
176 , m_traps(false)
177 {
178 }
179
180 bool isHashTableDeletedValue() const
181 {
182 return *this == Kind(WTF::HashTableDeletedValue);
183 }
184
185private:
186 Opcode m_opcode;
187 bool m_isChill : 1;
188 bool m_traps : 1;
189};
190
191// For every flag 'foo' you add, it's customary to create a Kind B3::foo(Kind) function that makes
192// a kind with the flag set. For example, for chill, this lets us say:
193//
194// block->appendNew<Value>(m_proc, chill(Mod), Origin(), a, b);
195//
196// I like to make the flag name fill in the sentence "Mod _____" (like "isChill" or "traps") while
197// the flag constructor fills in the phrase "_____ Mod" (like "chill" or "trapping").
198
199inline Kind chill(Kind kind)
200{
201 kind.setIsChill(true);
202 return kind;
203}
204
205inline Kind trapping(Kind kind)
206{
207 kind.setTraps(true);
208 return kind;
209}
210
211struct KindHash {
212 static unsigned hash(const Kind& key) { return key.hash(); }
213 static bool equal(const Kind& a, const Kind& b) { return a == b; }
214 static constexpr bool safeToCompareToEmptyOrDeleted = true;
215};
216
217} } // namespace JSC::B3
218
219namespace WTF {
220
221template<typename T> struct DefaultHash;
222template<> struct DefaultHash<JSC::B3::Kind> {
223 typedef JSC::B3::KindHash Hash;
224};
225
226template<typename T> struct HashTraits;
227template<> struct HashTraits<JSC::B3::Kind> : public SimpleClassHashTraits<JSC::B3::Kind> {
228 static constexpr bool emptyValueIsZero = false;
229};
230
231} // namespace WTF
232
233#endif // ENABLE(B3_JIT)
234
235#endif // B3Kind_h
236
237