Add support for the Wasm multi-value proposal
[WebKit-https.git] / Source / JavaScriptCore / b3 / B3ValueRep.h
1 /*
2  * Copyright (C) 2015-2018 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 "FPRInfo.h"
31 #include "GPRInfo.h"
32 #include "JSCJSValue.h"
33 #include "Reg.h"
34 #include "RegisterSet.h"
35 #include "ValueRecovery.h"
36 #include <wtf/PrintStream.h>
37
38 namespace JSC {
39
40 class AssemblyHelpers;
41
42 namespace B3 {
43
44 // We use this class to describe value representations at stackmaps. It's used both to force a
45 // representation and to get the representation. When the B3 client forces a representation, we say
46 // that it's an input. When B3 tells the client what representation it picked, we say that it's an
47 // output.
48
49 class ValueRep {
50     WTF_MAKE_FAST_ALLOCATED;
51 public:
52     enum Kind : uint8_t {
53         // As an input representation, this means that B3 can pick any representation. As an output
54         // representation, this means that we don't know. This will only arise as an output
55         // representation for the active arguments of Check/CheckAdd/CheckSub/CheckMul.
56         WarmAny,
57
58         // Same as WarmAny, but implies that the use is cold. A cold use is not counted as a use for
59         // computing the priority of the used temporary.
60         ColdAny,
61
62         // Same as ColdAny, but also implies that the use occurs after all other effects of the stackmap
63         // value.
64         LateColdAny,
65
66         // As an input representation, this means that B3 should pick some register. It could be a
67         // register that this claims to clobber!
68         SomeRegister,
69         
70         // As an input representation, this means that B3 should pick some register but that this
71         // register is then cobbered with garbage. This only works for patchpoints.
72         SomeRegisterWithClobber,
73
74         // As an input representation, this tells us that B3 should pick some register, but implies
75         // that the def happens before any of the effects of the stackmap. This is only valid for
76         // the result constraint of a Patchpoint.
77         SomeEarlyRegister,
78
79         // As an input representation, this tells us that B3 should pick some register, but implies
80         // the use happens after any defs. This is only works for patchpoints.
81         SomeLateRegister,
82
83         // As an input representation, this forces a particular register. As an output
84         // representation, this tells us what register B3 picked.
85         Register,
86
87         // As an input representation, this forces a particular register and states that
88         // the register is used late. This means that the register is used after the result
89         // is defined (i.e, the result will interfere with this as an input).
90         // It's not a valid output representation.
91         LateRegister,
92
93         // As an output representation, this tells us what stack slot B3 picked. It's not a valid
94         // input representation.
95         Stack,
96
97         // As an input representation, this forces the value to end up in the argument area at some
98         // offset. As an output representation this tells us what offset from SP B3 picked.
99         StackArgument,
100
101         // As an output representation, this tells us that B3 constant-folded the value.
102         Constant
103     };
104     
105     ValueRep()
106         : m_kind(WarmAny)
107     {
108     }
109
110     explicit ValueRep(Reg reg)
111         : m_kind(Register)
112     {
113         u.reg = reg;
114     }
115
116     ValueRep(const ValueRep&) = default;
117
118     ValueRep(Kind kind)
119         : m_kind(kind)
120     {
121         ASSERT(kind == WarmAny || kind == ColdAny || kind == LateColdAny || kind == SomeRegister || kind == SomeRegisterWithClobber || kind == SomeEarlyRegister || kind == SomeLateRegister);
122     }
123
124     static ValueRep reg(Reg reg)
125     {
126         return ValueRep(reg);
127     }
128
129     static ValueRep lateReg(Reg reg)
130     {
131         ValueRep result(reg);
132         result.m_kind = LateRegister;
133         return result;
134     }
135
136     static ValueRep stack(intptr_t offsetFromFP)
137     {
138         ValueRep result;
139         result.m_kind = Stack;
140         result.u.offsetFromFP = offsetFromFP;
141         return result;
142     }
143
144     static ValueRep stackArgument(intptr_t offsetFromSP)
145     {
146         ValueRep result;
147         result.m_kind = StackArgument;
148         result.u.offsetFromSP = offsetFromSP;
149         return result;
150     }
151
152     static ValueRep constant(int64_t value)
153     {
154         ValueRep result;
155         result.m_kind = Constant;
156         result.u.value = value;
157         return result;
158     }
159
160     static ValueRep constantDouble(double value)
161     {
162         return ValueRep::constant(bitwise_cast<int64_t>(value));
163     }
164
165     static ValueRep constantFloat(float value)
166     {
167         return ValueRep::constant(static_cast<uint64_t>(bitwise_cast<uint32_t>(value)));
168     }
169
170     Kind kind() const { return m_kind; }
171
172     bool operator==(const ValueRep& other) const
173     {
174         if (kind() != other.kind())
175             return false;
176         switch (kind()) {
177         case LateRegister:
178         case Register:
179             return u.reg == other.u.reg;
180         case Stack:
181             return u.offsetFromFP == other.u.offsetFromFP;
182         case StackArgument:
183             return u.offsetFromSP == other.u.offsetFromSP;
184         case Constant:
185             return u.value == other.u.value;
186         default:
187             return true;
188         }
189     }
190
191     bool operator!=(const ValueRep& other) const
192     {
193         return !(*this == other);
194     }
195
196     explicit operator bool() const { return kind() != WarmAny; }
197
198     bool isAny() const { return kind() == WarmAny || kind() == ColdAny || kind() == LateColdAny; }
199
200     bool isReg() const { return kind() == Register || kind() == LateRegister || kind() == SomeLateRegister; }
201     
202     Reg reg() const
203     {
204         ASSERT(isReg());
205         return u.reg;
206     }
207
208     bool isGPR() const { return isReg() && reg().isGPR(); }
209     bool isFPR() const { return isReg() && reg().isFPR(); }
210
211     GPRReg gpr() const { return reg().gpr(); }
212     FPRReg fpr() const { return reg().fpr(); }
213
214     bool isStack() const { return kind() == Stack; }
215
216     intptr_t offsetFromFP() const
217     {
218         ASSERT(isStack());
219         return u.offsetFromFP;
220     }
221
222     bool isStackArgument() const { return kind() == StackArgument; }
223
224     intptr_t offsetFromSP() const
225     {
226         ASSERT(isStackArgument());
227         return u.offsetFromSP;
228     }
229
230     bool isConstant() const { return kind() == Constant; }
231
232     int64_t value() const
233     {
234         ASSERT(isConstant());
235         return u.value;
236     }
237
238     double doubleValue() const
239     {
240         return bitwise_cast<double>(value());
241     }
242
243     float floatValue() const
244     {
245         return bitwise_cast<float>(static_cast<uint32_t>(static_cast<uint64_t>(value())));
246     }
247
248     ValueRep withOffset(intptr_t offset) const
249     {
250         switch (kind()) {
251         case Stack:
252             return stack(offsetFromFP() + offset);
253         case StackArgument:
254             return stackArgument(offsetFromSP() + offset);
255         default:
256             return *this;
257         }
258     }
259
260     void addUsedRegistersTo(RegisterSet&) const;
261     
262     RegisterSet usedRegisters() const;
263
264     // Get the used registers for a vector of ValueReps.
265     template<typename VectorType>
266     static RegisterSet usedRegisters(const VectorType& vector)
267     {
268         RegisterSet result;
269         for (const ValueRep& value : vector)
270             value.addUsedRegistersTo(result);
271         return result;
272     }
273
274     JS_EXPORT_PRIVATE void dump(PrintStream&) const;
275
276     // This has a simple contract: it emits code to restore the value into the given register. This
277     // will work even if it requires moving between bits a GPR and a FPR.
278     void emitRestore(AssemblyHelpers&, Reg) const;
279
280     // Computes the ValueRecovery assuming that the Value* was for a JSValue (i.e. Int64).
281     // NOTE: We should avoid putting JSValue-related methods in B3, but this was hard to avoid
282     // because some parts of JSC use ValueRecovery like a general "where my bits at" object, almost
283     // exactly like ValueRep.
284     ValueRecovery recoveryForJSValue() const;
285
286 private:
287     union U {
288         Reg reg;
289         intptr_t offsetFromFP;
290         intptr_t offsetFromSP;
291         int64_t value;
292
293         U()
294         {
295             memset(static_cast<void*>(this), 0, sizeof(*this));
296         }
297     } u;
298     Kind m_kind;
299 };
300
301 } } // namespace JSC::B3
302
303 namespace WTF {
304
305 void printInternal(PrintStream&, JSC::B3::ValueRep::Kind);
306
307 } // namespace WTF
308
309 #endif // ENABLE(B3_JIT)