blob: 0a13f98d8593f32e8990752d7d1a64451314ae6d [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/compiler/wasm-compiler.h"
6
7#include "src/isolate-inl.h"
8
Ben Murdochda12d292016-06-02 14:46:10 +01009#include "src/base/platform/elapsed-timer.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010#include "src/base/platform/platform.h"
11
12#include "src/compiler/access-builder.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013#include "src/compiler/common-operator.h"
14#include "src/compiler/diamond.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015#include "src/compiler/graph-visualizer.h"
Ben Murdochc5610432016-08-08 18:44:38 +010016#include "src/compiler/graph.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017#include "src/compiler/instruction-selector.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010018#include "src/compiler/int64-lowering.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019#include "src/compiler/js-generic-lowering.h"
20#include "src/compiler/js-graph.h"
21#include "src/compiler/js-operator.h"
22#include "src/compiler/linkage.h"
23#include "src/compiler/machine-operator.h"
24#include "src/compiler/node-matchers.h"
25#include "src/compiler/pipeline.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000026#include "src/compiler/source-position.h"
Ben Murdochc5610432016-08-08 18:44:38 +010027#include "src/compiler/zone-pool.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000028
29#include "src/code-factory.h"
30#include "src/code-stubs.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010031#include "src/factory.h"
32#include "src/log-inl.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000033
34#include "src/wasm/ast-decoder.h"
35#include "src/wasm/wasm-module.h"
36#include "src/wasm/wasm-opcodes.h"
37
38// TODO(titzer): pull WASM_64 up to a common header.
39#if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64
40#define WASM_64 1
41#else
42#define WASM_64 0
43#endif
44
45namespace v8 {
46namespace internal {
47namespace compiler {
48
49namespace {
50const Operator* UnsupportedOpcode(wasm::WasmOpcode opcode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000051 V8_Fatal(__FILE__, __LINE__, "Unsupported opcode #%d:%s", opcode,
52 wasm::WasmOpcodes::OpcodeName(opcode));
53 return nullptr;
54}
55
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000056void MergeControlToEnd(JSGraph* jsgraph, Node* node) {
57 Graph* g = jsgraph->graph();
58 if (g->end()) {
59 NodeProperties::MergeControlToEnd(g, jsgraph->common(), node);
60 } else {
61 g->SetEnd(g->NewNode(jsgraph->common()->End(1), node));
62 }
63}
64
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000065} // namespace
66
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000067// A helper that handles building graph fragments for trapping.
68// To avoid generating a ton of redundant code that just calls the runtime
69// to trap, we generate a per-trap-reason block of code that all trap sites
70// in this function will branch to.
71class WasmTrapHelper : public ZoneObject {
72 public:
73 explicit WasmTrapHelper(WasmGraphBuilder* builder)
74 : builder_(builder),
75 jsgraph_(builder->jsgraph()),
Ben Murdochc5610432016-08-08 18:44:38 +010076 graph_(builder->jsgraph() ? builder->jsgraph()->graph() : nullptr) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000077
78 // Make the current control path trap to unreachable.
Ben Murdochc5610432016-08-08 18:44:38 +010079 void Unreachable(wasm::WasmCodePosition position) {
80 ConnectTrap(wasm::kTrapUnreachable, position);
81 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000082
Ben Murdoch097c5b22016-05-18 11:27:45 +010083 // Always trap with the given reason.
Ben Murdochc5610432016-08-08 18:44:38 +010084 void TrapAlways(wasm::TrapReason reason, wasm::WasmCodePosition position) {
85 ConnectTrap(reason, position);
86 }
Ben Murdoch097c5b22016-05-18 11:27:45 +010087
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000088 // Add a check that traps if {node} is equal to {val}.
Ben Murdochc5610432016-08-08 18:44:38 +010089 Node* TrapIfEq32(wasm::TrapReason reason, Node* node, int32_t val,
90 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000091 Int32Matcher m(node);
92 if (m.HasValue() && !m.Is(val)) return graph()->start();
93 if (val == 0) {
Ben Murdochc5610432016-08-08 18:44:38 +010094 AddTrapIfFalse(reason, node, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000095 } else {
96 AddTrapIfTrue(reason,
97 graph()->NewNode(jsgraph()->machine()->Word32Equal(), node,
Ben Murdochc5610432016-08-08 18:44:38 +010098 jsgraph()->Int32Constant(val)),
99 position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000100 }
101 return builder_->Control();
102 }
103
104 // Add a check that traps if {node} is zero.
Ben Murdochc5610432016-08-08 18:44:38 +0100105 Node* ZeroCheck32(wasm::TrapReason reason, Node* node,
106 wasm::WasmCodePosition position) {
107 return TrapIfEq32(reason, node, 0, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000108 }
109
110 // Add a check that traps if {node} is equal to {val}.
Ben Murdochc5610432016-08-08 18:44:38 +0100111 Node* TrapIfEq64(wasm::TrapReason reason, Node* node, int64_t val,
112 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000113 Int64Matcher m(node);
114 if (m.HasValue() && !m.Is(val)) return graph()->start();
Ben Murdochc5610432016-08-08 18:44:38 +0100115 AddTrapIfTrue(reason, graph()->NewNode(jsgraph()->machine()->Word64Equal(),
116 node, jsgraph()->Int64Constant(val)),
117 position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000118 return builder_->Control();
119 }
120
121 // Add a check that traps if {node} is zero.
Ben Murdochc5610432016-08-08 18:44:38 +0100122 Node* ZeroCheck64(wasm::TrapReason reason, Node* node,
123 wasm::WasmCodePosition position) {
124 return TrapIfEq64(reason, node, 0, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000125 }
126
127 // Add a trap if {cond} is true.
Ben Murdochc5610432016-08-08 18:44:38 +0100128 void AddTrapIfTrue(wasm::TrapReason reason, Node* cond,
129 wasm::WasmCodePosition position) {
130 AddTrapIf(reason, cond, true, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000131 }
132
133 // Add a trap if {cond} is false.
Ben Murdochc5610432016-08-08 18:44:38 +0100134 void AddTrapIfFalse(wasm::TrapReason reason, Node* cond,
135 wasm::WasmCodePosition position) {
136 AddTrapIf(reason, cond, false, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000137 }
138
139 // Add a trap if {cond} is true or false according to {iftrue}.
Ben Murdochc5610432016-08-08 18:44:38 +0100140 void AddTrapIf(wasm::TrapReason reason, Node* cond, bool iftrue,
141 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000142 Node** effect_ptr = builder_->effect_;
143 Node** control_ptr = builder_->control_;
144 Node* before = *effect_ptr;
145 BranchHint hint = iftrue ? BranchHint::kFalse : BranchHint::kTrue;
146 Node* branch = graph()->NewNode(common()->Branch(hint), cond, *control_ptr);
147 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
148 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
149
150 *control_ptr = iftrue ? if_true : if_false;
Ben Murdochc5610432016-08-08 18:44:38 +0100151 ConnectTrap(reason, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000152 *control_ptr = iftrue ? if_false : if_true;
153 *effect_ptr = before;
154 }
155
Ben Murdoch097c5b22016-05-18 11:27:45 +0100156 Node* GetTrapValue(wasm::FunctionSig* sig) {
157 if (sig->return_count() > 0) {
158 switch (sig->GetReturn()) {
159 case wasm::kAstI32:
160 return jsgraph()->Int32Constant(0xdeadbeef);
161 case wasm::kAstI64:
162 return jsgraph()->Int64Constant(0xdeadbeefdeadbeef);
163 case wasm::kAstF32:
164 return jsgraph()->Float32Constant(bit_cast<float>(0xdeadbeef));
165 case wasm::kAstF64:
166 return jsgraph()->Float64Constant(
167 bit_cast<double>(0xdeadbeefdeadbeef));
168 break;
169 default:
170 UNREACHABLE();
171 return nullptr;
172 }
173 } else {
174 return jsgraph()->Int32Constant(0xdeadbeef);
175 }
176 }
177
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000178 private:
179 WasmGraphBuilder* builder_;
180 JSGraph* jsgraph_;
181 Graph* graph_;
Ben Murdochc5610432016-08-08 18:44:38 +0100182 Node* trap_merge_ = nullptr;
183 Node* trap_effect_;
184 Node* trap_reason_;
185 Node* trap_position_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000186
187 JSGraph* jsgraph() { return jsgraph_; }
188 Graph* graph() { return jsgraph_->graph(); }
189 CommonOperatorBuilder* common() { return jsgraph()->common(); }
190
Ben Murdochc5610432016-08-08 18:44:38 +0100191 void ConnectTrap(wasm::TrapReason reason, wasm::WasmCodePosition position) {
192 DCHECK(position != wasm::kNoCodePosition);
193 Node* reason_node = builder_->Int32Constant(
194 wasm::WasmOpcodes::TrapReasonToMessageId(reason));
195 Node* position_node = builder_->Int32Constant(position);
196 if (trap_merge_ == nullptr) {
197 // Create trap code for the first time.
198 return BuildTrapCode(reason_node, position_node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000199 }
200 // Connect the current control and effect to the existing trap code.
Ben Murdochc5610432016-08-08 18:44:38 +0100201 builder_->AppendToMerge(trap_merge_, builder_->Control());
202 builder_->AppendToPhi(trap_effect_, builder_->Effect());
203 builder_->AppendToPhi(trap_reason_, reason_node);
204 builder_->AppendToPhi(trap_position_, position_node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000205 }
206
Ben Murdochc5610432016-08-08 18:44:38 +0100207 void BuildTrapCode(Node* reason_node, Node* position_node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000208 Node* end;
209 Node** control_ptr = builder_->control_;
210 Node** effect_ptr = builder_->effect_;
211 wasm::ModuleEnv* module = builder_->module_;
Ben Murdochc5610432016-08-08 18:44:38 +0100212 DCHECK(trap_merge_ == NULL);
213 *control_ptr = trap_merge_ =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000214 graph()->NewNode(common()->Merge(1), *control_ptr);
Ben Murdochc5610432016-08-08 18:44:38 +0100215 *effect_ptr = trap_effect_ =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000216 graph()->NewNode(common()->EffectPhi(1), *effect_ptr, *control_ptr);
Ben Murdochc5610432016-08-08 18:44:38 +0100217 trap_reason_ =
218 graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 1),
219 reason_node, *control_ptr);
220 trap_position_ =
221 graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 1),
222 position_node, *control_ptr);
223
224 Node* trap_reason_smi = builder_->BuildChangeInt32ToSmi(trap_reason_);
225 Node* trap_position_smi = builder_->BuildChangeInt32ToSmi(trap_position_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000226
Ben Murdoch097c5b22016-05-18 11:27:45 +0100227 if (module && !module->instance->context.is_null()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000228 // Use the module context to call the runtime to throw an exception.
Ben Murdochc5610432016-08-08 18:44:38 +0100229 Runtime::FunctionId f = Runtime::kThrowWasmError;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000230 const Runtime::Function* fun = Runtime::FunctionForId(f);
231 CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
232 jsgraph()->zone(), f, fun->nargs, Operator::kNoProperties,
233 CallDescriptor::kNoFlags);
Ben Murdochc5610432016-08-08 18:44:38 +0100234 // CEntryStubConstant nodes have to be created and cached in the main
235 // thread. At the moment this is only done for CEntryStubConstant(1).
236 DCHECK_EQ(1, fun->result_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000237 Node* inputs[] = {
238 jsgraph()->CEntryStubConstant(fun->result_size), // C entry
Ben Murdochc5610432016-08-08 18:44:38 +0100239 trap_reason_smi, // message id
240 trap_position_smi, // byte position
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000241 jsgraph()->ExternalConstant(
Ben Murdochc5610432016-08-08 18:44:38 +0100242 ExternalReference(f, jsgraph()->isolate())), // ref
243 jsgraph()->Int32Constant(fun->nargs), // arity
244 builder_->HeapConstant(module->instance->context), // context
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000245 *effect_ptr,
246 *control_ptr};
247
248 Node* node = graph()->NewNode(
249 common()->Call(desc), static_cast<int>(arraysize(inputs)), inputs);
250 *control_ptr = node;
251 *effect_ptr = node;
252 }
253 if (false) {
254 // End the control flow with a throw
255 Node* thrw =
256 graph()->NewNode(common()->Throw(), jsgraph()->ZeroConstant(),
257 *effect_ptr, *control_ptr);
258 end = thrw;
259 } else {
260 // End the control flow with returning 0xdeadbeef
Ben Murdoch097c5b22016-05-18 11:27:45 +0100261 Node* ret_value = GetTrapValue(builder_->GetFunctionSignature());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000262 end = graph()->NewNode(jsgraph()->common()->Return(), ret_value,
263 *effect_ptr, *control_ptr);
264 }
265
266 MergeControlToEnd(jsgraph(), end);
267 }
268};
269
Ben Murdochc5610432016-08-08 18:44:38 +0100270WasmGraphBuilder::WasmGraphBuilder(
271 Zone* zone, JSGraph* jsgraph, wasm::FunctionSig* function_signature,
272 compiler::SourcePositionTable* source_position_table)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000273 : zone_(zone),
274 jsgraph_(jsgraph),
275 module_(nullptr),
276 mem_buffer_(nullptr),
277 mem_size_(nullptr),
278 function_table_(nullptr),
279 control_(nullptr),
280 effect_(nullptr),
281 cur_buffer_(def_buffer_),
282 cur_bufsize_(kDefaultBufferSize),
283 trap_(new (zone) WasmTrapHelper(this)),
Ben Murdochc5610432016-08-08 18:44:38 +0100284 function_signature_(function_signature),
285 source_position_table_(source_position_table) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000286 DCHECK_NOT_NULL(jsgraph_);
287}
288
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000289Node* WasmGraphBuilder::Error() { return jsgraph()->Dead(); }
290
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000291Node* WasmGraphBuilder::Start(unsigned params) {
292 Node* start = graph()->NewNode(jsgraph()->common()->Start(params));
293 graph()->SetStart(start);
294 return start;
295}
296
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000297Node* WasmGraphBuilder::Param(unsigned index, wasm::LocalType type) {
298 return graph()->NewNode(jsgraph()->common()->Parameter(index),
299 graph()->start());
300}
301
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000302Node* WasmGraphBuilder::Loop(Node* entry) {
303 return graph()->NewNode(jsgraph()->common()->Loop(1), entry);
304}
305
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000306Node* WasmGraphBuilder::Terminate(Node* effect, Node* control) {
307 Node* terminate =
308 graph()->NewNode(jsgraph()->common()->Terminate(), effect, control);
309 MergeControlToEnd(jsgraph(), terminate);
310 return terminate;
311}
312
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000313unsigned WasmGraphBuilder::InputCount(Node* node) {
314 return static_cast<unsigned>(node->InputCount());
315}
316
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000317bool WasmGraphBuilder::IsPhiWithMerge(Node* phi, Node* merge) {
318 return phi && IrOpcode::IsPhiOpcode(phi->opcode()) &&
319 NodeProperties::GetControlInput(phi) == merge;
320}
321
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000322void WasmGraphBuilder::AppendToMerge(Node* merge, Node* from) {
323 DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
324 merge->AppendInput(jsgraph()->zone(), from);
325 int new_size = merge->InputCount();
326 NodeProperties::ChangeOp(
327 merge, jsgraph()->common()->ResizeMergeOrPhi(merge->op(), new_size));
328}
329
Ben Murdochc5610432016-08-08 18:44:38 +0100330void WasmGraphBuilder::AppendToPhi(Node* phi, Node* from) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000331 DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000332 int new_size = phi->InputCount();
333 phi->InsertInput(jsgraph()->zone(), phi->InputCount() - 1, from);
334 NodeProperties::ChangeOp(
335 phi, jsgraph()->common()->ResizeMergeOrPhi(phi->op(), new_size));
336}
337
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000338Node* WasmGraphBuilder::Merge(unsigned count, Node** controls) {
339 return graph()->NewNode(jsgraph()->common()->Merge(count), count, controls);
340}
341
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000342Node* WasmGraphBuilder::Phi(wasm::LocalType type, unsigned count, Node** vals,
343 Node* control) {
344 DCHECK(IrOpcode::IsMergeOpcode(control->opcode()));
Ben Murdochda12d292016-06-02 14:46:10 +0100345 Node** buf = Realloc(vals, count, count + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000346 buf[count] = control;
347 return graph()->NewNode(jsgraph()->common()->Phi(type, count), count + 1,
348 buf);
349}
350
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000351Node* WasmGraphBuilder::EffectPhi(unsigned count, Node** effects,
352 Node* control) {
353 DCHECK(IrOpcode::IsMergeOpcode(control->opcode()));
Ben Murdochda12d292016-06-02 14:46:10 +0100354 Node** buf = Realloc(effects, count, count + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000355 buf[count] = control;
356 return graph()->NewNode(jsgraph()->common()->EffectPhi(count), count + 1,
357 buf);
358}
359
Ben Murdochc5610432016-08-08 18:44:38 +0100360Node* WasmGraphBuilder::NumberConstant(int32_t value) {
361 return jsgraph()->Constant(value);
362}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000363
364Node* WasmGraphBuilder::Int32Constant(int32_t value) {
365 return jsgraph()->Int32Constant(value);
366}
367
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000368Node* WasmGraphBuilder::Int64Constant(int64_t value) {
369 return jsgraph()->Int64Constant(value);
370}
371
Ben Murdochc5610432016-08-08 18:44:38 +0100372Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left, Node* right,
373 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000374 const Operator* op;
375 MachineOperatorBuilder* m = jsgraph()->machine();
376 switch (opcode) {
377 case wasm::kExprI32Add:
378 op = m->Int32Add();
379 break;
380 case wasm::kExprI32Sub:
381 op = m->Int32Sub();
382 break;
383 case wasm::kExprI32Mul:
384 op = m->Int32Mul();
385 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100386 case wasm::kExprI32DivS:
Ben Murdochc5610432016-08-08 18:44:38 +0100387 return BuildI32DivS(left, right, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000388 case wasm::kExprI32DivU:
Ben Murdochc5610432016-08-08 18:44:38 +0100389 return BuildI32DivU(left, right, position);
Ben Murdochda12d292016-06-02 14:46:10 +0100390 case wasm::kExprI32RemS:
Ben Murdochc5610432016-08-08 18:44:38 +0100391 return BuildI32RemS(left, right, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000392 case wasm::kExprI32RemU:
Ben Murdochc5610432016-08-08 18:44:38 +0100393 return BuildI32RemU(left, right, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000394 case wasm::kExprI32And:
395 op = m->Word32And();
396 break;
397 case wasm::kExprI32Ior:
398 op = m->Word32Or();
399 break;
400 case wasm::kExprI32Xor:
401 op = m->Word32Xor();
402 break;
403 case wasm::kExprI32Shl:
404 op = m->Word32Shl();
Ben Murdochda12d292016-06-02 14:46:10 +0100405 right = MaskShiftCount32(right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000406 break;
407 case wasm::kExprI32ShrU:
408 op = m->Word32Shr();
Ben Murdochda12d292016-06-02 14:46:10 +0100409 right = MaskShiftCount32(right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000410 break;
411 case wasm::kExprI32ShrS:
412 op = m->Word32Sar();
Ben Murdochda12d292016-06-02 14:46:10 +0100413 right = MaskShiftCount32(right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000414 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100415 case wasm::kExprI32Ror:
416 op = m->Word32Ror();
417 right = MaskShiftCount32(right);
418 break;
419 case wasm::kExprI32Rol:
420 right = MaskShiftCount32(right);
421 return BuildI32Rol(left, right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000422 case wasm::kExprI32Eq:
423 op = m->Word32Equal();
424 break;
425 case wasm::kExprI32Ne:
426 return Invert(Binop(wasm::kExprI32Eq, left, right));
427 case wasm::kExprI32LtS:
428 op = m->Int32LessThan();
429 break;
430 case wasm::kExprI32LeS:
431 op = m->Int32LessThanOrEqual();
432 break;
433 case wasm::kExprI32LtU:
434 op = m->Uint32LessThan();
435 break;
436 case wasm::kExprI32LeU:
437 op = m->Uint32LessThanOrEqual();
438 break;
439 case wasm::kExprI32GtS:
440 op = m->Int32LessThan();
441 std::swap(left, right);
442 break;
443 case wasm::kExprI32GeS:
444 op = m->Int32LessThanOrEqual();
445 std::swap(left, right);
446 break;
447 case wasm::kExprI32GtU:
448 op = m->Uint32LessThan();
449 std::swap(left, right);
450 break;
451 case wasm::kExprI32GeU:
452 op = m->Uint32LessThanOrEqual();
453 std::swap(left, right);
454 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100455 case wasm::kExprI64And:
456 op = m->Word64And();
457 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000458 case wasm::kExprI64Add:
459 op = m->Int64Add();
460 break;
461 case wasm::kExprI64Sub:
462 op = m->Int64Sub();
463 break;
464 case wasm::kExprI64Mul:
465 op = m->Int64Mul();
466 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100467 case wasm::kExprI64DivS:
Ben Murdochc5610432016-08-08 18:44:38 +0100468 return BuildI64DivS(left, right, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000469 case wasm::kExprI64DivU:
Ben Murdochc5610432016-08-08 18:44:38 +0100470 return BuildI64DivU(left, right, position);
Ben Murdochda12d292016-06-02 14:46:10 +0100471 case wasm::kExprI64RemS:
Ben Murdochc5610432016-08-08 18:44:38 +0100472 return BuildI64RemS(left, right, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000473 case wasm::kExprI64RemU:
Ben Murdochc5610432016-08-08 18:44:38 +0100474 return BuildI64RemU(left, right, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000475 case wasm::kExprI64Ior:
476 op = m->Word64Or();
477 break;
478 case wasm::kExprI64Xor:
479 op = m->Word64Xor();
480 break;
481 case wasm::kExprI64Shl:
482 op = m->Word64Shl();
Ben Murdochda12d292016-06-02 14:46:10 +0100483 right = MaskShiftCount64(right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000484 break;
485 case wasm::kExprI64ShrU:
486 op = m->Word64Shr();
Ben Murdochda12d292016-06-02 14:46:10 +0100487 right = MaskShiftCount64(right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000488 break;
489 case wasm::kExprI64ShrS:
490 op = m->Word64Sar();
Ben Murdochda12d292016-06-02 14:46:10 +0100491 right = MaskShiftCount64(right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000492 break;
493 case wasm::kExprI64Eq:
494 op = m->Word64Equal();
495 break;
496 case wasm::kExprI64Ne:
497 return Invert(Binop(wasm::kExprI64Eq, left, right));
498 case wasm::kExprI64LtS:
499 op = m->Int64LessThan();
500 break;
501 case wasm::kExprI64LeS:
502 op = m->Int64LessThanOrEqual();
503 break;
504 case wasm::kExprI64LtU:
505 op = m->Uint64LessThan();
506 break;
507 case wasm::kExprI64LeU:
508 op = m->Uint64LessThanOrEqual();
509 break;
510 case wasm::kExprI64GtS:
511 op = m->Int64LessThan();
512 std::swap(left, right);
513 break;
514 case wasm::kExprI64GeS:
515 op = m->Int64LessThanOrEqual();
516 std::swap(left, right);
517 break;
518 case wasm::kExprI64GtU:
519 op = m->Uint64LessThan();
520 std::swap(left, right);
521 break;
522 case wasm::kExprI64GeU:
523 op = m->Uint64LessThanOrEqual();
524 std::swap(left, right);
525 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100526 case wasm::kExprI64Ror:
527 op = m->Word64Ror();
528 right = MaskShiftCount64(right);
529 break;
530 case wasm::kExprI64Rol:
531 return BuildI64Rol(left, right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000532 case wasm::kExprF32CopySign:
533 return BuildF32CopySign(left, right);
534 case wasm::kExprF64CopySign:
535 return BuildF64CopySign(left, right);
536 case wasm::kExprF32Add:
537 op = m->Float32Add();
538 break;
539 case wasm::kExprF32Sub:
Ben Murdochc5610432016-08-08 18:44:38 +0100540 op = m->Float32SubPreserveNan();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000541 break;
542 case wasm::kExprF32Mul:
543 op = m->Float32Mul();
544 break;
545 case wasm::kExprF32Div:
546 op = m->Float32Div();
547 break;
548 case wasm::kExprF32Eq:
549 op = m->Float32Equal();
550 break;
551 case wasm::kExprF32Ne:
552 return Invert(Binop(wasm::kExprF32Eq, left, right));
553 case wasm::kExprF32Lt:
554 op = m->Float32LessThan();
555 break;
556 case wasm::kExprF32Ge:
557 op = m->Float32LessThanOrEqual();
558 std::swap(left, right);
559 break;
560 case wasm::kExprF32Gt:
561 op = m->Float32LessThan();
562 std::swap(left, right);
563 break;
564 case wasm::kExprF32Le:
565 op = m->Float32LessThanOrEqual();
566 break;
567 case wasm::kExprF64Add:
568 op = m->Float64Add();
569 break;
570 case wasm::kExprF64Sub:
Ben Murdochc5610432016-08-08 18:44:38 +0100571 op = m->Float64SubPreserveNan();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000572 break;
573 case wasm::kExprF64Mul:
574 op = m->Float64Mul();
575 break;
576 case wasm::kExprF64Div:
577 op = m->Float64Div();
578 break;
579 case wasm::kExprF64Eq:
580 op = m->Float64Equal();
581 break;
582 case wasm::kExprF64Ne:
583 return Invert(Binop(wasm::kExprF64Eq, left, right));
584 case wasm::kExprF64Lt:
585 op = m->Float64LessThan();
586 break;
587 case wasm::kExprF64Le:
588 op = m->Float64LessThanOrEqual();
589 break;
590 case wasm::kExprF64Gt:
591 op = m->Float64LessThan();
592 std::swap(left, right);
593 break;
594 case wasm::kExprF64Ge:
595 op = m->Float64LessThanOrEqual();
596 std::swap(left, right);
597 break;
598 case wasm::kExprF32Min:
599 return BuildF32Min(left, right);
600 case wasm::kExprF64Min:
601 return BuildF64Min(left, right);
602 case wasm::kExprF32Max:
603 return BuildF32Max(left, right);
604 case wasm::kExprF64Max:
605 return BuildF64Max(left, right);
Ben Murdochc5610432016-08-08 18:44:38 +0100606 case wasm::kExprF64Pow:
Ben Murdochda12d292016-06-02 14:46:10 +0100607 return BuildF64Pow(left, right);
Ben Murdochc5610432016-08-08 18:44:38 +0100608 case wasm::kExprF64Atan2:
Ben Murdoch61f157c2016-09-16 13:49:30 +0100609 op = m->Float64Atan2();
610 break;
Ben Murdochc5610432016-08-08 18:44:38 +0100611 case wasm::kExprF64Mod:
Ben Murdochda12d292016-06-02 14:46:10 +0100612 return BuildF64Mod(left, right);
Ben Murdochc5610432016-08-08 18:44:38 +0100613 case wasm::kExprI32AsmjsDivS:
614 return BuildI32AsmjsDivS(left, right);
615 case wasm::kExprI32AsmjsDivU:
616 return BuildI32AsmjsDivU(left, right);
617 case wasm::kExprI32AsmjsRemS:
618 return BuildI32AsmjsRemS(left, right);
619 case wasm::kExprI32AsmjsRemU:
620 return BuildI32AsmjsRemU(left, right);
621 case wasm::kExprI32AsmjsStoreMem8:
622 return BuildAsmjsStoreMem(MachineType::Int8(), left, right);
623 case wasm::kExprI32AsmjsStoreMem16:
624 return BuildAsmjsStoreMem(MachineType::Int16(), left, right);
625 case wasm::kExprI32AsmjsStoreMem:
626 return BuildAsmjsStoreMem(MachineType::Int32(), left, right);
627 case wasm::kExprF32AsmjsStoreMem:
628 return BuildAsmjsStoreMem(MachineType::Float32(), left, right);
629 case wasm::kExprF64AsmjsStoreMem:
630 return BuildAsmjsStoreMem(MachineType::Float64(), left, right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000631 default:
632 op = UnsupportedOpcode(opcode);
633 }
634 return graph()->NewNode(op, left, right);
635}
636
Ben Murdochc5610432016-08-08 18:44:38 +0100637Node* WasmGraphBuilder::Unop(wasm::WasmOpcode opcode, Node* input,
638 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000639 const Operator* op;
640 MachineOperatorBuilder* m = jsgraph()->machine();
641 switch (opcode) {
Ben Murdochda12d292016-06-02 14:46:10 +0100642 case wasm::kExprI32Eqz:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000643 op = m->Word32Equal();
644 return graph()->NewNode(op, input, jsgraph()->Int32Constant(0));
645 case wasm::kExprF32Abs:
646 op = m->Float32Abs();
647 break;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100648 case wasm::kExprF32Neg: {
649 if (m->Float32Neg().IsSupported()) {
650 op = m->Float32Neg().op();
651 break;
652 } else {
653 return BuildF32Neg(input);
654 }
655 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000656 case wasm::kExprF32Sqrt:
657 op = m->Float32Sqrt();
658 break;
659 case wasm::kExprF64Abs:
660 op = m->Float64Abs();
661 break;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100662 case wasm::kExprF64Neg: {
663 if (m->Float64Neg().IsSupported()) {
664 op = m->Float64Neg().op();
665 break;
666 } else {
667 return BuildF64Neg(input);
668 }
669 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000670 case wasm::kExprF64Sqrt:
671 op = m->Float64Sqrt();
672 break;
673 case wasm::kExprI32SConvertF64:
Ben Murdochc5610432016-08-08 18:44:38 +0100674 return BuildI32SConvertF64(input, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000675 case wasm::kExprI32UConvertF64:
Ben Murdochc5610432016-08-08 18:44:38 +0100676 return BuildI32UConvertF64(input, position);
677 case wasm::kExprI32AsmjsSConvertF64:
678 return BuildI32AsmjsSConvertF64(input);
679 case wasm::kExprI32AsmjsUConvertF64:
680 return BuildI32AsmjsUConvertF64(input);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000681 case wasm::kExprF32ConvertF64:
682 op = m->TruncateFloat64ToFloat32();
683 break;
684 case wasm::kExprF64SConvertI32:
685 op = m->ChangeInt32ToFloat64();
686 break;
687 case wasm::kExprF64UConvertI32:
688 op = m->ChangeUint32ToFloat64();
689 break;
690 case wasm::kExprF32SConvertI32:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100691 op = m->RoundInt32ToFloat32();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000692 break;
693 case wasm::kExprF32UConvertI32:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100694 op = m->RoundUint32ToFloat32();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000695 break;
696 case wasm::kExprI32SConvertF32:
Ben Murdochc5610432016-08-08 18:44:38 +0100697 return BuildI32SConvertF32(input, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000698 case wasm::kExprI32UConvertF32:
Ben Murdochc5610432016-08-08 18:44:38 +0100699 return BuildI32UConvertF32(input, position);
700 case wasm::kExprI32AsmjsSConvertF32:
701 return BuildI32AsmjsSConvertF32(input);
702 case wasm::kExprI32AsmjsUConvertF32:
703 return BuildI32AsmjsUConvertF32(input);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000704 case wasm::kExprF64ConvertF32:
705 op = m->ChangeFloat32ToFloat64();
706 break;
707 case wasm::kExprF32ReinterpretI32:
708 op = m->BitcastInt32ToFloat32();
709 break;
710 case wasm::kExprI32ReinterpretF32:
711 op = m->BitcastFloat32ToInt32();
712 break;
713 case wasm::kExprI32Clz:
714 op = m->Word32Clz();
715 break;
716 case wasm::kExprI32Ctz: {
717 if (m->Word32Ctz().IsSupported()) {
718 op = m->Word32Ctz().op();
719 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100720 } else if (m->Word32ReverseBits().IsSupported()) {
721 Node* reversed = graph()->NewNode(m->Word32ReverseBits().op(), input);
722 Node* result = graph()->NewNode(m->Word32Clz(), reversed);
723 return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000724 } else {
725 return BuildI32Ctz(input);
726 }
727 }
728 case wasm::kExprI32Popcnt: {
729 if (m->Word32Popcnt().IsSupported()) {
730 op = m->Word32Popcnt().op();
731 break;
732 } else {
733 return BuildI32Popcnt(input);
734 }
735 }
736 case wasm::kExprF32Floor: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100737 if (!m->Float32RoundDown().IsSupported()) return BuildF32Floor(input);
738 op = m->Float32RoundDown().op();
739 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000740 }
741 case wasm::kExprF32Ceil: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100742 if (!m->Float32RoundUp().IsSupported()) return BuildF32Ceil(input);
743 op = m->Float32RoundUp().op();
744 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000745 }
746 case wasm::kExprF32Trunc: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100747 if (!m->Float32RoundTruncate().IsSupported()) return BuildF32Trunc(input);
748 op = m->Float32RoundTruncate().op();
749 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000750 }
751 case wasm::kExprF32NearestInt: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100752 if (!m->Float32RoundTiesEven().IsSupported())
753 return BuildF32NearestInt(input);
754 op = m->Float32RoundTiesEven().op();
755 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000756 }
757 case wasm::kExprF64Floor: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100758 if (!m->Float64RoundDown().IsSupported()) return BuildF64Floor(input);
759 op = m->Float64RoundDown().op();
760 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000761 }
762 case wasm::kExprF64Ceil: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100763 if (!m->Float64RoundUp().IsSupported()) return BuildF64Ceil(input);
764 op = m->Float64RoundUp().op();
765 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000766 }
767 case wasm::kExprF64Trunc: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100768 if (!m->Float64RoundTruncate().IsSupported()) return BuildF64Trunc(input);
769 op = m->Float64RoundTruncate().op();
770 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000771 }
772 case wasm::kExprF64NearestInt: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100773 if (!m->Float64RoundTiesEven().IsSupported())
774 return BuildF64NearestInt(input);
775 op = m->Float64RoundTiesEven().op();
776 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000777 }
Ben Murdochda12d292016-06-02 14:46:10 +0100778 case wasm::kExprF64Acos: {
779 return BuildF64Acos(input);
780 }
781 case wasm::kExprF64Asin: {
782 return BuildF64Asin(input);
783 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100784 case wasm::kExprF64Atan:
785 op = m->Float64Atan();
786 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100787 case wasm::kExprF64Cos: {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100788 op = m->Float64Cos();
789 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100790 }
791 case wasm::kExprF64Sin: {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100792 op = m->Float64Sin();
793 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100794 }
795 case wasm::kExprF64Tan: {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100796 op = m->Float64Tan();
797 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100798 }
799 case wasm::kExprF64Exp: {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100800 op = m->Float64Exp();
801 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100802 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100803 case wasm::kExprF64Log:
804 op = m->Float64Log();
805 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000806 case wasm::kExprI32ConvertI64:
807 op = m->TruncateInt64ToInt32();
808 break;
809 case wasm::kExprI64SConvertI32:
810 op = m->ChangeInt32ToInt64();
811 break;
812 case wasm::kExprI64UConvertI32:
813 op = m->ChangeUint32ToUint64();
814 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000815 case wasm::kExprF64ReinterpretI64:
816 op = m->BitcastInt64ToFloat64();
817 break;
818 case wasm::kExprI64ReinterpretF64:
819 op = m->BitcastFloat64ToInt64();
820 break;
821 case wasm::kExprI64Clz:
822 op = m->Word64Clz();
823 break;
824 case wasm::kExprI64Ctz: {
825 if (m->Word64Ctz().IsSupported()) {
826 op = m->Word64Ctz().op();
827 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100828 } else if (m->Is32() && m->Word32Ctz().IsSupported()) {
829 op = m->Word64CtzPlaceholder();
830 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100831 } else if (m->Word64ReverseBits().IsSupported()) {
832 Node* reversed = graph()->NewNode(m->Word64ReverseBits().op(), input);
833 Node* result = graph()->NewNode(m->Word64Clz(), reversed);
834 return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000835 } else {
836 return BuildI64Ctz(input);
837 }
838 }
839 case wasm::kExprI64Popcnt: {
840 if (m->Word64Popcnt().IsSupported()) {
841 op = m->Word64Popcnt().op();
Ben Murdochda12d292016-06-02 14:46:10 +0100842 } else if (m->Is32() && m->Word32Popcnt().IsSupported()) {
843 op = m->Word64PopcntPlaceholder();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000844 } else {
845 return BuildI64Popcnt(input);
846 }
Ben Murdochda12d292016-06-02 14:46:10 +0100847 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000848 }
Ben Murdochda12d292016-06-02 14:46:10 +0100849 case wasm::kExprI64Eqz:
850 op = m->Word64Equal();
851 return graph()->NewNode(op, input, jsgraph()->Int64Constant(0));
852 case wasm::kExprF32SConvertI64:
853 if (m->Is32()) {
854 return BuildF32SConvertI64(input);
855 }
856 op = m->RoundInt64ToFloat32();
857 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100858 case wasm::kExprF32UConvertI64:
859 if (m->Is32()) {
860 return BuildF32UConvertI64(input);
861 }
862 op = m->RoundUint64ToFloat32();
863 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100864 case wasm::kExprF64SConvertI64:
865 if (m->Is32()) {
866 return BuildF64SConvertI64(input);
867 }
868 op = m->RoundInt64ToFloat64();
869 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100870 case wasm::kExprF64UConvertI64:
871 if (m->Is32()) {
872 return BuildF64UConvertI64(input);
873 }
874 op = m->RoundUint64ToFloat64();
875 break;
Ben Murdochc5610432016-08-08 18:44:38 +0100876 case wasm::kExprI64SConvertF32:
877 return BuildI64SConvertF32(input, position);
878 case wasm::kExprI64SConvertF64:
879 return BuildI64SConvertF64(input, position);
880 case wasm::kExprI64UConvertF32:
881 return BuildI64UConvertF32(input, position);
882 case wasm::kExprI64UConvertF64:
883 return BuildI64UConvertF64(input, position);
884 case wasm::kExprI32AsmjsLoadMem8S:
885 return BuildAsmjsLoadMem(MachineType::Int8(), input);
886 case wasm::kExprI32AsmjsLoadMem8U:
887 return BuildAsmjsLoadMem(MachineType::Uint8(), input);
888 case wasm::kExprI32AsmjsLoadMem16S:
889 return BuildAsmjsLoadMem(MachineType::Int16(), input);
890 case wasm::kExprI32AsmjsLoadMem16U:
891 return BuildAsmjsLoadMem(MachineType::Uint16(), input);
892 case wasm::kExprI32AsmjsLoadMem:
893 return BuildAsmjsLoadMem(MachineType::Int32(), input);
894 case wasm::kExprF32AsmjsLoadMem:
895 return BuildAsmjsLoadMem(MachineType::Float32(), input);
896 case wasm::kExprF64AsmjsLoadMem:
897 return BuildAsmjsLoadMem(MachineType::Float64(), input);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000898 default:
899 op = UnsupportedOpcode(opcode);
900 }
901 return graph()->NewNode(op, input);
902}
903
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000904Node* WasmGraphBuilder::Float32Constant(float value) {
905 return jsgraph()->Float32Constant(value);
906}
907
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000908Node* WasmGraphBuilder::Float64Constant(double value) {
909 return jsgraph()->Float64Constant(value);
910}
911
Ben Murdochc5610432016-08-08 18:44:38 +0100912Node* WasmGraphBuilder::HeapConstant(Handle<HeapObject> value) {
913 return jsgraph()->HeapConstant(value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000914}
915
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000916Node* WasmGraphBuilder::Branch(Node* cond, Node** true_node,
917 Node** false_node) {
918 DCHECK_NOT_NULL(cond);
919 DCHECK_NOT_NULL(*control_);
920 Node* branch =
921 graph()->NewNode(jsgraph()->common()->Branch(), cond, *control_);
922 *true_node = graph()->NewNode(jsgraph()->common()->IfTrue(), branch);
923 *false_node = graph()->NewNode(jsgraph()->common()->IfFalse(), branch);
924 return branch;
925}
926
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000927Node* WasmGraphBuilder::Switch(unsigned count, Node* key) {
928 return graph()->NewNode(jsgraph()->common()->Switch(count), key, *control_);
929}
930
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000931Node* WasmGraphBuilder::IfValue(int32_t value, Node* sw) {
932 DCHECK_EQ(IrOpcode::kSwitch, sw->opcode());
933 return graph()->NewNode(jsgraph()->common()->IfValue(value), sw);
934}
935
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000936Node* WasmGraphBuilder::IfDefault(Node* sw) {
937 DCHECK_EQ(IrOpcode::kSwitch, sw->opcode());
938 return graph()->NewNode(jsgraph()->common()->IfDefault(), sw);
939}
940
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000941Node* WasmGraphBuilder::Return(unsigned count, Node** vals) {
942 DCHECK_NOT_NULL(*control_);
943 DCHECK_NOT_NULL(*effect_);
944
945 if (count == 0) {
946 // Handle a return of void.
947 vals[0] = jsgraph()->Int32Constant(0);
948 count = 1;
949 }
950
Ben Murdochda12d292016-06-02 14:46:10 +0100951 Node** buf = Realloc(vals, count, count + 2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000952 buf[count] = *effect_;
953 buf[count + 1] = *control_;
954 Node* ret = graph()->NewNode(jsgraph()->common()->Return(), count + 2, vals);
955
956 MergeControlToEnd(jsgraph(), ret);
957 return ret;
958}
959
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000960Node* WasmGraphBuilder::ReturnVoid() { return Return(0, Buffer(0)); }
961
Ben Murdochc5610432016-08-08 18:44:38 +0100962Node* WasmGraphBuilder::Unreachable(wasm::WasmCodePosition position) {
963 trap_->Unreachable(position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000964 return nullptr;
965}
966
Ben Murdochda12d292016-06-02 14:46:10 +0100967Node* WasmGraphBuilder::MaskShiftCount32(Node* node) {
968 static const int32_t kMask32 = 0x1f;
969 if (!jsgraph()->machine()->Word32ShiftIsSafe()) {
970 // Shifts by constants are so common we pattern-match them here.
971 Int32Matcher match(node);
972 if (match.HasValue()) {
973 int32_t masked = (match.Value() & kMask32);
974 if (match.Value() != masked) node = jsgraph()->Int32Constant(masked);
975 } else {
976 node = graph()->NewNode(jsgraph()->machine()->Word32And(), node,
977 jsgraph()->Int32Constant(kMask32));
978 }
979 }
980 return node;
981}
982
983Node* WasmGraphBuilder::MaskShiftCount64(Node* node) {
984 static const int64_t kMask64 = 0x3f;
985 if (!jsgraph()->machine()->Word32ShiftIsSafe()) {
986 // Shifts by constants are so common we pattern-match them here.
987 Int64Matcher match(node);
988 if (match.HasValue()) {
989 int64_t masked = (match.Value() & kMask64);
990 if (match.Value() != masked) node = jsgraph()->Int64Constant(masked);
991 } else {
992 node = graph()->NewNode(jsgraph()->machine()->Word64And(), node,
993 jsgraph()->Int64Constant(kMask64));
994 }
995 }
996 return node;
997}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000998
999Node* WasmGraphBuilder::BuildF32Neg(Node* input) {
1000 Node* result =
1001 Unop(wasm::kExprF32ReinterpretI32,
1002 Binop(wasm::kExprI32Xor, Unop(wasm::kExprI32ReinterpretF32, input),
1003 jsgraph()->Int32Constant(0x80000000)));
1004
1005 return result;
1006}
1007
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001008Node* WasmGraphBuilder::BuildF64Neg(Node* input) {
1009#if WASM_64
1010 Node* result =
1011 Unop(wasm::kExprF64ReinterpretI64,
1012 Binop(wasm::kExprI64Xor, Unop(wasm::kExprI64ReinterpretF64, input),
1013 jsgraph()->Int64Constant(0x8000000000000000)));
1014
1015 return result;
1016#else
1017 MachineOperatorBuilder* m = jsgraph()->machine();
1018
1019 Node* old_high_word = graph()->NewNode(m->Float64ExtractHighWord32(), input);
1020 Node* new_high_word = Binop(wasm::kExprI32Xor, old_high_word,
1021 jsgraph()->Int32Constant(0x80000000));
1022
1023 return graph()->NewNode(m->Float64InsertHighWord32(), input, new_high_word);
1024#endif
1025}
1026
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001027Node* WasmGraphBuilder::BuildF32CopySign(Node* left, Node* right) {
1028 Node* result = Unop(
1029 wasm::kExprF32ReinterpretI32,
1030 Binop(wasm::kExprI32Ior,
1031 Binop(wasm::kExprI32And, Unop(wasm::kExprI32ReinterpretF32, left),
1032 jsgraph()->Int32Constant(0x7fffffff)),
1033 Binop(wasm::kExprI32And, Unop(wasm::kExprI32ReinterpretF32, right),
1034 jsgraph()->Int32Constant(0x80000000))));
1035
1036 return result;
1037}
1038
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001039Node* WasmGraphBuilder::BuildF64CopySign(Node* left, Node* right) {
1040#if WASM_64
1041 Node* result = Unop(
1042 wasm::kExprF64ReinterpretI64,
1043 Binop(wasm::kExprI64Ior,
1044 Binop(wasm::kExprI64And, Unop(wasm::kExprI64ReinterpretF64, left),
1045 jsgraph()->Int64Constant(0x7fffffffffffffff)),
1046 Binop(wasm::kExprI64And, Unop(wasm::kExprI64ReinterpretF64, right),
1047 jsgraph()->Int64Constant(0x8000000000000000))));
1048
1049 return result;
1050#else
1051 MachineOperatorBuilder* m = jsgraph()->machine();
1052
1053 Node* high_word_left = graph()->NewNode(m->Float64ExtractHighWord32(), left);
1054 Node* high_word_right =
1055 graph()->NewNode(m->Float64ExtractHighWord32(), right);
1056
1057 Node* new_high_word =
1058 Binop(wasm::kExprI32Ior, Binop(wasm::kExprI32And, high_word_left,
1059 jsgraph()->Int32Constant(0x7fffffff)),
1060 Binop(wasm::kExprI32And, high_word_right,
1061 jsgraph()->Int32Constant(0x80000000)));
1062
1063 return graph()->NewNode(m->Float64InsertHighWord32(), left, new_high_word);
1064#endif
1065}
1066
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001067Node* WasmGraphBuilder::BuildF32Min(Node* left, Node* right) {
1068 Diamond left_le_right(graph(), jsgraph()->common(),
1069 Binop(wasm::kExprF32Le, left, right));
1070
1071 Diamond right_lt_left(graph(), jsgraph()->common(),
1072 Binop(wasm::kExprF32Lt, right, left));
1073
1074 Diamond left_is_not_nan(graph(), jsgraph()->common(),
1075 Binop(wasm::kExprF32Eq, left, left));
1076
1077 return left_le_right.Phi(
1078 wasm::kAstF32, left,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001079 right_lt_left.Phi(
1080 wasm::kAstF32, right,
1081 left_is_not_nan.Phi(
1082 wasm::kAstF32,
1083 Binop(wasm::kExprF32Mul, right, Float32Constant(1.0)),
1084 Binop(wasm::kExprF32Mul, left, Float32Constant(1.0)))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001085}
1086
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001087Node* WasmGraphBuilder::BuildF32Max(Node* left, Node* right) {
1088 Diamond left_ge_right(graph(), jsgraph()->common(),
1089 Binop(wasm::kExprF32Ge, left, right));
1090
1091 Diamond right_gt_left(graph(), jsgraph()->common(),
1092 Binop(wasm::kExprF32Gt, right, left));
1093
1094 Diamond left_is_not_nan(graph(), jsgraph()->common(),
1095 Binop(wasm::kExprF32Eq, left, left));
1096
1097 return left_ge_right.Phi(
1098 wasm::kAstF32, left,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001099 right_gt_left.Phi(
1100 wasm::kAstF32, right,
1101 left_is_not_nan.Phi(
1102 wasm::kAstF32,
1103 Binop(wasm::kExprF32Mul, right, Float32Constant(1.0)),
1104 Binop(wasm::kExprF32Mul, left, Float32Constant(1.0)))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001105}
1106
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001107Node* WasmGraphBuilder::BuildF64Min(Node* left, Node* right) {
1108 Diamond left_le_right(graph(), jsgraph()->common(),
1109 Binop(wasm::kExprF64Le, left, right));
1110
1111 Diamond right_lt_left(graph(), jsgraph()->common(),
1112 Binop(wasm::kExprF64Lt, right, left));
1113
1114 Diamond left_is_not_nan(graph(), jsgraph()->common(),
1115 Binop(wasm::kExprF64Eq, left, left));
1116
1117 return left_le_right.Phi(
1118 wasm::kAstF64, left,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001119 right_lt_left.Phi(
1120 wasm::kAstF64, right,
1121 left_is_not_nan.Phi(
1122 wasm::kAstF64,
1123 Binop(wasm::kExprF64Mul, right, Float64Constant(1.0)),
1124 Binop(wasm::kExprF64Mul, left, Float64Constant(1.0)))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001125}
1126
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001127Node* WasmGraphBuilder::BuildF64Max(Node* left, Node* right) {
1128 Diamond left_ge_right(graph(), jsgraph()->common(),
1129 Binop(wasm::kExprF64Ge, left, right));
1130
1131 Diamond right_gt_left(graph(), jsgraph()->common(),
1132 Binop(wasm::kExprF64Lt, right, left));
1133
1134 Diamond left_is_not_nan(graph(), jsgraph()->common(),
1135 Binop(wasm::kExprF64Eq, left, left));
1136
1137 return left_ge_right.Phi(
1138 wasm::kAstF64, left,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001139 right_gt_left.Phi(
1140 wasm::kAstF64, right,
1141 left_is_not_nan.Phi(
1142 wasm::kAstF64,
1143 Binop(wasm::kExprF64Mul, right, Float64Constant(1.0)),
1144 Binop(wasm::kExprF64Mul, left, Float64Constant(1.0)))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001145}
1146
Ben Murdochc5610432016-08-08 18:44:38 +01001147Node* WasmGraphBuilder::BuildI32SConvertF32(Node* input,
1148 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001149 MachineOperatorBuilder* m = jsgraph()->machine();
1150 // Truncation of the input value is needed for the overflow check later.
1151 Node* trunc = Unop(wasm::kExprF32Trunc, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001152 Node* result = graph()->NewNode(m->TruncateFloat32ToInt32(), trunc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001153
1154 // Convert the result back to f64. If we end up at a different value than the
1155 // truncated input value, then there has been an overflow and we trap.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001156 Node* check = Unop(wasm::kExprF32SConvertI32, result);
1157 Node* overflow = Binop(wasm::kExprF32Ne, trunc, check);
Ben Murdochc5610432016-08-08 18:44:38 +01001158 trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001159
1160 return result;
1161}
1162
Ben Murdochc5610432016-08-08 18:44:38 +01001163Node* WasmGraphBuilder::BuildI32SConvertF64(Node* input,
1164 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001165 MachineOperatorBuilder* m = jsgraph()->machine();
1166 // Truncation of the input value is needed for the overflow check later.
1167 Node* trunc = Unop(wasm::kExprF64Trunc, input);
1168 Node* result = graph()->NewNode(m->ChangeFloat64ToInt32(), trunc);
1169
1170 // Convert the result back to f64. If we end up at a different value than the
1171 // truncated input value, then there has been an overflow and we trap.
1172 Node* check = Unop(wasm::kExprF64SConvertI32, result);
1173 Node* overflow = Binop(wasm::kExprF64Ne, trunc, check);
Ben Murdochc5610432016-08-08 18:44:38 +01001174 trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001175
1176 return result;
1177}
1178
Ben Murdochc5610432016-08-08 18:44:38 +01001179Node* WasmGraphBuilder::BuildI32UConvertF32(Node* input,
1180 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001181 MachineOperatorBuilder* m = jsgraph()->machine();
1182 // Truncation of the input value is needed for the overflow check later.
1183 Node* trunc = Unop(wasm::kExprF32Trunc, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001184 Node* result = graph()->NewNode(m->TruncateFloat32ToUint32(), trunc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001185
Ben Murdoch097c5b22016-05-18 11:27:45 +01001186 // Convert the result back to f32. If we end up at a different value than the
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001187 // truncated input value, then there has been an overflow and we trap.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001188 Node* check = Unop(wasm::kExprF32UConvertI32, result);
1189 Node* overflow = Binop(wasm::kExprF32Ne, trunc, check);
Ben Murdochc5610432016-08-08 18:44:38 +01001190 trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001191
1192 return result;
1193}
1194
Ben Murdochc5610432016-08-08 18:44:38 +01001195Node* WasmGraphBuilder::BuildI32UConvertF64(Node* input,
1196 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001197 MachineOperatorBuilder* m = jsgraph()->machine();
1198 // Truncation of the input value is needed for the overflow check later.
1199 Node* trunc = Unop(wasm::kExprF64Trunc, input);
Ben Murdochda12d292016-06-02 14:46:10 +01001200 Node* result = graph()->NewNode(m->TruncateFloat64ToUint32(), trunc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001201
1202 // Convert the result back to f64. If we end up at a different value than the
1203 // truncated input value, then there has been an overflow and we trap.
1204 Node* check = Unop(wasm::kExprF64UConvertI32, result);
1205 Node* overflow = Binop(wasm::kExprF64Ne, trunc, check);
Ben Murdochc5610432016-08-08 18:44:38 +01001206 trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001207
1208 return result;
1209}
1210
Ben Murdochc5610432016-08-08 18:44:38 +01001211Node* WasmGraphBuilder::BuildI32AsmjsSConvertF32(Node* input) {
1212 MachineOperatorBuilder* m = jsgraph()->machine();
1213 // asm.js must use the wacky JS semantics.
1214 input = graph()->NewNode(m->ChangeFloat32ToFloat64(), input);
1215 return graph()->NewNode(m->TruncateFloat64ToWord32(), input);
1216}
1217
1218Node* WasmGraphBuilder::BuildI32AsmjsSConvertF64(Node* input) {
1219 MachineOperatorBuilder* m = jsgraph()->machine();
1220 // asm.js must use the wacky JS semantics.
1221 return graph()->NewNode(m->TruncateFloat64ToWord32(), input);
1222}
1223
1224Node* WasmGraphBuilder::BuildI32AsmjsUConvertF32(Node* input) {
1225 MachineOperatorBuilder* m = jsgraph()->machine();
1226 // asm.js must use the wacky JS semantics.
1227 input = graph()->NewNode(m->ChangeFloat32ToFloat64(), input);
1228 return graph()->NewNode(m->TruncateFloat64ToWord32(), input);
1229}
1230
1231Node* WasmGraphBuilder::BuildI32AsmjsUConvertF64(Node* input) {
1232 MachineOperatorBuilder* m = jsgraph()->machine();
1233 // asm.js must use the wacky JS semantics.
1234 return graph()->NewNode(m->TruncateFloat64ToWord32(), input);
1235}
1236
1237Node* WasmGraphBuilder::BuildBitCountingCall(Node* input, ExternalReference ref,
1238 MachineRepresentation input_type) {
1239 Node* stack_slot_param =
1240 graph()->NewNode(jsgraph()->machine()->StackSlot(input_type));
1241
1242 const Operator* store_op = jsgraph()->machine()->Store(
1243 StoreRepresentation(input_type, kNoWriteBarrier));
1244 *effect_ =
1245 graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0),
1246 input, *effect_, *control_);
1247
1248 MachineSignature::Builder sig_builder(jsgraph()->zone(), 1, 1);
1249 sig_builder.AddReturn(MachineType::Int32());
1250 sig_builder.AddParam(MachineType::Pointer());
1251
1252 Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
1253 Node* args[] = {function, stack_slot_param};
1254
1255 return BuildCCall(sig_builder.Build(), args);
1256}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001257
1258Node* WasmGraphBuilder::BuildI32Ctz(Node* input) {
Ben Murdochc5610432016-08-08 18:44:38 +01001259 return BuildBitCountingCall(
1260 input, ExternalReference::wasm_word32_ctz(jsgraph()->isolate()),
1261 MachineRepresentation::kWord32);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001262}
1263
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001264Node* WasmGraphBuilder::BuildI64Ctz(Node* input) {
Ben Murdochc5610432016-08-08 18:44:38 +01001265 return Unop(wasm::kExprI64UConvertI32,
1266 BuildBitCountingCall(input, ExternalReference::wasm_word64_ctz(
1267 jsgraph()->isolate()),
1268 MachineRepresentation::kWord64));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001269}
1270
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001271Node* WasmGraphBuilder::BuildI32Popcnt(Node* input) {
Ben Murdochc5610432016-08-08 18:44:38 +01001272 return BuildBitCountingCall(
1273 input, ExternalReference::wasm_word32_popcnt(jsgraph()->isolate()),
1274 MachineRepresentation::kWord32);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001275}
1276
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001277Node* WasmGraphBuilder::BuildI64Popcnt(Node* input) {
Ben Murdochc5610432016-08-08 18:44:38 +01001278 return Unop(wasm::kExprI64UConvertI32,
1279 BuildBitCountingCall(input, ExternalReference::wasm_word64_popcnt(
1280 jsgraph()->isolate()),
1281 MachineRepresentation::kWord64));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001282}
1283
Ben Murdoch097c5b22016-05-18 11:27:45 +01001284Node* WasmGraphBuilder::BuildF32Trunc(Node* input) {
1285 MachineType type = MachineType::Float32();
1286 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001287 ExternalReference::wasm_f32_trunc(jsgraph()->isolate());
1288
1289 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001290}
1291
1292Node* WasmGraphBuilder::BuildF32Floor(Node* input) {
1293 MachineType type = MachineType::Float32();
1294 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001295 ExternalReference::wasm_f32_floor(jsgraph()->isolate());
1296 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001297}
1298
1299Node* WasmGraphBuilder::BuildF32Ceil(Node* input) {
1300 MachineType type = MachineType::Float32();
1301 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001302 ExternalReference::wasm_f32_ceil(jsgraph()->isolate());
1303 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001304}
1305
1306Node* WasmGraphBuilder::BuildF32NearestInt(Node* input) {
1307 MachineType type = MachineType::Float32();
1308 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001309 ExternalReference::wasm_f32_nearest_int(jsgraph()->isolate());
1310 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001311}
1312
1313Node* WasmGraphBuilder::BuildF64Trunc(Node* input) {
1314 MachineType type = MachineType::Float64();
1315 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001316 ExternalReference::wasm_f64_trunc(jsgraph()->isolate());
1317 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001318}
1319
1320Node* WasmGraphBuilder::BuildF64Floor(Node* input) {
1321 MachineType type = MachineType::Float64();
1322 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001323 ExternalReference::wasm_f64_floor(jsgraph()->isolate());
1324 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001325}
1326
1327Node* WasmGraphBuilder::BuildF64Ceil(Node* input) {
1328 MachineType type = MachineType::Float64();
1329 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001330 ExternalReference::wasm_f64_ceil(jsgraph()->isolate());
1331 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001332}
1333
1334Node* WasmGraphBuilder::BuildF64NearestInt(Node* input) {
1335 MachineType type = MachineType::Float64();
1336 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001337 ExternalReference::wasm_f64_nearest_int(jsgraph()->isolate());
1338 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001339}
1340
Ben Murdochda12d292016-06-02 14:46:10 +01001341Node* WasmGraphBuilder::BuildF64Acos(Node* input) {
1342 MachineType type = MachineType::Float64();
1343 ExternalReference ref =
1344 ExternalReference::f64_acos_wrapper_function(jsgraph()->isolate());
1345 return BuildCFuncInstruction(ref, type, input);
1346}
Ben Murdoch097c5b22016-05-18 11:27:45 +01001347
Ben Murdochda12d292016-06-02 14:46:10 +01001348Node* WasmGraphBuilder::BuildF64Asin(Node* input) {
1349 MachineType type = MachineType::Float64();
1350 ExternalReference ref =
1351 ExternalReference::f64_asin_wrapper_function(jsgraph()->isolate());
1352 return BuildCFuncInstruction(ref, type, input);
1353}
1354
Ben Murdochda12d292016-06-02 14:46:10 +01001355Node* WasmGraphBuilder::BuildF64Pow(Node* left, Node* right) {
1356 MachineType type = MachineType::Float64();
1357 ExternalReference ref =
1358 ExternalReference::f64_pow_wrapper_function(jsgraph()->isolate());
1359 return BuildCFuncInstruction(ref, type, left, right);
1360}
1361
1362Node* WasmGraphBuilder::BuildF64Mod(Node* left, Node* right) {
1363 MachineType type = MachineType::Float64();
1364 ExternalReference ref =
1365 ExternalReference::f64_mod_wrapper_function(jsgraph()->isolate());
1366 return BuildCFuncInstruction(ref, type, left, right);
1367}
1368
1369Node* WasmGraphBuilder::BuildCFuncInstruction(ExternalReference ref,
1370 MachineType type, Node* input0,
1371 Node* input1) {
1372 // We do truncation by calling a C function which calculates the result.
1373 // The input is passed to the C function as a double*'s to avoid double
1374 // parameters. For this we reserve slots on the stack, store the parameters
1375 // in those slots, pass pointers to the slot to the C function,
1376 // and after calling the C function we collect the return value from
1377 // the stack slot.
1378
1379 Node* stack_slot_param0 =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001380 graph()->NewNode(jsgraph()->machine()->StackSlot(type.representation()));
1381
Ben Murdochda12d292016-06-02 14:46:10 +01001382 const Operator* store_op0 = jsgraph()->machine()->Store(
Ben Murdoch097c5b22016-05-18 11:27:45 +01001383 StoreRepresentation(type.representation(), kNoWriteBarrier));
Ben Murdochda12d292016-06-02 14:46:10 +01001384 *effect_ = graph()->NewNode(store_op0, stack_slot_param0,
1385 jsgraph()->Int32Constant(0), input0, *effect_,
1386 *control_);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001387
Ben Murdoch097c5b22016-05-18 11:27:45 +01001388 Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
Ben Murdochda12d292016-06-02 14:46:10 +01001389 Node** args = Buffer(5);
1390 args[0] = function;
1391 args[1] = stack_slot_param0;
1392 int input_count = 1;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001393
Ben Murdochda12d292016-06-02 14:46:10 +01001394 if (input1 != nullptr) {
1395 Node* stack_slot_param1 = graph()->NewNode(
1396 jsgraph()->machine()->StackSlot(type.representation()));
1397 const Operator* store_op1 = jsgraph()->machine()->Store(
1398 StoreRepresentation(type.representation(), kNoWriteBarrier));
1399 *effect_ = graph()->NewNode(store_op1, stack_slot_param1,
1400 jsgraph()->Int32Constant(0), input1, *effect_,
1401 *control_);
1402 args[2] = stack_slot_param1;
1403 ++input_count;
1404 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001405
Ben Murdochda12d292016-06-02 14:46:10 +01001406 Signature<MachineType>::Builder sig_builder(jsgraph()->zone(), 0,
1407 input_count);
1408 sig_builder.AddParam(MachineType::Pointer());
1409 if (input1 != nullptr) {
1410 sig_builder.AddParam(MachineType::Pointer());
1411 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001412 BuildCCall(sig_builder.Build(), args);
1413
1414 const Operator* load_op = jsgraph()->machine()->Load(type);
1415
1416 Node* load =
Ben Murdochda12d292016-06-02 14:46:10 +01001417 graph()->NewNode(load_op, stack_slot_param0, jsgraph()->Int32Constant(0),
1418 *effect_, *control_);
1419 *effect_ = load;
1420 return load;
1421}
1422
1423Node* WasmGraphBuilder::BuildF32SConvertI64(Node* input) {
1424 // TODO(titzer/bradnelson): Check handlng of asm.js case.
1425 return BuildIntToFloatConversionInstruction(
1426 input, ExternalReference::wasm_int64_to_float32(jsgraph()->isolate()),
1427 MachineRepresentation::kWord64, MachineType::Float32());
1428}
1429Node* WasmGraphBuilder::BuildF32UConvertI64(Node* input) {
1430 // TODO(titzer/bradnelson): Check handlng of asm.js case.
1431 return BuildIntToFloatConversionInstruction(
1432 input, ExternalReference::wasm_uint64_to_float32(jsgraph()->isolate()),
1433 MachineRepresentation::kWord64, MachineType::Float32());
1434}
1435Node* WasmGraphBuilder::BuildF64SConvertI64(Node* input) {
1436 return BuildIntToFloatConversionInstruction(
1437 input, ExternalReference::wasm_int64_to_float64(jsgraph()->isolate()),
1438 MachineRepresentation::kWord64, MachineType::Float64());
1439}
1440Node* WasmGraphBuilder::BuildF64UConvertI64(Node* input) {
1441 return BuildIntToFloatConversionInstruction(
1442 input, ExternalReference::wasm_uint64_to_float64(jsgraph()->isolate()),
1443 MachineRepresentation::kWord64, MachineType::Float64());
1444}
1445
1446Node* WasmGraphBuilder::BuildIntToFloatConversionInstruction(
1447 Node* input, ExternalReference ref,
1448 MachineRepresentation parameter_representation,
1449 const MachineType result_type) {
1450 Node* stack_slot_param = graph()->NewNode(
1451 jsgraph()->machine()->StackSlot(parameter_representation));
1452 Node* stack_slot_result = graph()->NewNode(
1453 jsgraph()->machine()->StackSlot(result_type.representation()));
1454 const Operator* store_op = jsgraph()->machine()->Store(
1455 StoreRepresentation(parameter_representation, kNoWriteBarrier));
1456 *effect_ =
1457 graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0),
1458 input, *effect_, *control_);
1459 MachineSignature::Builder sig_builder(jsgraph()->zone(), 0, 2);
1460 sig_builder.AddParam(MachineType::Pointer());
1461 sig_builder.AddParam(MachineType::Pointer());
1462 Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
1463 Node* args[] = {function, stack_slot_param, stack_slot_result};
1464 BuildCCall(sig_builder.Build(), args);
1465 const Operator* load_op = jsgraph()->machine()->Load(result_type);
1466 Node* load =
1467 graph()->NewNode(load_op, stack_slot_result, jsgraph()->Int32Constant(0),
1468 *effect_, *control_);
1469 *effect_ = load;
1470 return load;
1471}
1472
Ben Murdochc5610432016-08-08 18:44:38 +01001473Node* WasmGraphBuilder::BuildI64SConvertF32(Node* input,
1474 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001475 if (jsgraph()->machine()->Is32()) {
1476 return BuildFloatToIntConversionInstruction(
1477 input, ExternalReference::wasm_float32_to_int64(jsgraph()->isolate()),
Ben Murdochc5610432016-08-08 18:44:38 +01001478 MachineRepresentation::kFloat32, MachineType::Int64(), position);
Ben Murdochda12d292016-06-02 14:46:10 +01001479 } else {
1480 Node* trunc = graph()->NewNode(
1481 jsgraph()->machine()->TryTruncateFloat32ToInt64(), input);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001482 Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc,
1483 graph()->start());
1484 Node* overflow = graph()->NewNode(jsgraph()->common()->Projection(1), trunc,
1485 graph()->start());
Ben Murdochc5610432016-08-08 18:44:38 +01001486 trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001487 return result;
1488 }
1489}
1490
Ben Murdochc5610432016-08-08 18:44:38 +01001491Node* WasmGraphBuilder::BuildI64UConvertF32(Node* input,
1492 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001493 if (jsgraph()->machine()->Is32()) {
1494 return BuildFloatToIntConversionInstruction(
1495 input, ExternalReference::wasm_float32_to_uint64(jsgraph()->isolate()),
Ben Murdochc5610432016-08-08 18:44:38 +01001496 MachineRepresentation::kFloat32, MachineType::Int64(), position);
Ben Murdochda12d292016-06-02 14:46:10 +01001497 } else {
1498 Node* trunc = graph()->NewNode(
1499 jsgraph()->machine()->TryTruncateFloat32ToUint64(), input);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001500 Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc,
1501 graph()->start());
1502 Node* overflow = graph()->NewNode(jsgraph()->common()->Projection(1), trunc,
1503 graph()->start());
Ben Murdochc5610432016-08-08 18:44:38 +01001504 trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001505 return result;
1506 }
1507}
1508
Ben Murdochc5610432016-08-08 18:44:38 +01001509Node* WasmGraphBuilder::BuildI64SConvertF64(Node* input,
1510 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001511 if (jsgraph()->machine()->Is32()) {
1512 return BuildFloatToIntConversionInstruction(
1513 input, ExternalReference::wasm_float64_to_int64(jsgraph()->isolate()),
Ben Murdochc5610432016-08-08 18:44:38 +01001514 MachineRepresentation::kFloat64, MachineType::Int64(), position);
Ben Murdochda12d292016-06-02 14:46:10 +01001515 } else {
1516 Node* trunc = graph()->NewNode(
1517 jsgraph()->machine()->TryTruncateFloat64ToInt64(), input);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001518 Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc,
1519 graph()->start());
1520 Node* overflow = graph()->NewNode(jsgraph()->common()->Projection(1), trunc,
1521 graph()->start());
Ben Murdochc5610432016-08-08 18:44:38 +01001522 trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001523 return result;
1524 }
1525}
1526
Ben Murdochc5610432016-08-08 18:44:38 +01001527Node* WasmGraphBuilder::BuildI64UConvertF64(Node* input,
1528 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001529 if (jsgraph()->machine()->Is32()) {
1530 return BuildFloatToIntConversionInstruction(
1531 input, ExternalReference::wasm_float64_to_uint64(jsgraph()->isolate()),
Ben Murdochc5610432016-08-08 18:44:38 +01001532 MachineRepresentation::kFloat64, MachineType::Int64(), position);
Ben Murdochda12d292016-06-02 14:46:10 +01001533 } else {
1534 Node* trunc = graph()->NewNode(
1535 jsgraph()->machine()->TryTruncateFloat64ToUint64(), input);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001536 Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc,
1537 graph()->start());
1538 Node* overflow = graph()->NewNode(jsgraph()->common()->Projection(1), trunc,
1539 graph()->start());
Ben Murdochc5610432016-08-08 18:44:38 +01001540 trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001541 return result;
1542 }
1543}
1544
1545Node* WasmGraphBuilder::BuildFloatToIntConversionInstruction(
1546 Node* input, ExternalReference ref,
1547 MachineRepresentation parameter_representation,
Ben Murdochc5610432016-08-08 18:44:38 +01001548 const MachineType result_type, wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001549 Node* stack_slot_param = graph()->NewNode(
1550 jsgraph()->machine()->StackSlot(parameter_representation));
1551 Node* stack_slot_result = graph()->NewNode(
1552 jsgraph()->machine()->StackSlot(result_type.representation()));
1553 const Operator* store_op = jsgraph()->machine()->Store(
1554 StoreRepresentation(parameter_representation, kNoWriteBarrier));
1555 *effect_ =
1556 graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0),
1557 input, *effect_, *control_);
1558 MachineSignature::Builder sig_builder(jsgraph()->zone(), 1, 2);
1559 sig_builder.AddReturn(MachineType::Int32());
1560 sig_builder.AddParam(MachineType::Pointer());
1561 sig_builder.AddParam(MachineType::Pointer());
1562 Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
1563 Node* args[] = {function, stack_slot_param, stack_slot_result};
1564 trap_->ZeroCheck32(wasm::kTrapFloatUnrepresentable,
Ben Murdochc5610432016-08-08 18:44:38 +01001565 BuildCCall(sig_builder.Build(), args), position);
Ben Murdochda12d292016-06-02 14:46:10 +01001566 const Operator* load_op = jsgraph()->machine()->Load(result_type);
1567 Node* load =
1568 graph()->NewNode(load_op, stack_slot_result, jsgraph()->Int32Constant(0),
1569 *effect_, *control_);
1570 *effect_ = load;
1571 return load;
1572}
1573
Ben Murdochc5610432016-08-08 18:44:38 +01001574Node* WasmGraphBuilder::BuildI32DivS(Node* left, Node* right,
1575 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001576 MachineOperatorBuilder* m = jsgraph()->machine();
Ben Murdochc5610432016-08-08 18:44:38 +01001577 trap_->ZeroCheck32(wasm::kTrapDivByZero, right, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001578 Node* before = *control_;
1579 Node* denom_is_m1;
1580 Node* denom_is_not_m1;
1581 Branch(
1582 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
1583 &denom_is_m1, &denom_is_not_m1);
1584 *control_ = denom_is_m1;
Ben Murdochc5610432016-08-08 18:44:38 +01001585 trap_->TrapIfEq32(wasm::kTrapDivUnrepresentable, left, kMinInt, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001586 if (*control_ != denom_is_m1) {
1587 *control_ = graph()->NewNode(jsgraph()->common()->Merge(2), denom_is_not_m1,
1588 *control_);
1589 } else {
1590 *control_ = before;
1591 }
1592 return graph()->NewNode(m->Int32Div(), left, right, *control_);
1593}
1594
Ben Murdochc5610432016-08-08 18:44:38 +01001595Node* WasmGraphBuilder::BuildI32RemS(Node* left, Node* right,
1596 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001597 MachineOperatorBuilder* m = jsgraph()->machine();
Ben Murdochda12d292016-06-02 14:46:10 +01001598
Ben Murdochc5610432016-08-08 18:44:38 +01001599 trap_->ZeroCheck32(wasm::kTrapRemByZero, right, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001600
1601 Diamond d(
1602 graph(), jsgraph()->common(),
1603 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
1604 BranchHint::kFalse);
1605 d.Chain(*control_);
1606
1607 return d.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
1608 graph()->NewNode(m->Int32Mod(), left, right, d.if_false));
1609}
1610
Ben Murdochc5610432016-08-08 18:44:38 +01001611Node* WasmGraphBuilder::BuildI32DivU(Node* left, Node* right,
1612 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001613 MachineOperatorBuilder* m = jsgraph()->machine();
Ben Murdochc5610432016-08-08 18:44:38 +01001614 return graph()->NewNode(
1615 m->Uint32Div(), left, right,
1616 trap_->ZeroCheck32(wasm::kTrapDivByZero, right, position));
Ben Murdochda12d292016-06-02 14:46:10 +01001617}
1618
Ben Murdochc5610432016-08-08 18:44:38 +01001619Node* WasmGraphBuilder::BuildI32RemU(Node* left, Node* right,
1620 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001621 MachineOperatorBuilder* m = jsgraph()->machine();
Ben Murdochc5610432016-08-08 18:44:38 +01001622 return graph()->NewNode(
1623 m->Uint32Mod(), left, right,
1624 trap_->ZeroCheck32(wasm::kTrapRemByZero, right, position));
Ben Murdochda12d292016-06-02 14:46:10 +01001625}
1626
Ben Murdochc5610432016-08-08 18:44:38 +01001627Node* WasmGraphBuilder::BuildI32AsmjsDivS(Node* left, Node* right) {
1628 MachineOperatorBuilder* m = jsgraph()->machine();
1629 // asm.js semantics return 0 on divide or mod by zero.
1630 if (m->Int32DivIsSafe()) {
1631 // The hardware instruction does the right thing (e.g. arm).
1632 return graph()->NewNode(m->Int32Div(), left, right, graph()->start());
1633 }
1634
1635 // Check denominator for zero.
1636 Diamond z(
1637 graph(), jsgraph()->common(),
1638 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
1639 BranchHint::kFalse);
1640
1641 // Check numerator for -1. (avoid minint / -1 case).
1642 Diamond n(
1643 graph(), jsgraph()->common(),
1644 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
1645 BranchHint::kFalse);
1646
1647 Node* div = graph()->NewNode(m->Int32Div(), left, right, z.if_false);
1648 Node* neg =
1649 graph()->NewNode(m->Int32Sub(), jsgraph()->Int32Constant(0), left);
1650
1651 return n.Phi(
1652 MachineRepresentation::kWord32, neg,
1653 z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0), div));
1654}
1655
1656Node* WasmGraphBuilder::BuildI32AsmjsRemS(Node* left, Node* right) {
1657 MachineOperatorBuilder* m = jsgraph()->machine();
1658 // asm.js semantics return 0 on divide or mod by zero.
1659 // Explicit check for x % 0.
1660 Diamond z(
1661 graph(), jsgraph()->common(),
1662 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
1663 BranchHint::kFalse);
1664
1665 // Explicit check for x % -1.
1666 Diamond d(
1667 graph(), jsgraph()->common(),
1668 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
1669 BranchHint::kFalse);
1670 d.Chain(z.if_false);
1671
1672 return z.Phi(
1673 MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
1674 d.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
1675 graph()->NewNode(m->Int32Mod(), left, right, d.if_false)));
1676}
1677
1678Node* WasmGraphBuilder::BuildI32AsmjsDivU(Node* left, Node* right) {
1679 MachineOperatorBuilder* m = jsgraph()->machine();
1680 // asm.js semantics return 0 on divide or mod by zero.
1681 if (m->Uint32DivIsSafe()) {
1682 // The hardware instruction does the right thing (e.g. arm).
1683 return graph()->NewNode(m->Uint32Div(), left, right, graph()->start());
1684 }
1685
1686 // Explicit check for x % 0.
1687 Diamond z(
1688 graph(), jsgraph()->common(),
1689 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
1690 BranchHint::kFalse);
1691
1692 return z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
1693 graph()->NewNode(jsgraph()->machine()->Uint32Div(), left, right,
1694 z.if_false));
1695}
1696
1697Node* WasmGraphBuilder::BuildI32AsmjsRemU(Node* left, Node* right) {
1698 MachineOperatorBuilder* m = jsgraph()->machine();
1699 // asm.js semantics return 0 on divide or mod by zero.
1700 // Explicit check for x % 0.
1701 Diamond z(
1702 graph(), jsgraph()->common(),
1703 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
1704 BranchHint::kFalse);
1705
1706 Node* rem = graph()->NewNode(jsgraph()->machine()->Uint32Mod(), left, right,
1707 z.if_false);
1708 return z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
1709 rem);
1710}
1711
1712Node* WasmGraphBuilder::BuildI64DivS(Node* left, Node* right,
1713 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001714 if (jsgraph()->machine()->Is32()) {
1715 return BuildDiv64Call(
1716 left, right, ExternalReference::wasm_int64_div(jsgraph()->isolate()),
Ben Murdochc5610432016-08-08 18:44:38 +01001717 MachineType::Int64(), wasm::kTrapDivByZero, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001718 }
Ben Murdochc5610432016-08-08 18:44:38 +01001719 trap_->ZeroCheck64(wasm::kTrapDivByZero, right, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001720 Node* before = *control_;
1721 Node* denom_is_m1;
1722 Node* denom_is_not_m1;
1723 Branch(graph()->NewNode(jsgraph()->machine()->Word64Equal(), right,
1724 jsgraph()->Int64Constant(-1)),
1725 &denom_is_m1, &denom_is_not_m1);
1726 *control_ = denom_is_m1;
1727 trap_->TrapIfEq64(wasm::kTrapDivUnrepresentable, left,
Ben Murdochc5610432016-08-08 18:44:38 +01001728 std::numeric_limits<int64_t>::min(), position);
Ben Murdochda12d292016-06-02 14:46:10 +01001729 if (*control_ != denom_is_m1) {
1730 *control_ = graph()->NewNode(jsgraph()->common()->Merge(2), denom_is_not_m1,
1731 *control_);
1732 } else {
1733 *control_ = before;
1734 }
1735 return graph()->NewNode(jsgraph()->machine()->Int64Div(), left, right,
1736 *control_);
1737}
1738
Ben Murdochc5610432016-08-08 18:44:38 +01001739Node* WasmGraphBuilder::BuildI64RemS(Node* left, Node* right,
1740 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001741 if (jsgraph()->machine()->Is32()) {
1742 return BuildDiv64Call(
1743 left, right, ExternalReference::wasm_int64_mod(jsgraph()->isolate()),
Ben Murdochc5610432016-08-08 18:44:38 +01001744 MachineType::Int64(), wasm::kTrapRemByZero, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001745 }
Ben Murdochc5610432016-08-08 18:44:38 +01001746 trap_->ZeroCheck64(wasm::kTrapRemByZero, right, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001747 Diamond d(jsgraph()->graph(), jsgraph()->common(),
1748 graph()->NewNode(jsgraph()->machine()->Word64Equal(), right,
1749 jsgraph()->Int64Constant(-1)));
1750
1751 Node* rem = graph()->NewNode(jsgraph()->machine()->Int64Mod(), left, right,
1752 d.if_false);
1753
1754 return d.Phi(MachineRepresentation::kWord64, jsgraph()->Int64Constant(0),
1755 rem);
1756}
1757
Ben Murdochc5610432016-08-08 18:44:38 +01001758Node* WasmGraphBuilder::BuildI64DivU(Node* left, Node* right,
1759 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001760 if (jsgraph()->machine()->Is32()) {
1761 return BuildDiv64Call(
1762 left, right, ExternalReference::wasm_uint64_div(jsgraph()->isolate()),
Ben Murdochc5610432016-08-08 18:44:38 +01001763 MachineType::Int64(), wasm::kTrapDivByZero, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001764 }
Ben Murdochc5610432016-08-08 18:44:38 +01001765 return graph()->NewNode(
1766 jsgraph()->machine()->Uint64Div(), left, right,
1767 trap_->ZeroCheck64(wasm::kTrapDivByZero, right, position));
Ben Murdochda12d292016-06-02 14:46:10 +01001768}
Ben Murdochc5610432016-08-08 18:44:38 +01001769Node* WasmGraphBuilder::BuildI64RemU(Node* left, Node* right,
1770 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001771 if (jsgraph()->machine()->Is32()) {
1772 return BuildDiv64Call(
1773 left, right, ExternalReference::wasm_uint64_mod(jsgraph()->isolate()),
Ben Murdochc5610432016-08-08 18:44:38 +01001774 MachineType::Int64(), wasm::kTrapRemByZero, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001775 }
Ben Murdochc5610432016-08-08 18:44:38 +01001776 return graph()->NewNode(
1777 jsgraph()->machine()->Uint64Mod(), left, right,
1778 trap_->ZeroCheck64(wasm::kTrapRemByZero, right, position));
Ben Murdochda12d292016-06-02 14:46:10 +01001779}
1780
1781Node* WasmGraphBuilder::BuildDiv64Call(Node* left, Node* right,
1782 ExternalReference ref,
Ben Murdochc5610432016-08-08 18:44:38 +01001783 MachineType result_type, int trap_zero,
1784 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001785 Node* stack_slot_dst = graph()->NewNode(
1786 jsgraph()->machine()->StackSlot(MachineRepresentation::kWord64));
1787 Node* stack_slot_src = graph()->NewNode(
1788 jsgraph()->machine()->StackSlot(MachineRepresentation::kWord64));
1789
1790 const Operator* store_op = jsgraph()->machine()->Store(
1791 StoreRepresentation(MachineRepresentation::kWord64, kNoWriteBarrier));
1792 *effect_ =
1793 graph()->NewNode(store_op, stack_slot_dst, jsgraph()->Int32Constant(0),
1794 left, *effect_, *control_);
1795 *effect_ =
1796 graph()->NewNode(store_op, stack_slot_src, jsgraph()->Int32Constant(0),
1797 right, *effect_, *control_);
1798
1799 MachineSignature::Builder sig_builder(jsgraph()->zone(), 1, 2);
1800 sig_builder.AddReturn(MachineType::Int32());
1801 sig_builder.AddParam(MachineType::Pointer());
1802 sig_builder.AddParam(MachineType::Pointer());
1803
1804 Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
1805 Node* args[] = {function, stack_slot_dst, stack_slot_src};
1806
1807 Node* call = BuildCCall(sig_builder.Build(), args);
1808
1809 // TODO(wasm): This can get simpler if we have a specialized runtime call to
1810 // throw WASM exceptions by trap code instead of by string.
Ben Murdochc5610432016-08-08 18:44:38 +01001811 trap_->ZeroCheck32(static_cast<wasm::TrapReason>(trap_zero), call, position);
1812 trap_->TrapIfEq32(wasm::kTrapDivUnrepresentable, call, -1, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001813 const Operator* load_op = jsgraph()->machine()->Load(result_type);
1814 Node* load =
1815 graph()->NewNode(load_op, stack_slot_dst, jsgraph()->Int32Constant(0),
Ben Murdoch097c5b22016-05-18 11:27:45 +01001816 *effect_, *control_);
1817 *effect_ = load;
1818 return load;
1819}
1820
1821Node* WasmGraphBuilder::BuildCCall(MachineSignature* sig, Node** args) {
1822 const size_t params = sig->parameter_count();
1823 const size_t extra = 2; // effect and control inputs.
1824 const size_t count = 1 + params + extra;
1825
1826 // Reallocate the buffer to make space for extra inputs.
Ben Murdochda12d292016-06-02 14:46:10 +01001827 args = Realloc(args, 1 + params, count);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001828
1829 // Add effect and control inputs.
1830 args[params + 1] = *effect_;
1831 args[params + 2] = *control_;
1832
1833 CallDescriptor* desc =
1834 Linkage::GetSimplifiedCDescriptor(jsgraph()->zone(), sig);
1835
1836 const Operator* op = jsgraph()->common()->Call(desc);
1837 Node* call = graph()->NewNode(op, static_cast<int>(count), args);
1838 *effect_ = call;
1839 return call;
1840}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001841
Ben Murdochc5610432016-08-08 18:44:38 +01001842Node* WasmGraphBuilder::BuildWasmCall(wasm::FunctionSig* sig, Node** args,
1843 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001844 const size_t params = sig->parameter_count();
1845 const size_t extra = 2; // effect and control inputs.
1846 const size_t count = 1 + params + extra;
1847
1848 // Reallocate the buffer to make space for extra inputs.
Ben Murdochda12d292016-06-02 14:46:10 +01001849 args = Realloc(args, 1 + params, count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001850
1851 // Add effect and control inputs.
1852 args[params + 1] = *effect_;
1853 args[params + 2] = *control_;
1854
Ben Murdoch097c5b22016-05-18 11:27:45 +01001855 CallDescriptor* descriptor =
1856 wasm::ModuleEnv::GetWasmCallDescriptor(jsgraph()->zone(), sig);
1857 const Operator* op = jsgraph()->common()->Call(descriptor);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001858 Node* call = graph()->NewNode(op, static_cast<int>(count), args);
Ben Murdochc5610432016-08-08 18:44:38 +01001859 SetSourcePosition(call, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001860
1861 *effect_ = call;
1862 return call;
1863}
1864
Ben Murdochc5610432016-08-08 18:44:38 +01001865Node* WasmGraphBuilder::CallDirect(uint32_t index, Node** args,
1866 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001867 DCHECK_NULL(args[0]);
1868
1869 // Add code object as constant.
Ben Murdoch61f157c2016-09-16 13:49:30 +01001870 args[0] = HeapConstant(module_->GetCodeOrPlaceholder(index));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001871 wasm::FunctionSig* sig = module_->GetFunctionSignature(index);
1872
Ben Murdochc5610432016-08-08 18:44:38 +01001873 return BuildWasmCall(sig, args, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001874}
1875
Ben Murdochc5610432016-08-08 18:44:38 +01001876Node* WasmGraphBuilder::CallImport(uint32_t index, Node** args,
1877 wasm::WasmCodePosition position) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001878 DCHECK_NULL(args[0]);
1879
1880 // Add code object as constant.
Ben Murdochc5610432016-08-08 18:44:38 +01001881 args[0] = HeapConstant(module_->GetImportCode(index));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001882 wasm::FunctionSig* sig = module_->GetImportSignature(index);
1883
Ben Murdochc5610432016-08-08 18:44:38 +01001884 return BuildWasmCall(sig, args, position);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001885}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001886
Ben Murdochc5610432016-08-08 18:44:38 +01001887Node* WasmGraphBuilder::CallIndirect(uint32_t index, Node** args,
1888 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001889 DCHECK_NOT_NULL(args[0]);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001890 DCHECK(module_ && module_->instance);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001891
1892 MachineOperatorBuilder* machine = jsgraph()->machine();
1893
1894 // Compute the code object by loading it from the function table.
1895 Node* key = args[0];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001896
1897 // Bounds check the index.
1898 int table_size = static_cast<int>(module_->FunctionTableSize());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001899 if (table_size > 0) {
1900 // Bounds check against the table size.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001901 Node* size = Int32Constant(static_cast<int>(table_size));
1902 Node* in_bounds = graph()->NewNode(machine->Uint32LessThan(), key, size);
Ben Murdochc5610432016-08-08 18:44:38 +01001903 trap_->AddTrapIfFalse(wasm::kTrapFuncInvalid, in_bounds, position);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001904 } else {
1905 // No function table. Generate a trap and return a constant.
Ben Murdochc5610432016-08-08 18:44:38 +01001906 trap_->AddTrapIfFalse(wasm::kTrapFuncInvalid, Int32Constant(0), position);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001907 return trap_->GetTrapValue(module_->GetSignature(index));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001908 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001909 Node* table = FunctionTable();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001910
1911 // Load signature from the table and check.
1912 // The table is a FixedArray; signatures are encoded as SMIs.
1913 // [sig1, sig2, sig3, ...., code1, code2, code3 ...]
1914 ElementAccess access = AccessBuilder::ForFixedArrayElement();
1915 const int fixed_offset = access.header_size - access.tag();
1916 {
1917 Node* load_sig = graph()->NewNode(
1918 machine->Load(MachineType::AnyTagged()), table,
1919 graph()->NewNode(machine->Int32Add(),
1920 graph()->NewNode(machine->Word32Shl(), key,
1921 Int32Constant(kPointerSizeLog2)),
1922 Int32Constant(fixed_offset)),
1923 *effect_, *control_);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001924 Node* sig_match =
1925 graph()->NewNode(machine->Word32Equal(),
1926 BuildChangeSmiToInt32(load_sig), Int32Constant(index));
Ben Murdochc5610432016-08-08 18:44:38 +01001927 trap_->AddTrapIfFalse(wasm::kTrapFuncSigMismatch, sig_match, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001928 }
1929
1930 // Load code object from the table.
1931 int offset = fixed_offset + kPointerSize * table_size;
1932 Node* load_code = graph()->NewNode(
1933 machine->Load(MachineType::AnyTagged()), table,
1934 graph()->NewNode(machine->Int32Add(),
1935 graph()->NewNode(machine->Word32Shl(), key,
1936 Int32Constant(kPointerSizeLog2)),
1937 Int32Constant(offset)),
1938 *effect_, *control_);
1939
1940 args[0] = load_code;
1941 wasm::FunctionSig* sig = module_->GetSignature(index);
Ben Murdochc5610432016-08-08 18:44:38 +01001942 return BuildWasmCall(sig, args, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001943}
1944
Ben Murdochda12d292016-06-02 14:46:10 +01001945Node* WasmGraphBuilder::BuildI32Rol(Node* left, Node* right) {
1946 // Implement Rol by Ror since TurboFan does not have Rol opcode.
1947 // TODO(weiliang): support Word32Rol opcode in TurboFan.
1948 Int32Matcher m(right);
1949 if (m.HasValue()) {
1950 return Binop(wasm::kExprI32Ror, left,
1951 jsgraph()->Int32Constant(32 - m.Value()));
1952 } else {
1953 return Binop(wasm::kExprI32Ror, left,
1954 Binop(wasm::kExprI32Sub, jsgraph()->Int32Constant(32), right));
1955 }
1956}
1957
1958Node* WasmGraphBuilder::BuildI64Rol(Node* left, Node* right) {
1959 // Implement Rol by Ror since TurboFan does not have Rol opcode.
1960 // TODO(weiliang): support Word64Rol opcode in TurboFan.
1961 Int64Matcher m(right);
1962 if (m.HasValue()) {
1963 return Binop(wasm::kExprI64Ror, left,
1964 jsgraph()->Int64Constant(64 - m.Value()));
1965 } else {
1966 return Binop(wasm::kExprI64Ror, left,
1967 Binop(wasm::kExprI64Sub, jsgraph()->Int64Constant(64), right));
1968 }
1969}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001970
1971Node* WasmGraphBuilder::Invert(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01001972 return Unop(wasm::kExprI32Eqz, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001973}
1974
Ben Murdochc5610432016-08-08 18:44:38 +01001975Node* WasmGraphBuilder::BuildChangeInt32ToTagged(Node* value) {
1976 MachineOperatorBuilder* machine = jsgraph()->machine();
1977 CommonOperatorBuilder* common = jsgraph()->common();
1978
1979 if (machine->Is64()) {
1980 return BuildChangeInt32ToSmi(value);
1981 }
1982
Ben Murdoch61f157c2016-09-16 13:49:30 +01001983 Node* add = graph()->NewNode(machine->Int32AddWithOverflow(), value, value,
1984 graph()->start());
Ben Murdochc5610432016-08-08 18:44:38 +01001985
Ben Murdoch61f157c2016-09-16 13:49:30 +01001986 Node* ovf = graph()->NewNode(common->Projection(1), add, graph()->start());
Ben Murdochc5610432016-08-08 18:44:38 +01001987 Node* branch = graph()->NewNode(common->Branch(BranchHint::kFalse), ovf,
1988 graph()->start());
1989
1990 Node* if_true = graph()->NewNode(common->IfTrue(), branch);
1991 Node* vtrue = BuildAllocateHeapNumberWithValue(
1992 graph()->NewNode(machine->ChangeInt32ToFloat64(), value), if_true);
1993
1994 Node* if_false = graph()->NewNode(common->IfFalse(), branch);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001995 Node* vfalse = graph()->NewNode(common->Projection(0), add, if_false);
Ben Murdochc5610432016-08-08 18:44:38 +01001996
1997 Node* merge = graph()->NewNode(common->Merge(2), if_true, if_false);
1998 Node* phi = graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2),
1999 vtrue, vfalse, merge);
2000 return phi;
2001}
2002
2003Node* WasmGraphBuilder::BuildChangeFloat64ToTagged(Node* value) {
2004 MachineOperatorBuilder* machine = jsgraph()->machine();
2005 CommonOperatorBuilder* common = jsgraph()->common();
2006
2007 Node* value32 = graph()->NewNode(machine->RoundFloat64ToInt32(), value);
2008 Node* check_same = graph()->NewNode(
2009 machine->Float64Equal(), value,
2010 graph()->NewNode(machine->ChangeInt32ToFloat64(), value32));
2011 Node* branch_same =
2012 graph()->NewNode(common->Branch(), check_same, graph()->start());
2013
2014 Node* if_smi = graph()->NewNode(common->IfTrue(), branch_same);
2015 Node* vsmi;
2016 Node* if_box = graph()->NewNode(common->IfFalse(), branch_same);
2017 Node* vbox;
2018
2019 // We only need to check for -0 if the {value} can potentially contain -0.
2020 Node* check_zero = graph()->NewNode(machine->Word32Equal(), value32,
2021 jsgraph()->Int32Constant(0));
2022 Node* branch_zero =
2023 graph()->NewNode(common->Branch(BranchHint::kFalse), check_zero, if_smi);
2024
2025 Node* if_zero = graph()->NewNode(common->IfTrue(), branch_zero);
2026 Node* if_notzero = graph()->NewNode(common->IfFalse(), branch_zero);
2027
2028 // In case of 0, we need to check the high bits for the IEEE -0 pattern.
2029 Node* check_negative = graph()->NewNode(
2030 machine->Int32LessThan(),
2031 graph()->NewNode(machine->Float64ExtractHighWord32(), value),
2032 jsgraph()->Int32Constant(0));
2033 Node* branch_negative = graph()->NewNode(common->Branch(BranchHint::kFalse),
2034 check_negative, if_zero);
2035
2036 Node* if_negative = graph()->NewNode(common->IfTrue(), branch_negative);
2037 Node* if_notnegative = graph()->NewNode(common->IfFalse(), branch_negative);
2038
2039 // We need to create a box for negative 0.
2040 if_smi = graph()->NewNode(common->Merge(2), if_notzero, if_notnegative);
2041 if_box = graph()->NewNode(common->Merge(2), if_box, if_negative);
2042
2043 // On 64-bit machines we can just wrap the 32-bit integer in a smi, for 32-bit
2044 // machines we need to deal with potential overflow and fallback to boxing.
2045 if (machine->Is64()) {
2046 vsmi = BuildChangeInt32ToSmi(value32);
2047 } else {
Ben Murdoch61f157c2016-09-16 13:49:30 +01002048 Node* smi_tag = graph()->NewNode(machine->Int32AddWithOverflow(), value32,
2049 value32, if_smi);
Ben Murdochc5610432016-08-08 18:44:38 +01002050
Ben Murdoch61f157c2016-09-16 13:49:30 +01002051 Node* check_ovf = graph()->NewNode(common->Projection(1), smi_tag, if_smi);
Ben Murdochc5610432016-08-08 18:44:38 +01002052 Node* branch_ovf =
2053 graph()->NewNode(common->Branch(BranchHint::kFalse), check_ovf, if_smi);
2054
2055 Node* if_ovf = graph()->NewNode(common->IfTrue(), branch_ovf);
2056 if_box = graph()->NewNode(common->Merge(2), if_ovf, if_box);
2057
2058 if_smi = graph()->NewNode(common->IfFalse(), branch_ovf);
Ben Murdoch61f157c2016-09-16 13:49:30 +01002059 vsmi = graph()->NewNode(common->Projection(0), smi_tag, if_smi);
Ben Murdochc5610432016-08-08 18:44:38 +01002060 }
2061
2062 // Allocate the box for the {value}.
2063 vbox = BuildAllocateHeapNumberWithValue(value, if_box);
2064
2065 Node* control = graph()->NewNode(common->Merge(2), if_smi, if_box);
2066 value = graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2), vsmi,
2067 vbox, control);
2068 return value;
2069}
2070
2071Node* WasmGraphBuilder::ToJS(Node* node, Node* context, wasm::LocalType type) {
2072 switch (type) {
2073 case wasm::kAstI32:
2074 return BuildChangeInt32ToTagged(node);
2075 case wasm::kAstI64:
2076 // TODO(titzer): i64->JS has no good solution right now. Using lower 32
2077 // bits.
2078 if (jsgraph()->machine()->Is64()) {
2079 // On 32 bit platforms we do not have to do the truncation because the
2080 // node we get in as a parameter only contains the low word anyways.
2081 node = graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(),
2082 node);
2083 }
2084 return BuildChangeInt32ToTagged(node);
2085 case wasm::kAstF32:
2086 node = graph()->NewNode(jsgraph()->machine()->ChangeFloat32ToFloat64(),
2087 node);
2088 return BuildChangeFloat64ToTagged(node);
2089 case wasm::kAstF64:
2090 return BuildChangeFloat64ToTagged(node);
2091 case wasm::kAstStmt:
2092 return jsgraph()->UndefinedConstant();
2093 default:
2094 UNREACHABLE();
2095 return nullptr;
2096 }
2097}
2098
2099Node* WasmGraphBuilder::BuildJavaScriptToNumber(Node* node, Node* context,
2100 Node* effect, Node* control) {
2101 Callable callable = CodeFactory::ToNumber(jsgraph()->isolate());
2102 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
2103 jsgraph()->isolate(), jsgraph()->zone(), callable.descriptor(), 0,
2104 CallDescriptor::kNoFlags, Operator::kNoProperties);
2105 Node* stub_code = jsgraph()->HeapConstant(callable.code());
2106
2107 Node* result = graph()->NewNode(jsgraph()->common()->Call(desc), stub_code,
2108 node, context, effect, control);
2109
2110 *control_ = result;
2111 *effect_ = result;
2112
2113 return result;
2114}
2115
2116bool CanCover(Node* value, IrOpcode::Value opcode) {
2117 if (value->opcode() != opcode) return false;
2118 bool first = true;
2119 for (Edge const edge : value->use_edges()) {
2120 if (NodeProperties::IsControlEdge(edge)) continue;
2121 if (NodeProperties::IsEffectEdge(edge)) continue;
2122 DCHECK(NodeProperties::IsValueEdge(edge));
2123 if (!first) return false;
2124 first = false;
2125 }
2126 return true;
2127}
2128
2129Node* WasmGraphBuilder::BuildChangeTaggedToFloat64(Node* value) {
2130 MachineOperatorBuilder* machine = jsgraph()->machine();
2131 CommonOperatorBuilder* common = jsgraph()->common();
2132
2133 if (CanCover(value, IrOpcode::kJSToNumber)) {
2134 // ChangeTaggedToFloat64(JSToNumber(x)) =>
2135 // if IsSmi(x) then ChangeSmiToFloat64(x)
2136 // else let y = JSToNumber(x) in
2137 // if IsSmi(y) then ChangeSmiToFloat64(y)
2138 // else BuildLoadHeapNumberValue(y)
2139 Node* object = NodeProperties::GetValueInput(value, 0);
2140 Node* context = NodeProperties::GetContextInput(value);
2141 Node* frame_state = NodeProperties::GetFrameStateInput(value, 0);
2142 Node* effect = NodeProperties::GetEffectInput(value);
2143 Node* control = NodeProperties::GetControlInput(value);
2144
2145 const Operator* merge_op = common->Merge(2);
2146 const Operator* ephi_op = common->EffectPhi(2);
2147 const Operator* phi_op = common->Phi(MachineRepresentation::kFloat64, 2);
2148
2149 Node* check1 = BuildTestNotSmi(object);
2150 Node* branch1 =
2151 graph()->NewNode(common->Branch(BranchHint::kFalse), check1, control);
2152
2153 Node* if_true1 = graph()->NewNode(common->IfTrue(), branch1);
2154 Node* vtrue1 = graph()->NewNode(value->op(), object, context, frame_state,
2155 effect, if_true1);
2156 Node* etrue1 = vtrue1;
2157
2158 Node* check2 = BuildTestNotSmi(vtrue1);
2159 Node* branch2 = graph()->NewNode(common->Branch(), check2, if_true1);
2160
2161 Node* if_true2 = graph()->NewNode(common->IfTrue(), branch2);
2162 Node* vtrue2 = BuildLoadHeapNumberValue(vtrue1, if_true2);
2163
2164 Node* if_false2 = graph()->NewNode(common->IfFalse(), branch2);
2165 Node* vfalse2 = BuildChangeSmiToFloat64(vtrue1);
2166
2167 if_true1 = graph()->NewNode(merge_op, if_true2, if_false2);
2168 vtrue1 = graph()->NewNode(phi_op, vtrue2, vfalse2, if_true1);
2169
2170 Node* if_false1 = graph()->NewNode(common->IfFalse(), branch1);
2171 Node* vfalse1 = BuildChangeSmiToFloat64(object);
2172 Node* efalse1 = effect;
2173
2174 Node* merge1 = graph()->NewNode(merge_op, if_true1, if_false1);
2175 Node* ephi1 = graph()->NewNode(ephi_op, etrue1, efalse1, merge1);
2176 Node* phi1 = graph()->NewNode(phi_op, vtrue1, vfalse1, merge1);
2177
2178 // Wire the new diamond into the graph, {JSToNumber} can still throw.
2179 NodeProperties::ReplaceUses(value, phi1, ephi1, etrue1, etrue1);
2180
2181 // TODO(mstarzinger): This iteration cuts out the IfSuccess projection from
2182 // the node and places it inside the diamond. Come up with a helper method!
2183 for (Node* use : etrue1->uses()) {
2184 if (use->opcode() == IrOpcode::kIfSuccess) {
2185 use->ReplaceUses(merge1);
2186 NodeProperties::ReplaceControlInput(branch2, use);
2187 }
2188 }
2189 return phi1;
2190 }
2191
2192 Node* check = BuildTestNotSmi(value);
2193 Node* branch = graph()->NewNode(common->Branch(BranchHint::kFalse), check,
2194 graph()->start());
2195
2196 Node* if_not_smi = graph()->NewNode(common->IfTrue(), branch);
2197
2198 Node* vnot_smi;
2199 Node* check_undefined = graph()->NewNode(machine->WordEqual(), value,
2200 jsgraph()->UndefinedConstant());
2201 Node* branch_undefined = graph()->NewNode(common->Branch(BranchHint::kFalse),
2202 check_undefined, if_not_smi);
2203
2204 Node* if_undefined = graph()->NewNode(common->IfTrue(), branch_undefined);
2205 Node* vundefined =
2206 jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN());
2207
2208 Node* if_not_undefined =
2209 graph()->NewNode(common->IfFalse(), branch_undefined);
2210 Node* vheap_number = BuildLoadHeapNumberValue(value, if_not_undefined);
2211
2212 if_not_smi =
2213 graph()->NewNode(common->Merge(2), if_undefined, if_not_undefined);
2214 vnot_smi = graph()->NewNode(common->Phi(MachineRepresentation::kFloat64, 2),
2215 vundefined, vheap_number, if_not_smi);
2216
2217 Node* if_smi = graph()->NewNode(common->IfFalse(), branch);
2218 Node* vfrom_smi = BuildChangeSmiToFloat64(value);
2219
2220 Node* merge = graph()->NewNode(common->Merge(2), if_not_smi, if_smi);
2221 Node* phi = graph()->NewNode(common->Phi(MachineRepresentation::kFloat64, 2),
2222 vnot_smi, vfrom_smi, merge);
2223
2224 return phi;
2225}
2226
2227Node* WasmGraphBuilder::FromJS(Node* node, Node* context,
2228 wasm::LocalType type) {
2229 // Do a JavaScript ToNumber.
2230 Node* num = BuildJavaScriptToNumber(node, context, *effect_, *control_);
2231
2232 // Change representation.
2233 SimplifiedOperatorBuilder simplified(jsgraph()->zone());
2234 num = BuildChangeTaggedToFloat64(num);
2235
2236 switch (type) {
2237 case wasm::kAstI32: {
2238 num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToWord32(),
2239 num);
2240 break;
2241 }
2242 case wasm::kAstI64:
2243 // TODO(titzer): JS->i64 has no good solution right now. Using 32 bits.
2244 num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToWord32(),
2245 num);
2246 if (jsgraph()->machine()->Is64()) {
2247 // We cannot change an int32 to an int64 on a 32 bit platform. Instead
2248 // we will split the parameter node later.
2249 num = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), num);
2250 }
2251 break;
2252 case wasm::kAstF32:
2253 num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToFloat32(),
2254 num);
2255 break;
2256 case wasm::kAstF64:
2257 break;
2258 case wasm::kAstStmt:
2259 num = jsgraph()->Int32Constant(0);
2260 break;
2261 default:
2262 UNREACHABLE();
2263 return nullptr;
2264 }
2265 return num;
2266}
2267
2268Node* WasmGraphBuilder::BuildChangeInt32ToSmi(Node* value) {
2269 if (jsgraph()->machine()->Is64()) {
2270 value = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), value);
2271 }
2272 return graph()->NewNode(jsgraph()->machine()->WordShl(), value,
2273 BuildSmiShiftBitsConstant());
2274}
2275
2276Node* WasmGraphBuilder::BuildChangeSmiToInt32(Node* value) {
2277 value = graph()->NewNode(jsgraph()->machine()->WordSar(), value,
2278 BuildSmiShiftBitsConstant());
2279 if (jsgraph()->machine()->Is64()) {
2280 value =
2281 graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(), value);
2282 }
2283 return value;
2284}
2285
2286Node* WasmGraphBuilder::BuildChangeSmiToFloat64(Node* value) {
2287 return graph()->NewNode(jsgraph()->machine()->ChangeInt32ToFloat64(),
2288 BuildChangeSmiToInt32(value));
2289}
2290
2291Node* WasmGraphBuilder::BuildTestNotSmi(Node* value) {
2292 STATIC_ASSERT(kSmiTag == 0);
2293 STATIC_ASSERT(kSmiTagMask == 1);
2294 return graph()->NewNode(jsgraph()->machine()->WordAnd(), value,
2295 jsgraph()->IntPtrConstant(kSmiTagMask));
2296}
2297
2298Node* WasmGraphBuilder::BuildSmiShiftBitsConstant() {
2299 return jsgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize);
2300}
2301
2302Node* WasmGraphBuilder::BuildAllocateHeapNumberWithValue(Node* value,
2303 Node* control) {
2304 MachineOperatorBuilder* machine = jsgraph()->machine();
2305 CommonOperatorBuilder* common = jsgraph()->common();
2306 // The AllocateHeapNumberStub does not use the context, so we can safely pass
2307 // in Smi zero here.
2308 Callable callable = CodeFactory::AllocateHeapNumber(jsgraph()->isolate());
2309 Node* target = jsgraph()->HeapConstant(callable.code());
2310 Node* context = jsgraph()->NoContextConstant();
Ben Murdoch61f157c2016-09-16 13:49:30 +01002311 Node* effect =
2312 graph()->NewNode(common->BeginRegion(RegionObservability::kNotObservable),
2313 graph()->start());
Ben Murdochc5610432016-08-08 18:44:38 +01002314 if (!allocate_heap_number_operator_.is_set()) {
2315 CallDescriptor* descriptor = Linkage::GetStubCallDescriptor(
2316 jsgraph()->isolate(), jsgraph()->zone(), callable.descriptor(), 0,
2317 CallDescriptor::kNoFlags, Operator::kNoThrow);
2318 allocate_heap_number_operator_.set(common->Call(descriptor));
2319 }
2320 Node* heap_number = graph()->NewNode(allocate_heap_number_operator_.get(),
2321 target, context, effect, control);
2322 Node* store =
2323 graph()->NewNode(machine->Store(StoreRepresentation(
2324 MachineRepresentation::kFloat64, kNoWriteBarrier)),
2325 heap_number, BuildHeapNumberValueIndexConstant(), value,
2326 heap_number, control);
2327 return graph()->NewNode(common->FinishRegion(), heap_number, store);
2328}
2329
2330Node* WasmGraphBuilder::BuildLoadHeapNumberValue(Node* value, Node* control) {
2331 return graph()->NewNode(jsgraph()->machine()->Load(MachineType::Float64()),
2332 value, BuildHeapNumberValueIndexConstant(),
2333 graph()->start(), control);
2334}
2335
2336Node* WasmGraphBuilder::BuildHeapNumberValueIndexConstant() {
2337 return jsgraph()->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag);
2338}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002339
2340void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code,
2341 wasm::FunctionSig* sig) {
Ben Murdochc5610432016-08-08 18:44:38 +01002342 int wasm_count = static_cast<int>(sig->parameter_count());
2343 int param_count;
2344 if (jsgraph()->machine()->Is64()) {
2345 param_count = static_cast<int>(sig->parameter_count());
2346 } else {
2347 param_count = Int64Lowering::GetParameterCountAfterLowering(sig);
2348 }
2349 int count = param_count + 3;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002350 Node** args = Buffer(count);
2351
2352 // Build the start and the JS parameter nodes.
Ben Murdochc5610432016-08-08 18:44:38 +01002353 Node* start = Start(param_count + 5);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002354 *control_ = start;
2355 *effect_ = start;
Ben Murdochda12d292016-06-02 14:46:10 +01002356 // Create the context parameter
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002357 Node* context = graph()->NewNode(
Ben Murdochda12d292016-06-02 14:46:10 +01002358 jsgraph()->common()->Parameter(
Ben Murdochc5610432016-08-08 18:44:38 +01002359 Linkage::GetJSCallContextParamIndex(wasm_count + 1), "%context"),
Ben Murdochda12d292016-06-02 14:46:10 +01002360 graph()->start());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002361
2362 int pos = 0;
Ben Murdochc5610432016-08-08 18:44:38 +01002363 args[pos++] = HeapConstant(wasm_code);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002364
2365 // Convert JS parameters to WASM numbers.
Ben Murdoch61f157c2016-09-16 13:49:30 +01002366 for (int i = 0; i < wasm_count; ++i) {
Ben Murdochda12d292016-06-02 14:46:10 +01002367 Node* param =
2368 graph()->NewNode(jsgraph()->common()->Parameter(i + 1), start);
Ben Murdochc5610432016-08-08 18:44:38 +01002369 Node* wasm_param = FromJS(param, context, sig->GetParam(i));
2370 args[pos++] = wasm_param;
2371 if (jsgraph()->machine()->Is32() && sig->GetParam(i) == wasm::kAstI64) {
2372 // We make up the high word with SAR to get the proper sign extension.
2373 args[pos++] = graph()->NewNode(jsgraph()->machine()->Word32Sar(),
2374 wasm_param, jsgraph()->Int32Constant(31));
2375 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002376 }
2377
2378 args[pos++] = *effect_;
2379 args[pos++] = *control_;
2380
2381 // Call the WASM code.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002382 CallDescriptor* desc =
2383 wasm::ModuleEnv::GetWasmCallDescriptor(jsgraph()->zone(), sig);
Ben Murdochc5610432016-08-08 18:44:38 +01002384 if (jsgraph()->machine()->Is32()) {
2385 desc = wasm::ModuleEnv::GetI32WasmCallDescriptor(jsgraph()->zone(), desc);
2386 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002387 Node* call = graph()->NewNode(jsgraph()->common()->Call(desc), count, args);
Ben Murdochc5610432016-08-08 18:44:38 +01002388 Node* retval = call;
2389 if (jsgraph()->machine()->Is32() && sig->return_count() > 0 &&
2390 sig->GetReturn(0) == wasm::kAstI64) {
2391 // The return values comes as two values, we pick the low word.
Ben Murdoch61f157c2016-09-16 13:49:30 +01002392 retval = graph()->NewNode(jsgraph()->common()->Projection(0), retval,
2393 graph()->start());
Ben Murdochc5610432016-08-08 18:44:38 +01002394 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002395 Node* jsval =
Ben Murdochc5610432016-08-08 18:44:38 +01002396 ToJS(retval, context,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002397 sig->return_count() == 0 ? wasm::kAstStmt : sig->GetReturn());
2398 Node* ret =
2399 graph()->NewNode(jsgraph()->common()->Return(), jsval, call, start);
2400
2401 MergeControlToEnd(jsgraph(), ret);
2402}
2403
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002404void WasmGraphBuilder::BuildWasmToJSWrapper(Handle<JSFunction> function,
2405 wasm::FunctionSig* sig) {
2406 int js_count = function->shared()->internal_formal_parameter_count();
2407 int wasm_count = static_cast<int>(sig->parameter_count());
Ben Murdochc5610432016-08-08 18:44:38 +01002408 int param_count;
2409 if (jsgraph()->machine()->Is64()) {
2410 param_count = wasm_count;
2411 } else {
2412 param_count = Int64Lowering::GetParameterCountAfterLowering(sig);
2413 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002414
2415 // Build the start and the parameter nodes.
2416 Isolate* isolate = jsgraph()->isolate();
2417 CallDescriptor* desc;
Ben Murdochc5610432016-08-08 18:44:38 +01002418 Node* start = Start(param_count + 3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002419 *effect_ = start;
2420 *control_ = start;
2421 // JS context is the last parameter.
Ben Murdochc5610432016-08-08 18:44:38 +01002422 Node* context = HeapConstant(Handle<Context>(function->context(), isolate));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002423 Node** args = Buffer(wasm_count + 7);
2424
2425 bool arg_count_before_args = false;
2426 bool add_new_target_undefined = false;
2427
2428 int pos = 0;
2429 if (js_count == wasm_count) {
2430 // exact arity match, just call the function directly.
2431 desc = Linkage::GetJSCallDescriptor(graph()->zone(), false, wasm_count + 1,
2432 CallDescriptor::kNoFlags);
2433 arg_count_before_args = false;
2434 add_new_target_undefined = true;
2435 } else {
2436 // Use the Call builtin.
2437 Callable callable = CodeFactory::Call(isolate);
2438 args[pos++] = jsgraph()->HeapConstant(callable.code());
2439 desc = Linkage::GetStubCallDescriptor(isolate, graph()->zone(),
2440 callable.descriptor(), wasm_count + 1,
2441 CallDescriptor::kNoFlags);
2442 arg_count_before_args = true;
2443 }
2444
2445 args[pos++] = jsgraph()->Constant(function); // JS function.
2446 if (arg_count_before_args) {
2447 args[pos++] = jsgraph()->Int32Constant(wasm_count); // argument count
2448 }
2449 // JS receiver.
2450 Handle<Object> global(function->context()->global_object(), isolate);
2451 args[pos++] = jsgraph()->Constant(global);
2452
2453 // Convert WASM numbers to JS values.
Ben Murdochc5610432016-08-08 18:44:38 +01002454 int param_index = 0;
Ben Murdoch61f157c2016-09-16 13:49:30 +01002455 for (int i = 0; i < wasm_count; ++i) {
Ben Murdochc5610432016-08-08 18:44:38 +01002456 Node* param =
2457 graph()->NewNode(jsgraph()->common()->Parameter(param_index++), start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002458 args[pos++] = ToJS(param, context, sig->GetParam(i));
Ben Murdochc5610432016-08-08 18:44:38 +01002459 if (jsgraph()->machine()->Is32() && sig->GetParam(i) == wasm::kAstI64) {
2460 // On 32 bit platforms we have to skip the high word of int64 parameters.
2461 param_index++;
2462 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002463 }
2464
2465 if (add_new_target_undefined) {
2466 args[pos++] = jsgraph()->UndefinedConstant(); // new target
2467 }
2468
2469 if (!arg_count_before_args) {
2470 args[pos++] = jsgraph()->Int32Constant(wasm_count); // argument count
2471 }
2472 args[pos++] = context;
2473 args[pos++] = *effect_;
2474 args[pos++] = *control_;
2475
2476 Node* call = graph()->NewNode(jsgraph()->common()->Call(desc), pos, args);
2477
2478 // Convert the return value back.
Ben Murdochc5610432016-08-08 18:44:38 +01002479 Node* ret;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002480 Node* val =
2481 FromJS(call, context,
2482 sig->return_count() == 0 ? wasm::kAstStmt : sig->GetReturn());
Ben Murdochc5610432016-08-08 18:44:38 +01002483 if (jsgraph()->machine()->Is32() && sig->return_count() > 0 &&
2484 sig->GetReturn() == wasm::kAstI64) {
2485 ret = graph()->NewNode(jsgraph()->common()->Return(), val,
2486 graph()->NewNode(jsgraph()->machine()->Word32Sar(),
2487 val, jsgraph()->Int32Constant(31)),
2488 call, start);
2489 } else {
2490 ret = graph()->NewNode(jsgraph()->common()->Return(), val, call, start);
2491 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002492
2493 MergeControlToEnd(jsgraph(), ret);
2494}
2495
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002496Node* WasmGraphBuilder::MemBuffer(uint32_t offset) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002497 DCHECK(module_ && module_->instance);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002498 if (offset == 0) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002499 if (!mem_buffer_) {
Ben Murdochc5610432016-08-08 18:44:38 +01002500 mem_buffer_ = jsgraph()->RelocatableIntPtrConstant(
2501 reinterpret_cast<uintptr_t>(module_->instance->mem_start),
2502 RelocInfo::WASM_MEMORY_REFERENCE);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002503 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002504 return mem_buffer_;
2505 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01002506 return jsgraph()->RelocatableIntPtrConstant(
2507 reinterpret_cast<uintptr_t>(module_->instance->mem_start + offset),
2508 RelocInfo::WASM_MEMORY_REFERENCE);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002509 }
2510}
2511
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002512Node* WasmGraphBuilder::MemSize(uint32_t offset) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002513 DCHECK(module_ && module_->instance);
2514 uint32_t size = static_cast<uint32_t>(module_->instance->mem_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002515 if (offset == 0) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01002516 if (!mem_size_)
2517 mem_size_ = jsgraph()->RelocatableInt32Constant(
2518 size, RelocInfo::WASM_MEMORY_SIZE_REFERENCE);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002519 return mem_size_;
2520 } else {
Ben Murdoch61f157c2016-09-16 13:49:30 +01002521 return jsgraph()->RelocatableInt32Constant(
2522 size + offset, RelocInfo::WASM_MEMORY_SIZE_REFERENCE);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002523 }
2524}
2525
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002526Node* WasmGraphBuilder::FunctionTable() {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002527 DCHECK(module_ && module_->instance &&
2528 !module_->instance->function_table.is_null());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002529 if (!function_table_) {
Ben Murdochc5610432016-08-08 18:44:38 +01002530 function_table_ = HeapConstant(module_->instance->function_table);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002531 }
2532 return function_table_;
2533}
2534
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002535Node* WasmGraphBuilder::LoadGlobal(uint32_t index) {
2536 MachineType mem_type = module_->GetGlobalType(index);
Ben Murdoch61f157c2016-09-16 13:49:30 +01002537 Node* addr = jsgraph()->RelocatableIntPtrConstant(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002538 reinterpret_cast<uintptr_t>(module_->instance->globals_start +
Ben Murdoch61f157c2016-09-16 13:49:30 +01002539 module_->module->globals[index].offset),
2540 RelocInfo::WASM_GLOBAL_REFERENCE);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002541 const Operator* op = jsgraph()->machine()->Load(mem_type);
2542 Node* node = graph()->NewNode(op, addr, jsgraph()->Int32Constant(0), *effect_,
2543 *control_);
2544 *effect_ = node;
2545 return node;
2546}
2547
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002548Node* WasmGraphBuilder::StoreGlobal(uint32_t index, Node* val) {
2549 MachineType mem_type = module_->GetGlobalType(index);
Ben Murdoch61f157c2016-09-16 13:49:30 +01002550 Node* addr = jsgraph()->RelocatableIntPtrConstant(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002551 reinterpret_cast<uintptr_t>(module_->instance->globals_start +
Ben Murdoch61f157c2016-09-16 13:49:30 +01002552 module_->module->globals[index].offset),
2553 RelocInfo::WASM_GLOBAL_REFERENCE);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002554 const Operator* op = jsgraph()->machine()->Store(
2555 StoreRepresentation(mem_type.representation(), kNoWriteBarrier));
2556 Node* node = graph()->NewNode(op, addr, jsgraph()->Int32Constant(0), val,
2557 *effect_, *control_);
2558 *effect_ = node;
2559 return node;
2560}
2561
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002562void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index,
Ben Murdochc5610432016-08-08 18:44:38 +01002563 uint32_t offset,
2564 wasm::WasmCodePosition position) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002565 DCHECK(module_ && module_->instance);
Ben Murdoch61f157c2016-09-16 13:49:30 +01002566 uint32_t size = module_->instance->mem_size;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002567 byte memsize = wasm::WasmOpcodes::MemSize(memtype);
Ben Murdochc5610432016-08-08 18:44:38 +01002568
Ben Murdochc5610432016-08-08 18:44:38 +01002569 // Check against the effective size.
Ben Murdoch61f157c2016-09-16 13:49:30 +01002570 size_t effective_size;
2571 if (offset >= size || (static_cast<uint64_t>(offset) + memsize) > size) {
2572 effective_size = 0;
2573 } else {
2574 effective_size = size - offset - memsize + 1;
2575 }
Ben Murdochc5610432016-08-08 18:44:38 +01002576 CHECK(effective_size <= kMaxUInt32);
2577
2578 Uint32Matcher m(index);
2579 if (m.HasValue()) {
2580 uint32_t value = m.Value();
Ben Murdoch61f157c2016-09-16 13:49:30 +01002581 if (value < effective_size) {
Ben Murdochc5610432016-08-08 18:44:38 +01002582 // The bounds check will always succeed.
2583 return;
2584 }
2585 }
2586
Ben Murdoch61f157c2016-09-16 13:49:30 +01002587 Node* cond = graph()->NewNode(jsgraph()->machine()->Uint32LessThan(), index,
2588 jsgraph()->RelocatableInt32Constant(
2589 static_cast<uint32_t>(effective_size),
2590 RelocInfo::WASM_MEMORY_SIZE_REFERENCE));
Ben Murdochc5610432016-08-08 18:44:38 +01002591
2592 trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002593}
2594
Ben Murdoch61f157c2016-09-16 13:49:30 +01002595MachineType WasmGraphBuilder::GetTypeForUnalignedAccess(uint32_t alignment,
2596 bool signExtend) {
2597 switch (alignment) {
2598 case 0:
2599 return signExtend ? MachineType::Int8() : MachineType::Uint8();
2600 case 1:
2601 return signExtend ? MachineType::Int16() : MachineType::Uint16();
2602 case 2:
2603 return signExtend ? MachineType::Int32() : MachineType::Uint32();
2604 default:
2605 UNREACHABLE();
2606 return MachineType::None();
2607 }
2608}
2609
2610Node* WasmGraphBuilder::GetUnalignedLoadOffsetNode(Node* baseOffset,
2611 int numberOfBytes,
2612 int stride, int current) {
2613 int offset;
2614 wasm::WasmOpcode addOpcode;
2615
2616#if defined(V8_TARGET_LITTLE_ENDIAN)
2617 offset = numberOfBytes - stride - current;
2618#elif defined(V8_TARGET_BIG_ENDIAN)
2619 offset = current;
2620#else
2621#error Unsupported endianness
2622#endif
2623
2624#if WASM_64
2625 addOpcode = wasm::kExprI64Add;
2626#else
2627 addOpcode = wasm::kExprI32Add;
2628#endif
2629
2630 if (offset == 0) {
2631 return baseOffset;
2632 } else {
2633 return Binop(addOpcode, baseOffset, jsgraph()->Int32Constant(offset));
2634 }
2635}
2636
2637Node* WasmGraphBuilder::BuildUnalignedLoad(wasm::LocalType type,
2638 MachineType memtype, Node* index,
2639 uint32_t offset,
2640 uint32_t alignment) {
2641 Node* result;
2642 Node* load;
2643 bool extendTo64Bit = false;
2644
2645 wasm::WasmOpcode shiftOpcode;
2646 wasm::WasmOpcode orOpcode;
2647 Node* shiftConst;
2648
2649 bool signExtend = memtype.IsSigned();
2650
2651 bool isFloat = IsFloatingPoint(memtype.representation());
2652 int stride =
2653 1 << ElementSizeLog2Of(
2654 GetTypeForUnalignedAccess(alignment, false).representation());
2655 int numberOfBytes = 1 << ElementSizeLog2Of(memtype.representation());
2656 DCHECK(numberOfBytes % stride == 0);
2657
2658 switch (type) {
2659 case wasm::kAstI64:
2660 case wasm::kAstF64:
2661 shiftOpcode = wasm::kExprI64Shl;
2662 orOpcode = wasm::kExprI64Ior;
2663 result = jsgraph()->Int64Constant(0);
2664 shiftConst = jsgraph()->Int64Constant(8 * stride);
2665 extendTo64Bit = true;
2666 break;
2667 case wasm::kAstI32:
2668 case wasm::kAstF32:
2669 shiftOpcode = wasm::kExprI32Shl;
2670 orOpcode = wasm::kExprI32Ior;
2671 result = jsgraph()->Int32Constant(0);
2672 shiftConst = jsgraph()->Int32Constant(8 * stride);
2673 break;
2674 default:
2675 UNREACHABLE();
2676 }
2677
2678 Node* baseOffset = MemBuffer(offset);
2679
2680 for (int i = 0; i < numberOfBytes; i += stride) {
2681 result = Binop(shiftOpcode, result, shiftConst);
2682 load = graph()->NewNode(
2683 jsgraph()->machine()->Load(
2684 GetTypeForUnalignedAccess(alignment, signExtend)),
2685 GetUnalignedLoadOffsetNode(baseOffset, numberOfBytes, stride, i), index,
2686 *effect_, *control_);
2687 *effect_ = load;
2688 if (extendTo64Bit) {
2689 if (signExtend) {
2690 load =
2691 graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load);
2692 } else {
2693 load = graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(),
2694 load);
2695 }
2696 }
2697 signExtend = false;
2698 result = Binop(orOpcode, result, load);
2699 }
2700
2701 // Convert to float
2702 if (isFloat) {
2703 switch (type) {
2704 case wasm::kAstF32:
2705 result = Unop(wasm::kExprF32ReinterpretI32, result);
2706 break;
2707 case wasm::kAstF64:
2708 result = Unop(wasm::kExprF64ReinterpretI64, result);
2709 break;
2710 default:
2711 UNREACHABLE();
2712 }
2713 }
2714
2715 return result;
2716}
2717
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002718Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype,
Ben Murdochc5610432016-08-08 18:44:38 +01002719 Node* index, uint32_t offset,
Ben Murdoch61f157c2016-09-16 13:49:30 +01002720 uint32_t alignment,
Ben Murdochc5610432016-08-08 18:44:38 +01002721 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002722 Node* load;
Ben Murdoch61f157c2016-09-16 13:49:30 +01002723
Ben Murdochc5610432016-08-08 18:44:38 +01002724 // WASM semantics throw on OOB. Introduce explicit bounds check.
2725 BoundsCheckMem(memtype, index, offset, position);
Ben Murdoch61f157c2016-09-16 13:49:30 +01002726 bool aligned = static_cast<int>(alignment) >=
2727 ElementSizeLog2Of(memtype.representation());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002728
Ben Murdoch61f157c2016-09-16 13:49:30 +01002729 if (aligned ||
2730 jsgraph()->machine()->UnalignedLoadSupported(memtype, alignment)) {
2731 load = graph()->NewNode(jsgraph()->machine()->Load(memtype),
2732 MemBuffer(offset), index, *effect_, *control_);
2733 *effect_ = load;
2734 } else {
2735 load = BuildUnalignedLoad(type, memtype, index, offset, alignment);
2736 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002737
2738 if (type == wasm::kAstI64 &&
2739 ElementSizeLog2Of(memtype.representation()) < 3) {
2740 // TODO(titzer): TF zeroes the upper bits of 64-bit loads for subword sizes.
2741 if (memtype.IsSigned()) {
2742 // sign extend
2743 load = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load);
2744 } else {
2745 // zero extend
2746 load =
2747 graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), load);
2748 }
2749 }
2750
2751 return load;
2752}
2753
Ben Murdoch61f157c2016-09-16 13:49:30 +01002754Node* WasmGraphBuilder::GetUnalignedStoreOffsetNode(Node* baseOffset,
2755 int numberOfBytes,
2756 int stride, int current) {
2757 int offset;
2758 wasm::WasmOpcode addOpcode;
2759
2760#if defined(V8_TARGET_LITTLE_ENDIAN)
2761 offset = current;
2762#elif defined(V8_TARGET_BIG_ENDIAN)
2763 offset = numberOfBytes - stride - current;
2764#else
2765#error Unsupported endianness
2766#endif
2767
2768#if WASM_64
2769 addOpcode = wasm::kExprI64Add;
2770#else
2771 addOpcode = wasm::kExprI32Add;
2772#endif
2773
2774 if (offset == 0) {
2775 return baseOffset;
2776 } else {
2777 return Binop(addOpcode, baseOffset, jsgraph()->Int32Constant(offset));
2778 }
2779}
2780
2781Node* WasmGraphBuilder::BuildUnalignedStore(MachineType memtype, Node* index,
2782 uint32_t offset, uint32_t alignment,
2783 Node* val) {
2784 Node* store;
2785 Node* newValue;
2786
2787 wasm::WasmOpcode shiftOpcode;
2788
2789 Node* shiftConst;
2790 bool extendTo64Bit = false;
2791 bool isFloat = IsFloatingPoint(memtype.representation());
2792 int stride = 1 << ElementSizeLog2Of(
2793 GetTypeForUnalignedAccess(alignment).representation());
2794 int numberOfBytes = 1 << ElementSizeLog2Of(memtype.representation());
2795 DCHECK(numberOfBytes % stride == 0);
2796
2797 StoreRepresentation rep(GetTypeForUnalignedAccess(alignment).representation(),
2798 kNoWriteBarrier);
2799
2800 if (ElementSizeLog2Of(memtype.representation()) <= 2) {
2801 shiftOpcode = wasm::kExprI32ShrU;
2802 shiftConst = jsgraph()->Int32Constant(8 * stride);
2803 } else {
2804 shiftOpcode = wasm::kExprI64ShrU;
2805 shiftConst = jsgraph()->Int64Constant(8 * stride);
2806 extendTo64Bit = true;
2807 }
2808
2809 newValue = val;
2810 if (isFloat) {
2811 switch (memtype.representation()) {
2812 case MachineRepresentation::kFloat64:
2813 newValue = Unop(wasm::kExprI64ReinterpretF64, val);
2814 break;
2815 case MachineRepresentation::kFloat32:
2816 newValue = Unop(wasm::kExprI32ReinterpretF32, val);
2817 break;
2818 default:
2819 UNREACHABLE();
2820 }
2821 }
2822
2823 Node* baseOffset = MemBuffer(offset);
2824
2825 for (int i = 0; i < numberOfBytes - stride; i += stride) {
2826 store = graph()->NewNode(
2827 jsgraph()->machine()->Store(rep),
2828 GetUnalignedStoreOffsetNode(baseOffset, numberOfBytes, stride, i),
2829 index,
2830 extendTo64Bit ? Unop(wasm::kExprI32ConvertI64, newValue) : newValue,
2831 *effect_, *control_);
2832 newValue = Binop(shiftOpcode, newValue, shiftConst);
2833 *effect_ = store;
2834 }
2835 store = graph()->NewNode(
2836 jsgraph()->machine()->Store(rep),
2837 GetUnalignedStoreOffsetNode(baseOffset, numberOfBytes, stride,
2838 numberOfBytes - stride),
2839 index,
2840 extendTo64Bit ? Unop(wasm::kExprI32ConvertI64, newValue) : newValue,
2841 *effect_, *control_);
2842 *effect_ = store;
2843 return val;
2844}
2845
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002846Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index,
Ben Murdoch61f157c2016-09-16 13:49:30 +01002847 uint32_t offset, uint32_t alignment, Node* val,
Ben Murdochc5610432016-08-08 18:44:38 +01002848 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002849 Node* store;
Ben Murdoch61f157c2016-09-16 13:49:30 +01002850
Ben Murdochc5610432016-08-08 18:44:38 +01002851 // WASM semantics throw on OOB. Introduce explicit bounds check.
2852 BoundsCheckMem(memtype, index, offset, position);
2853 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier);
Ben Murdoch61f157c2016-09-16 13:49:30 +01002854 bool aligned = static_cast<int>(alignment) >=
2855 ElementSizeLog2Of(memtype.representation());
2856
2857 if (aligned ||
2858 jsgraph()->machine()->UnalignedStoreSupported(memtype, alignment)) {
2859 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier);
2860 store =
2861 graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset),
2862 index, val, *effect_, *control_);
2863 *effect_ = store;
2864 } else {
2865 store = BuildUnalignedStore(memtype, index, offset, alignment, val);
2866 }
2867
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002868 return store;
2869}
2870
Ben Murdochc5610432016-08-08 18:44:38 +01002871Node* WasmGraphBuilder::BuildAsmjsLoadMem(MachineType type, Node* index) {
2872 // TODO(turbofan): fold bounds checks for constant asm.js loads.
2873 // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish).
2874 const Operator* op = jsgraph()->machine()->CheckedLoad(type);
2875 Node* load = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), *effect_,
2876 *control_);
2877 *effect_ = load;
2878 return load;
2879}
2880
2881Node* WasmGraphBuilder::BuildAsmjsStoreMem(MachineType type, Node* index,
2882 Node* val) {
2883 // TODO(turbofan): fold bounds checks for constant asm.js stores.
2884 // asm.js semantics use CheckedStore (i.e. ignore OOB writes).
2885 const Operator* op =
2886 jsgraph()->machine()->CheckedStore(type.representation());
2887 Node* store = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), val,
2888 *effect_, *control_);
2889 *effect_ = store;
2890 return val;
2891}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002892
2893void WasmGraphBuilder::PrintDebugName(Node* node) {
2894 PrintF("#%d:%s", node->id(), node->op()->mnemonic());
2895}
2896
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002897Node* WasmGraphBuilder::String(const char* string) {
2898 return jsgraph()->Constant(
2899 jsgraph()->isolate()->factory()->NewStringFromAsciiChecked(string));
2900}
2901
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002902Graph* WasmGraphBuilder::graph() { return jsgraph()->graph(); }
2903
Ben Murdoch097c5b22016-05-18 11:27:45 +01002904void WasmGraphBuilder::Int64LoweringForTesting() {
Ben Murdochda12d292016-06-02 14:46:10 +01002905 if (jsgraph()->machine()->Is32()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002906 Int64Lowering r(jsgraph()->graph(), jsgraph()->machine(),
2907 jsgraph()->common(), jsgraph()->zone(),
2908 function_signature_);
2909 r.LowerGraph();
2910 }
2911}
2912
Ben Murdochc5610432016-08-08 18:44:38 +01002913void WasmGraphBuilder::SetSourcePosition(Node* node,
2914 wasm::WasmCodePosition position) {
2915 DCHECK_NE(position, wasm::kNoCodePosition);
2916 compiler::SourcePosition pos(position);
2917 if (source_position_table_)
2918 source_position_table_->SetSourcePosition(node, pos);
2919}
2920
Ben Murdoch61f157c2016-09-16 13:49:30 +01002921static void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
Ben Murdoch097c5b22016-05-18 11:27:45 +01002922 CompilationInfo* info,
2923 const char* message, uint32_t index,
Ben Murdochda12d292016-06-02 14:46:10 +01002924 wasm::WasmName func_name) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002925 Isolate* isolate = info->isolate();
Ben Murdoch61f157c2016-09-16 13:49:30 +01002926 if (isolate->logger()->is_logging_code_events() || isolate->is_profiling()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002927 ScopedVector<char> buffer(128);
Ben Murdochc5610432016-08-08 18:44:38 +01002928 SNPrintF(buffer, "%s#%d:%.*s", message, index, func_name.length(),
2929 func_name.start());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002930 Handle<String> name_str =
2931 isolate->factory()->NewStringFromAsciiChecked(buffer.start());
2932 Handle<String> script_str =
2933 isolate->factory()->NewStringFromAsciiChecked("(WASM)");
2934 Handle<Code> code = info->code();
2935 Handle<SharedFunctionInfo> shared =
2936 isolate->factory()->NewSharedFunctionInfo(name_str, code, false);
Ben Murdochda12d292016-06-02 14:46:10 +01002937 PROFILE(isolate, CodeCreateEvent(tag, AbstractCode::cast(*code), *shared,
Ben Murdochc5610432016-08-08 18:44:38 +01002938 *script_str, 0, 0));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002939 }
2940}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002941
2942Handle<JSFunction> CompileJSToWasmWrapper(
2943 Isolate* isolate, wasm::ModuleEnv* module, Handle<String> name,
2944 Handle<Code> wasm_code, Handle<JSObject> module_object, uint32_t index) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01002945 const wasm::WasmFunction* func = &module->module->functions[index];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002946
2947 //----------------------------------------------------------------------------
2948 // Create the JSFunction object.
2949 //----------------------------------------------------------------------------
2950 Handle<SharedFunctionInfo> shared =
2951 isolate->factory()->NewSharedFunctionInfo(name, wasm_code, false);
2952 int params = static_cast<int>(func->sig->parameter_count());
2953 shared->set_length(params);
Ben Murdochda12d292016-06-02 14:46:10 +01002954 shared->set_internal_formal_parameter_count(params);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002955 Handle<JSFunction> function = isolate->factory()->NewFunction(
2956 isolate->wasm_function_map(), name, MaybeHandle<Code>());
2957 function->SetInternalField(0, *module_object);
2958 function->set_shared(*shared);
2959
2960 //----------------------------------------------------------------------------
2961 // Create the Graph
2962 //----------------------------------------------------------------------------
Ben Murdochda12d292016-06-02 14:46:10 +01002963 Zone zone(isolate->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002964 Graph graph(&zone);
2965 CommonOperatorBuilder common(&zone);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002966 MachineOperatorBuilder machine(&zone);
Ben Murdochc5610432016-08-08 18:44:38 +01002967 JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002968
2969 Node* control = nullptr;
2970 Node* effect = nullptr;
2971
2972 WasmGraphBuilder builder(&zone, &jsgraph, func->sig);
2973 builder.set_control_ptr(&control);
2974 builder.set_effect_ptr(&effect);
2975 builder.set_module(module);
2976 builder.BuildJSToWasmWrapper(wasm_code, func->sig);
2977
2978 //----------------------------------------------------------------------------
2979 // Run the compilation pipeline.
2980 //----------------------------------------------------------------------------
2981 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002982 if (FLAG_trace_turbo_graph) { // Simple textual RPO.
2983 OFStream os(stdout);
2984 os << "-- Graph after change lowering -- " << std::endl;
2985 os << AsRPO(graph);
2986 }
2987
2988 // Schedule and compile to machine code.
2989 int params = static_cast<int>(
2990 module->GetFunctionSignature(index)->parameter_count());
2991 CallDescriptor* incoming = Linkage::GetJSCallDescriptor(
2992 &zone, false, params + 1, CallDescriptor::kNoFlags);
Ben Murdochda12d292016-06-02 14:46:10 +01002993 Code::Flags flags = Code::ComputeFlags(Code::JS_TO_WASM_FUNCTION);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002994 bool debugging =
2995#if DEBUG
2996 true;
2997#else
2998 FLAG_print_opt_code || FLAG_trace_turbo || FLAG_trace_turbo_graph;
2999#endif
Ben Murdochc5610432016-08-08 18:44:38 +01003000 Vector<const char> func_name = ArrayVector("js-to-wasm");
Ben Murdoch097c5b22016-05-18 11:27:45 +01003001
3002 static unsigned id = 0;
3003 Vector<char> buffer;
3004 if (debugging) {
3005 buffer = Vector<char>::New(128);
Ben Murdochc5610432016-08-08 18:44:38 +01003006 int chars = SNPrintF(buffer, "js-to-wasm#%d", id);
3007 func_name = Vector<const char>::cast(buffer.SubVector(0, chars));
Ben Murdoch097c5b22016-05-18 11:27:45 +01003008 }
3009
3010 CompilationInfo info(func_name, isolate, &zone, flags);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003011 Handle<Code> code =
Ben Murdochc5610432016-08-08 18:44:38 +01003012 Pipeline::GenerateCodeForTesting(&info, incoming, &graph);
Ben Murdochda12d292016-06-02 14:46:10 +01003013#ifdef ENABLE_DISASSEMBLER
3014 if (FLAG_print_opt_code && !code.is_null()) {
3015 OFStream os(stdout);
3016 code->Disassemble(buffer.start(), os);
3017 }
3018#endif
Ben Murdoch097c5b22016-05-18 11:27:45 +01003019 if (debugging) {
3020 buffer.Dispose();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003021 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01003022
Ben Murdochda12d292016-06-02 14:46:10 +01003023 RecordFunctionCompilation(
Ben Murdoch61f157c2016-09-16 13:49:30 +01003024 CodeEventListener::FUNCTION_TAG, &info, "js-to-wasm", index,
Ben Murdochda12d292016-06-02 14:46:10 +01003025 module->module->GetName(func->name_offset, func->name_length));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003026 // Set the JSFunction's machine code.
3027 function->set_code(*code);
3028 }
3029 return function;
3030}
3031
Ben Murdoch61f157c2016-09-16 13:49:30 +01003032Handle<Code> CompileWasmToJSWrapper(Isolate* isolate,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003033 Handle<JSFunction> function,
Ben Murdochda12d292016-06-02 14:46:10 +01003034 wasm::FunctionSig* sig,
3035 wasm::WasmName module_name,
3036 wasm::WasmName function_name) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003037 //----------------------------------------------------------------------------
3038 // Create the Graph
3039 //----------------------------------------------------------------------------
Ben Murdochda12d292016-06-02 14:46:10 +01003040 Zone zone(isolate->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003041 Graph graph(&zone);
3042 CommonOperatorBuilder common(&zone);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003043 MachineOperatorBuilder machine(&zone);
Ben Murdochc5610432016-08-08 18:44:38 +01003044 JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003045
3046 Node* control = nullptr;
3047 Node* effect = nullptr;
3048
Ben Murdoch097c5b22016-05-18 11:27:45 +01003049 WasmGraphBuilder builder(&zone, &jsgraph, sig);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003050 builder.set_control_ptr(&control);
3051 builder.set_effect_ptr(&effect);
Ben Murdoch097c5b22016-05-18 11:27:45 +01003052 builder.BuildWasmToJSWrapper(function, sig);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003053
3054 Handle<Code> code = Handle<Code>::null();
3055 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003056 if (FLAG_trace_turbo_graph) { // Simple textual RPO.
3057 OFStream os(stdout);
3058 os << "-- Graph after change lowering -- " << std::endl;
3059 os << AsRPO(graph);
3060 }
3061
3062 // Schedule and compile to machine code.
Ben Murdoch097c5b22016-05-18 11:27:45 +01003063 CallDescriptor* incoming =
3064 wasm::ModuleEnv::GetWasmCallDescriptor(&zone, sig);
Ben Murdochc5610432016-08-08 18:44:38 +01003065 if (machine.Is32()) {
3066 incoming = wasm::ModuleEnv::GetI32WasmCallDescriptor(&zone, incoming);
3067 }
Ben Murdochda12d292016-06-02 14:46:10 +01003068 Code::Flags flags = Code::ComputeFlags(Code::WASM_TO_JS_FUNCTION);
Ben Murdoch097c5b22016-05-18 11:27:45 +01003069 bool debugging =
3070#if DEBUG
3071 true;
3072#else
3073 FLAG_print_opt_code || FLAG_trace_turbo || FLAG_trace_turbo_graph;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003074#endif
Ben Murdochc5610432016-08-08 18:44:38 +01003075 Vector<const char> func_name = ArrayVector("wasm-to-js");
Ben Murdoch097c5b22016-05-18 11:27:45 +01003076 static unsigned id = 0;
3077 Vector<char> buffer;
3078 if (debugging) {
3079 buffer = Vector<char>::New(128);
Ben Murdochc5610432016-08-08 18:44:38 +01003080 int chars = SNPrintF(buffer, "wasm-to-js#%d", id);
3081 func_name = Vector<const char>::cast(buffer.SubVector(0, chars));
Ben Murdoch097c5b22016-05-18 11:27:45 +01003082 }
3083
3084 CompilationInfo info(func_name, isolate, &zone, flags);
3085 code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr);
Ben Murdochda12d292016-06-02 14:46:10 +01003086#ifdef ENABLE_DISASSEMBLER
3087 if (FLAG_print_opt_code && !code.is_null()) {
3088 OFStream os(stdout);
3089 code->Disassemble(buffer.start(), os);
3090 }
3091#endif
Ben Murdoch097c5b22016-05-18 11:27:45 +01003092 if (debugging) {
3093 buffer.Dispose();
3094 }
3095
Ben Murdoch61f157c2016-09-16 13:49:30 +01003096 RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, &info,
3097 "wasm-to-js", 0, module_name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003098 }
3099 return code;
3100}
3101
Ben Murdoch61f157c2016-09-16 13:49:30 +01003102SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction(
Ben Murdochc5610432016-08-08 18:44:38 +01003103 double* decode_ms) {
Ben Murdochda12d292016-06-02 14:46:10 +01003104 base::ElapsedTimer decode_timer;
3105 if (FLAG_trace_wasm_decode_time) {
3106 decode_timer.Start();
3107 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003108 // Create a TF graph during decoding.
Ben Murdoch61f157c2016-09-16 13:49:30 +01003109
3110 Graph* graph = jsgraph_->graph();
3111 CommonOperatorBuilder* common = jsgraph_->common();
3112 MachineOperatorBuilder* machine = jsgraph_->machine();
Ben Murdochc5610432016-08-08 18:44:38 +01003113 SourcePositionTable* source_position_table =
Ben Murdoch61f157c2016-09-16 13:49:30 +01003114 new (jsgraph_->zone()) SourcePositionTable(graph);
3115 WasmGraphBuilder builder(jsgraph_->zone(), jsgraph_, function_->sig,
Ben Murdochc5610432016-08-08 18:44:38 +01003116 source_position_table);
Ben Murdochda12d292016-06-02 14:46:10 +01003117 wasm::FunctionBody body = {
Ben Murdoch61f157c2016-09-16 13:49:30 +01003118 module_env_, function_->sig, module_env_->module->module_start,
3119 module_env_->module->module_start + function_->code_start_offset,
3120 module_env_->module->module_start + function_->code_end_offset};
3121 graph_construction_result_ =
3122 wasm::BuildTFGraph(isolate_->allocator(), &builder, body);
3123
3124 if (graph_construction_result_.failed()) {
3125 if (FLAG_trace_wasm_compiler) {
3126 OFStream os(stdout);
3127 os << "Compilation failed: " << graph_construction_result_ << std::endl;
3128 }
3129 return nullptr;
3130 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003131
Ben Murdochc5610432016-08-08 18:44:38 +01003132 if (machine->Is32()) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01003133 Int64Lowering r(graph, machine, common, jsgraph_->zone(), function_->sig);
Ben Murdochc5610432016-08-08 18:44:38 +01003134 r.LowerGraph();
3135 }
3136
Ben Murdoch61f157c2016-09-16 13:49:30 +01003137 int index = static_cast<int>(function_->func_index);
Ben Murdochda12d292016-06-02 14:46:10 +01003138 if (index >= FLAG_trace_wasm_ast_start && index < FLAG_trace_wasm_ast_end) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01003139 OFStream os(stdout);
3140 PrintAst(isolate_->allocator(), body, os, nullptr);
Ben Murdochda12d292016-06-02 14:46:10 +01003141 }
Ben Murdochda12d292016-06-02 14:46:10 +01003142 if (FLAG_trace_wasm_decode_time) {
Ben Murdochc5610432016-08-08 18:44:38 +01003143 *decode_ms = decode_timer.Elapsed().InMillisecondsF();
Ben Murdochda12d292016-06-02 14:46:10 +01003144 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01003145 return source_position_table;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003146}
3147
Ben Murdoch61f157c2016-09-16 13:49:30 +01003148WasmCompilationUnit::WasmCompilationUnit(wasm::ErrorThrower* thrower,
3149 Isolate* isolate,
3150 wasm::ModuleEnv* module_env,
3151 const wasm::WasmFunction* function,
3152 uint32_t index)
3153 : thrower_(thrower),
3154 isolate_(isolate),
3155 module_env_(module_env),
3156 function_(function),
3157 graph_zone_(new Zone(isolate->allocator())),
3158 jsgraph_(new (graph_zone()) JSGraph(
3159 isolate, new (graph_zone()) Graph(graph_zone()),
3160 new (graph_zone()) CommonOperatorBuilder(graph_zone()), nullptr,
3161 nullptr, new (graph_zone()) MachineOperatorBuilder(
3162 graph_zone(), MachineType::PointerRepresentation(),
3163 InstructionSelector::SupportedMachineOperatorFlags()))),
3164 compilation_zone_(isolate->allocator()),
3165 info_(function->name_length != 0
3166 ? module_env->module->GetNameOrNull(function->name_offset,
3167 function->name_length)
3168 : ArrayVector("wasm"),
3169 isolate, &compilation_zone_,
3170 Code::ComputeFlags(Code::WASM_FUNCTION)),
3171 job_(),
3172 index_(index),
3173 ok_(true) {
3174 // Create and cache this node in the main thread.
3175 jsgraph_->CEntryStubConstant(1);
3176}
3177
3178void WasmCompilationUnit::ExecuteCompilation() {
3179 // TODO(ahaas): The counters are not thread-safe at the moment.
3180 // HistogramTimerScope wasm_compile_function_time_scope(
3181 // isolate_->counters()->wasm_compile_function_time());
3182 if (FLAG_trace_wasm_compiler) {
3183 OFStream os(stdout);
3184 os << "Compiling WASM function "
3185 << wasm::WasmFunctionName(function_, module_env_) << std::endl;
3186 os << std::endl;
Ben Murdochc5610432016-08-08 18:44:38 +01003187 }
3188
Ben Murdoch61f157c2016-09-16 13:49:30 +01003189 double decode_ms = 0;
3190 size_t node_count = 0;
Ben Murdochc5610432016-08-08 18:44:38 +01003191
Ben Murdoch61f157c2016-09-16 13:49:30 +01003192 base::SmartPointer<Zone> graph_zone(graph_zone_.Detach());
3193 SourcePositionTable* source_positions = BuildGraphForWasmFunction(&decode_ms);
Ben Murdochc5610432016-08-08 18:44:38 +01003194
Ben Murdoch61f157c2016-09-16 13:49:30 +01003195 if (graph_construction_result_.failed()) {
3196 ok_ = false;
3197 return;
Ben Murdochc5610432016-08-08 18:44:38 +01003198 }
3199
Ben Murdoch61f157c2016-09-16 13:49:30 +01003200 base::ElapsedTimer pipeline_timer;
3201 if (FLAG_trace_wasm_decode_time) {
3202 node_count = jsgraph_->graph()->NodeCount();
3203 pipeline_timer.Start();
Ben Murdochc5610432016-08-08 18:44:38 +01003204 }
3205
Ben Murdoch61f157c2016-09-16 13:49:30 +01003206 // Run the compiler pipeline to generate machine code.
3207 CallDescriptor* descriptor = wasm::ModuleEnv::GetWasmCallDescriptor(
3208 &compilation_zone_, function_->sig);
3209 if (jsgraph_->machine()->Is32()) {
3210 descriptor =
3211 module_env_->GetI32WasmCallDescriptor(&compilation_zone_, descriptor);
3212 }
3213 job_.Reset(Pipeline::NewWasmCompilationJob(&info_, jsgraph_->graph(),
3214 descriptor, source_positions));
Ben Murdochc5610432016-08-08 18:44:38 +01003215
Ben Murdoch61f157c2016-09-16 13:49:30 +01003216 // The function name {OptimizeGraph()} is misleading but necessary because we
3217 // want to use the CompilationJob interface. A better name would be
3218 // ScheduleGraphAndSelectInstructions.
3219 ok_ = job_->OptimizeGraph() == CompilationJob::SUCCEEDED;
3220 // TODO(bradnelson): Improve histogram handling of size_t.
3221 // TODO(ahaas): The counters are not thread-safe at the moment.
3222 // isolate_->counters()->wasm_compile_function_peak_memory_bytes()
3223 // ->AddSample(
3224 // static_cast<int>(jsgraph->graph()->zone()->allocation_size()));
3225
3226 if (FLAG_trace_wasm_decode_time) {
3227 double pipeline_ms = pipeline_timer.Elapsed().InMillisecondsF();
3228 PrintF(
3229 "wasm-compilation phase 1 ok: %d bytes, %0.3f ms decode, %zu nodes, "
3230 "%0.3f ms pipeline\n",
3231 static_cast<int>(function_->code_end_offset -
3232 function_->code_start_offset),
3233 decode_ms, node_count, pipeline_ms);
3234 }
Ben Murdochc5610432016-08-08 18:44:38 +01003235}
3236
Ben Murdoch61f157c2016-09-16 13:49:30 +01003237Handle<Code> WasmCompilationUnit::FinishCompilation() {
3238 if (!ok_) {
3239 if (graph_construction_result_.failed()) {
3240 // Add the function as another context for the exception
3241 ScopedVector<char> buffer(128);
3242 wasm::WasmName name = module_env_->module->GetName(
3243 function_->name_offset, function_->name_length);
3244 SNPrintF(buffer, "Compiling WASM function #%d:%.*s failed:",
3245 function_->func_index, name.length(), name.start());
3246 thrower_->Failed(buffer.start(), graph_construction_result_);
3247 }
Ben Murdochc5610432016-08-08 18:44:38 +01003248
Ben Murdoch61f157c2016-09-16 13:49:30 +01003249 return Handle<Code>::null();
3250 }
3251 if (job_->GenerateCode() != CompilationJob::SUCCEEDED) {
3252 return Handle<Code>::null();
3253 }
3254 base::ElapsedTimer compile_timer;
3255 if (FLAG_trace_wasm_decode_time) {
3256 compile_timer.Start();
3257 }
3258 Handle<Code> code = info_.code();
3259 DCHECK(!code.is_null());
Ben Murdochc5610432016-08-08 18:44:38 +01003260
Ben Murdoch61f157c2016-09-16 13:49:30 +01003261 RecordFunctionCompilation(
3262 CodeEventListener::FUNCTION_TAG, &info_, "WASM_function",
3263 function_->func_index,
3264 module_env_->module->GetName(function_->name_offset,
3265 function_->name_length));
Ben Murdochc5610432016-08-08 18:44:38 +01003266
Ben Murdoch61f157c2016-09-16 13:49:30 +01003267 if (FLAG_trace_wasm_decode_time) {
3268 double compile_ms = compile_timer.Elapsed().InMillisecondsF();
3269 PrintF("wasm-code-generation ok: %d bytes, %0.3f ms code generation\n",
3270 static_cast<int>(function_->code_end_offset -
3271 function_->code_start_offset),
3272 compile_ms);
3273 }
3274
3275 return code;
Ben Murdochc5610432016-08-08 18:44:38 +01003276}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003277
3278} // namespace compiler
3279} // namespace internal
3280} // namespace v8