Create a super rough prototype of B3
[WebKit-https.git] / Source / JavaScriptCore / b3 / B3Value.h
1 /*
2  * Copyright (C) 2015 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 B3Value_h
27 #define B3Value_h
28
29 #if ENABLE(B3_JIT)
30
31 #include "AirArg.h"
32 #include "B3Effects.h"
33 #include "B3Opcode.h"
34 #include "B3Origin.h"
35 #include "B3Type.h"
36 #include <wtf/FastMalloc.h>
37 #include <wtf/Noncopyable.h>
38
39 namespace JSC { namespace B3 {
40
41 class BasicBlock;
42 class Procedure;
43 class Stackmap;
44
45 class JS_EXPORT_PRIVATE Value {
46     WTF_MAKE_NONCOPYABLE(Value);
47     WTF_MAKE_FAST_ALLOCATED;
48 public:
49     typedef Vector<Value*, 3> AdjacencyList;
50
51     static const char* const dumpPrefix;
52
53     static bool accepts(Opcode) { return true; }
54
55     virtual ~Value();
56
57     unsigned index() const { return m_index; }
58     
59     // Note that the opcode is immutable, except for replacing values with Identity or Nop.
60     Opcode opcode() const { return m_opcode; }
61
62     Origin origin() const { return m_origin; }
63     
64     Value*& child(unsigned index) { return m_children[index]; }
65     Value* child(unsigned index) const { return m_children[index]; }
66
67     unsigned numChildren() const { return m_children.size(); }
68
69     // This computes the type using the opcode.
70     Type type() const { return m_type; }
71
72     // This is useful when lowering. Note that this is only valid for non-void values.
73     Air::Arg::Type airType() const { return Air::Arg::typeForB3Type(type()); }
74
75     AdjacencyList& children() { return m_children; } 
76     const AdjacencyList& children() const { return m_children; }
77
78     void replaceWithIdentity(Value*);
79     void replaceWithNop();
80
81     void dump(PrintStream&) const;
82     void deepDump(PrintStream&) const;
83
84     // This is how you cast Values. For example, if you want to do something provided that we have a
85     // ArgumentRegValue, you can do:
86     //
87     // if (ArgumentRegValue* argumentReg = value->as<ArgumentRegValue>()) {
88     //     things
89     // }
90     //
91     // This will return null if this opcode() != ArgumentReg. This works because this returns nullptr
92     // if T::accepts(opcode()) returns false.
93     template<typename T>
94     T* as();
95     template<typename T>
96     const T* as() const;
97
98     bool isConstant() const;
99     
100     virtual Value* negConstant(Procedure&) const;
101     virtual Value* addConstant(Procedure&, int32_t other) const;
102     virtual Value* addConstant(Procedure&, Value* other) const;
103     virtual Value* subConstant(Procedure&, Value* other) const;
104
105     bool hasInt32() const;
106     int32_t asInt32() const;
107     
108     bool hasInt64() const;
109     int64_t asInt64() const;
110
111     bool hasInt() const;
112     int64_t asInt() const;
113     bool isInt(int64_t value) const;
114
115     bool hasIntPtr() const;
116     intptr_t asIntPtr() const;
117
118     bool hasDouble() const;
119     double asDouble() const;
120
121     Effects effects() const;
122
123     Stackmap* stackmap();
124
125     // Makes sure that none of the children are Identity's. If a child points to Identity, this will
126     // repoint it at the Identity's child. For simplicity, this will follow arbitrarily long chains
127     // of Identity's.
128     void performSubstitution();
129
130 protected:
131     virtual void dumpMeta(PrintStream&) const;
132     
133 private:
134     friend class Procedure;
135
136 protected:
137     // Instantiate values via Procedure.
138     // This form requires specifying the type explicitly:
139     template<typename... Arguments>
140     explicit Value(unsigned index, Opcode opcode, Type type, Origin origin, Value* firstChild, Arguments... arguments)
141         : m_index(index)
142         , m_opcode(opcode)
143         , m_type(type)
144         , m_origin(origin)
145         , m_children{ firstChild, arguments... }
146     {
147     }
148     // This form is for specifying the type explicitly when the opcode has no children:
149     explicit Value(unsigned index, Opcode opcode, Type type, Origin origin)
150         : m_index(index)
151         , m_opcode(opcode)
152         , m_type(type)
153         , m_origin(origin)
154     {
155     }
156     // This form is for those opcodes that can infer their type from the opcode and first child:
157     template<typename... Arguments>
158     explicit Value(unsigned index, Opcode opcode, Origin origin, Value* firstChild, Arguments... arguments)
159         : m_index(index)
160         , m_opcode(opcode)
161         , m_type(typeFor(opcode, firstChild))
162         , m_origin(origin)
163         , m_children{ firstChild, arguments... }
164     {
165     }
166     // This form is for those opcodes that can infer their type from the opcode alone, and that don't
167     // take any arguments:
168     explicit Value(unsigned index, Opcode opcode, Origin origin)
169         : m_index(index)
170         , m_opcode(opcode)
171         , m_type(typeFor(opcode, nullptr))
172         , m_origin(origin)
173     {
174     }
175     // Use this form for varargs.
176     explicit Value(unsigned index, Opcode opcode, Type type, Origin origin, const AdjacencyList& children)
177         : m_index(index)
178         , m_opcode(opcode)
179         , m_type(type)
180         , m_origin(origin)
181         , m_children(children)
182     {
183     }
184
185 private:
186     static Type typeFor(Opcode, Value* firstChild);
187
188     // This group of fields is arranged to fit in 64 bits.
189     unsigned m_index;
190     Opcode m_opcode;
191     Type m_type;
192     
193     Origin m_origin;
194     AdjacencyList m_children;
195
196 public:
197     BasicBlock* owner { nullptr }; // computed lazily.
198 };
199
200 class DeepValueDump {
201 public:
202     DeepValueDump(const Value* value)
203         : m_value(value)
204     {
205     }
206
207     void dump(PrintStream& out) const
208     {
209         if (m_value)
210             m_value->deepDump(out);
211         else
212             out.print("<null>");
213     }
214
215 private:
216     const Value* m_value;
217 };
218
219 inline DeepValueDump deepDump(const Value* value)
220 {
221     return DeepValueDump(value);
222 }
223
224 } } // namespace JSC::B3
225
226 #endif // ENABLE(B3_JIT)
227
228 #endif // B3Value_h
229