Use constexpr instead of const in symbol definitions that are obviously constexpr.
[WebKit-https.git] / Source / JavaScriptCore / b3 / B3Kind.h
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
35 namespace 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
59 class Kind {
60 public:
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     
185 private:
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
199 inline Kind chill(Kind kind)
200 {
201     kind.setIsChill(true);
202     return kind;
203 }
204
205 inline Kind trapping(Kind kind)
206 {
207     kind.setTraps(true);
208     return kind;
209 }
210
211 struct 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
219 namespace WTF {
220
221 template<typename T> struct DefaultHash;
222 template<> struct DefaultHash<JSC::B3::Kind> {
223     typedef JSC::B3::KindHash Hash;
224 };
225
226 template<typename T> struct HashTraits;
227 template<> 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