Add WASM support for i64 simple opcodes.
[WebKit-https.git] / Source / JavaScriptCore / wasm / WASMB3IRGenerator.cpp
1 /*
2  * Copyright (C) 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 #include "config.h"
27 #include "WASMB3IRGenerator.h"
28
29 #include "B3BasicBlockInlines.h"
30 #include "B3ValueInlines.h"
31 #include "B3Variable.h"
32 #include "B3VariableValue.h"
33 #include "WASMFunctionParser.h"
34 #include <wtf/Optional.h>
35
36 #if ENABLE(WEBASSEMBLY)
37
38 namespace JSC {
39
40 namespace WASM {
41
42 using namespace B3;
43
44 inline B3::Opcode toB3Op(WASMBinaryOpType op)
45 {
46     switch (op) {
47 #define CREATE_CASE(name, op, b3op) case WASMBinaryOpType::name: return b3op;
48     FOR_EACH_WASM_BINARY_OP(CREATE_CASE)
49 #undef CREATE_CASE
50     }
51 }
52
53 inline B3::Opcode toB3Op(WASMUnaryOpType op)
54 {
55     switch (op) {
56 #define CREATE_CASE(name, op, b3op) case WASMUnaryOpType::name: return b3op;
57     FOR_EACH_WASM_UNARY_OP(CREATE_CASE)
58 #undef CREATE_CASE
59     }
60 }
61
62 class B3IRGenerator {
63 public:
64     typedef Value* ExpressionType;
65
66     B3IRGenerator(Procedure&);
67
68     void addLocal(WASMValueType, uint32_t);
69     ExpressionType addConstant(WASMValueType, uint64_t);
70
71     bool WARN_UNUSED_RETURN binaryOp(WASMBinaryOpType, ExpressionType left, ExpressionType right, ExpressionType& result);
72     bool WARN_UNUSED_RETURN unaryOp(WASMUnaryOpType, ExpressionType arg, ExpressionType& result);
73
74     bool WARN_UNUSED_RETURN addBlock();
75     bool WARN_UNUSED_RETURN endBlock(Vector<ExpressionType>& expressionStack);
76     bool WARN_UNUSED_RETURN addReturn(const Vector<ExpressionType, 1>& returnValues);
77
78 private:
79     Optional<Vector<Variable*>>& stackForControlLevel(unsigned);
80     BasicBlock* blockForControlLevel(unsigned);
81     void unify(Variable* target, const ExpressionType source);
82     Vector<Variable*> initializeIncommingTypes(BasicBlock*, const Vector<ExpressionType>&);
83     void unifyValuesWithLevel(const Vector<ExpressionType>& resultStack, unsigned);
84
85     Procedure& m_proc;
86     BasicBlock* m_currentBlock;
87     // This is a pair of the continuation and the types expected on the stack for that continuation.
88     Vector<std::pair<BasicBlock*, Optional<Vector<Variable*>>>> m_controlStack;
89 };
90
91 B3IRGenerator::B3IRGenerator(Procedure& procedure)
92     : m_proc(procedure)
93 {
94     m_currentBlock = m_proc.addBlock();
95 }
96
97 void B3IRGenerator::addLocal(WASMValueType, uint32_t)
98 {
99     // TODO: Add locals.
100 }
101
102 bool B3IRGenerator::unaryOp(WASMUnaryOpType op, ExpressionType arg, ExpressionType& result)
103 {
104     result = m_currentBlock->appendNew<Value>(m_proc, toB3Op(op), Origin(), arg);
105     return true;
106 }
107
108 bool B3IRGenerator::binaryOp(WASMBinaryOpType op, ExpressionType left, ExpressionType right, ExpressionType& result)
109 {
110     result = m_currentBlock->appendNew<Value>(m_proc, toB3Op(op), Origin(), left, right);
111     return true;
112 }
113
114 B3IRGenerator::ExpressionType B3IRGenerator::addConstant(WASMValueType type, uint64_t value)
115 {
116     switch (type) {
117     case WASMValueType::I32:
118         return m_currentBlock->appendNew<Const32Value>(m_proc, Origin(), static_cast<int32_t>(value));
119     case WASMValueType::I64:
120         return m_currentBlock->appendNew<Const64Value>(m_proc, Origin(), value);
121     case WASMValueType::F32:
122         return m_currentBlock->appendNew<ConstFloatValue>(m_proc, Origin(), bitwise_cast<float>(static_cast<int32_t>(value)));
123     case WASMValueType::F64:
124         return m_currentBlock->appendNew<ConstDoubleValue>(m_proc, Origin(), bitwise_cast<double>(value));
125     default:
126         RELEASE_ASSERT_NOT_REACHED();
127         return nullptr;
128     }
129 }
130
131 bool B3IRGenerator::addBlock()
132 {
133     m_controlStack.append(std::make_pair(m_proc.addBlock(), Nullopt));
134     return true;
135 }
136
137 bool B3IRGenerator::endBlock(Vector<ExpressionType>& expressionStack)
138 {
139     // This means that we are exiting the function.
140     if (!m_controlStack.size()) {
141         // FIXME: Should this require the stack is empty? It's not clear from the current spec.
142         return !expressionStack.size();
143     }
144
145     unifyValuesWithLevel(expressionStack, 0);
146
147     m_currentBlock = m_controlStack.takeLast().first;
148     return true;
149 }
150
151 bool B3IRGenerator::addReturn(const Vector<ExpressionType, 1>& returnValues)
152 {
153     ASSERT(returnValues.size() <= 1);
154     if (returnValues.size())
155         m_currentBlock->appendNewControlValue(m_proc, B3::Return, Origin(), returnValues[0]);
156     else
157         m_currentBlock->appendNewControlValue(m_proc, B3::Return, Origin());
158     return true;
159 }
160
161 void B3IRGenerator::unify(Variable* variable, ExpressionType source)
162 {
163     m_currentBlock->appendNew<VariableValue>(m_proc, Set, Origin(), variable, source);
164 }
165
166 Vector<Variable*> B3IRGenerator::initializeIncommingTypes(BasicBlock* block, const Vector<ExpressionType>& source)
167 {
168     Vector<Variable*> result;
169     result.reserveInitialCapacity(source.size());
170     for (ExpressionType expr : source) {
171         ASSERT(expr->type() != Void);
172         Variable* var = m_proc.addVariable(expr->type());
173         result.append(var);
174         block->appendNew<VariableValue>(m_proc, B3::Get, Origin(), var);
175     }
176
177     return result;
178 }
179
180 void B3IRGenerator::unifyValuesWithLevel(const Vector<ExpressionType>& resultStack, unsigned level)
181 {
182     ASSERT(level < m_controlStack.size());
183
184     Optional<Vector<Variable*>>& expectedStack = stackForControlLevel(level);
185     if (!expectedStack) {
186         expectedStack = initializeIncommingTypes(blockForControlLevel(level), resultStack);
187         return;
188     }
189
190     ASSERT(expectedStack.value().size() != resultStack.size());
191
192     for (size_t i = 0; i < resultStack.size(); ++i)
193         unify(expectedStack.value()[i], resultStack[i]);
194 }
195     
196 Optional<Vector<Variable*>>& B3IRGenerator::stackForControlLevel(unsigned level)
197 {
198     return m_controlStack[m_controlStack.size() - 1 - level].second;
199 }
200
201 BasicBlock* B3IRGenerator::blockForControlLevel(unsigned level)
202 {
203     return m_controlStack[m_controlStack.size() - 1 - level].first;
204 }
205
206 std::unique_ptr<Compilation> parseAndCompile(VM& vm, Vector<uint8_t>& source, WASMFunctionInformation info, unsigned optLevel)
207 {
208     Procedure procedure;
209     B3IRGenerator context(procedure);
210     WASMFunctionParser<B3IRGenerator> parser(context, source, info);
211     if (!parser.parse())
212         RELEASE_ASSERT_NOT_REACHED();
213
214     return std::make_unique<Compilation>(vm, procedure, optLevel);
215 }
216
217 } // namespace WASM
218
219 } // namespace JSC
220
221 #endif // ENABLE(WEBASSEMBLY)