blob: 93d5a084b9a9ce7954d4101760c14426a12b892b [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"
13#include "src/compiler/change-lowering.h"
14#include "src/compiler/common-operator.h"
15#include "src/compiler/diamond.h"
16#include "src/compiler/graph.h"
17#include "src/compiler/graph-visualizer.h"
18#include "src/compiler/instruction-selector.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010019#include "src/compiler/int64-lowering.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000020#include "src/compiler/js-generic-lowering.h"
21#include "src/compiler/js-graph.h"
22#include "src/compiler/js-operator.h"
23#include "src/compiler/linkage.h"
24#include "src/compiler/machine-operator.h"
25#include "src/compiler/node-matchers.h"
26#include "src/compiler/pipeline.h"
27#include "src/compiler/simplified-lowering.h"
28#include "src/compiler/simplified-operator.h"
29#include "src/compiler/source-position.h"
30#include "src/compiler/typer.h"
31
32#include "src/code-factory.h"
33#include "src/code-stubs.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010034#include "src/factory.h"
35#include "src/log-inl.h"
36#include "src/profiler/cpu-profiler.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000037
38#include "src/wasm/ast-decoder.h"
39#include "src/wasm/wasm-module.h"
40#include "src/wasm/wasm-opcodes.h"
41
42// TODO(titzer): pull WASM_64 up to a common header.
43#if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64
44#define WASM_64 1
45#else
46#define WASM_64 0
47#endif
48
49namespace v8 {
50namespace internal {
51namespace compiler {
52
53namespace {
54const Operator* UnsupportedOpcode(wasm::WasmOpcode opcode) {
55 if (wasm::WasmOpcodes::IsSupported(opcode)) {
56 V8_Fatal(__FILE__, __LINE__,
57 "Unsupported opcode #%d:%s reported as supported", opcode,
58 wasm::WasmOpcodes::OpcodeName(opcode));
59 }
60 V8_Fatal(__FILE__, __LINE__, "Unsupported opcode #%d:%s", opcode,
61 wasm::WasmOpcodes::OpcodeName(opcode));
62 return nullptr;
63}
64
65
66void MergeControlToEnd(JSGraph* jsgraph, Node* node) {
67 Graph* g = jsgraph->graph();
68 if (g->end()) {
69 NodeProperties::MergeControlToEnd(g, jsgraph->common(), node);
70 } else {
71 g->SetEnd(g->NewNode(jsgraph->common()->End(1), node));
72 }
73}
74
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000075} // namespace
76
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000077// A helper that handles building graph fragments for trapping.
78// To avoid generating a ton of redundant code that just calls the runtime
79// to trap, we generate a per-trap-reason block of code that all trap sites
80// in this function will branch to.
81class WasmTrapHelper : public ZoneObject {
82 public:
83 explicit WasmTrapHelper(WasmGraphBuilder* builder)
84 : builder_(builder),
85 jsgraph_(builder->jsgraph()),
86 graph_(builder->jsgraph() ? builder->jsgraph()->graph() : nullptr) {
Ben Murdochda12d292016-06-02 14:46:10 +010087 for (int i = 0; i < wasm::kTrapCount; i++) traps_[i] = nullptr;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000088 }
89
90 // Make the current control path trap to unreachable.
Ben Murdochda12d292016-06-02 14:46:10 +010091 void Unreachable() { ConnectTrap(wasm::kTrapUnreachable); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000092
Ben Murdoch097c5b22016-05-18 11:27:45 +010093 // Always trap with the given reason.
Ben Murdochda12d292016-06-02 14:46:10 +010094 void TrapAlways(wasm::TrapReason reason) { ConnectTrap(reason); }
Ben Murdoch097c5b22016-05-18 11:27:45 +010095
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000096 // Add a check that traps if {node} is equal to {val}.
Ben Murdochda12d292016-06-02 14:46:10 +010097 Node* TrapIfEq32(wasm::TrapReason reason, Node* node, int32_t val) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000098 Int32Matcher m(node);
99 if (m.HasValue() && !m.Is(val)) return graph()->start();
100 if (val == 0) {
101 AddTrapIfFalse(reason, node);
102 } else {
103 AddTrapIfTrue(reason,
104 graph()->NewNode(jsgraph()->machine()->Word32Equal(), node,
105 jsgraph()->Int32Constant(val)));
106 }
107 return builder_->Control();
108 }
109
110 // Add a check that traps if {node} is zero.
Ben Murdochda12d292016-06-02 14:46:10 +0100111 Node* ZeroCheck32(wasm::TrapReason reason, Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000112 return TrapIfEq32(reason, node, 0);
113 }
114
115 // Add a check that traps if {node} is equal to {val}.
Ben Murdochda12d292016-06-02 14:46:10 +0100116 Node* TrapIfEq64(wasm::TrapReason reason, Node* node, int64_t val) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000117 Int64Matcher m(node);
118 if (m.HasValue() && !m.Is(val)) return graph()->start();
119 AddTrapIfTrue(reason,
120 graph()->NewNode(jsgraph()->machine()->Word64Equal(), node,
121 jsgraph()->Int64Constant(val)));
122 return builder_->Control();
123 }
124
125 // Add a check that traps if {node} is zero.
Ben Murdochda12d292016-06-02 14:46:10 +0100126 Node* ZeroCheck64(wasm::TrapReason reason, Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000127 return TrapIfEq64(reason, node, 0);
128 }
129
130 // Add a trap if {cond} is true.
Ben Murdochda12d292016-06-02 14:46:10 +0100131 void AddTrapIfTrue(wasm::TrapReason reason, Node* cond) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000132 AddTrapIf(reason, cond, true);
133 }
134
135 // Add a trap if {cond} is false.
Ben Murdochda12d292016-06-02 14:46:10 +0100136 void AddTrapIfFalse(wasm::TrapReason reason, Node* cond) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000137 AddTrapIf(reason, cond, false);
138 }
139
140 // Add a trap if {cond} is true or false according to {iftrue}.
Ben Murdochda12d292016-06-02 14:46:10 +0100141 void AddTrapIf(wasm::TrapReason reason, Node* cond, bool iftrue) {
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;
151 ConnectTrap(reason);
152 *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 Murdochda12d292016-06-02 14:46:10 +0100182 Node* traps_[wasm::kTrapCount];
183 Node* effects_[wasm::kTrapCount];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000184
185 JSGraph* jsgraph() { return jsgraph_; }
186 Graph* graph() { return jsgraph_->graph(); }
187 CommonOperatorBuilder* common() { return jsgraph()->common(); }
188
Ben Murdochda12d292016-06-02 14:46:10 +0100189 void ConnectTrap(wasm::TrapReason reason) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000190 if (traps_[reason] == nullptr) {
191 // Create trap code for the first time this trap is used.
192 return BuildTrapCode(reason);
193 }
194 // Connect the current control and effect to the existing trap code.
195 builder_->AppendToMerge(traps_[reason], builder_->Control());
196 builder_->AppendToPhi(traps_[reason], effects_[reason], builder_->Effect());
197 }
198
Ben Murdochda12d292016-06-02 14:46:10 +0100199 void BuildTrapCode(wasm::TrapReason reason) {
200 Node* exception =
201 builder_->String(wasm::WasmOpcodes::TrapReasonName(reason));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000202 Node* end;
203 Node** control_ptr = builder_->control_;
204 Node** effect_ptr = builder_->effect_;
205 wasm::ModuleEnv* module = builder_->module_;
206 *control_ptr = traps_[reason] =
207 graph()->NewNode(common()->Merge(1), *control_ptr);
208 *effect_ptr = effects_[reason] =
209 graph()->NewNode(common()->EffectPhi(1), *effect_ptr, *control_ptr);
210
Ben Murdoch097c5b22016-05-18 11:27:45 +0100211 if (module && !module->instance->context.is_null()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000212 // Use the module context to call the runtime to throw an exception.
213 Runtime::FunctionId f = Runtime::kThrow;
214 const Runtime::Function* fun = Runtime::FunctionForId(f);
215 CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
216 jsgraph()->zone(), f, fun->nargs, Operator::kNoProperties,
217 CallDescriptor::kNoFlags);
218 Node* inputs[] = {
219 jsgraph()->CEntryStubConstant(fun->result_size), // C entry
220 exception, // exception
221 jsgraph()->ExternalConstant(
222 ExternalReference(f, jsgraph()->isolate())), // ref
223 jsgraph()->Int32Constant(fun->nargs), // arity
Ben Murdoch097c5b22016-05-18 11:27:45 +0100224 jsgraph()->Constant(module->instance->context), // context
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000225 *effect_ptr,
226 *control_ptr};
227
228 Node* node = graph()->NewNode(
229 common()->Call(desc), static_cast<int>(arraysize(inputs)), inputs);
230 *control_ptr = node;
231 *effect_ptr = node;
232 }
233 if (false) {
234 // End the control flow with a throw
235 Node* thrw =
236 graph()->NewNode(common()->Throw(), jsgraph()->ZeroConstant(),
237 *effect_ptr, *control_ptr);
238 end = thrw;
239 } else {
240 // End the control flow with returning 0xdeadbeef
Ben Murdoch097c5b22016-05-18 11:27:45 +0100241 Node* ret_value = GetTrapValue(builder_->GetFunctionSignature());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000242 end = graph()->NewNode(jsgraph()->common()->Return(), ret_value,
243 *effect_ptr, *control_ptr);
244 }
245
246 MergeControlToEnd(jsgraph(), end);
247 }
248};
249
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000250WasmGraphBuilder::WasmGraphBuilder(Zone* zone, JSGraph* jsgraph,
251 wasm::FunctionSig* function_signature)
252 : zone_(zone),
253 jsgraph_(jsgraph),
254 module_(nullptr),
255 mem_buffer_(nullptr),
256 mem_size_(nullptr),
257 function_table_(nullptr),
258 control_(nullptr),
259 effect_(nullptr),
260 cur_buffer_(def_buffer_),
261 cur_bufsize_(kDefaultBufferSize),
262 trap_(new (zone) WasmTrapHelper(this)),
263 function_signature_(function_signature) {
264 DCHECK_NOT_NULL(jsgraph_);
265}
266
267
268Node* WasmGraphBuilder::Error() { return jsgraph()->Dead(); }
269
270
271Node* WasmGraphBuilder::Start(unsigned params) {
272 Node* start = graph()->NewNode(jsgraph()->common()->Start(params));
273 graph()->SetStart(start);
274 return start;
275}
276
277
278Node* WasmGraphBuilder::Param(unsigned index, wasm::LocalType type) {
279 return graph()->NewNode(jsgraph()->common()->Parameter(index),
280 graph()->start());
281}
282
283
284Node* WasmGraphBuilder::Loop(Node* entry) {
285 return graph()->NewNode(jsgraph()->common()->Loop(1), entry);
286}
287
288
289Node* WasmGraphBuilder::Terminate(Node* effect, Node* control) {
290 Node* terminate =
291 graph()->NewNode(jsgraph()->common()->Terminate(), effect, control);
292 MergeControlToEnd(jsgraph(), terminate);
293 return terminate;
294}
295
296
297unsigned WasmGraphBuilder::InputCount(Node* node) {
298 return static_cast<unsigned>(node->InputCount());
299}
300
301
302bool WasmGraphBuilder::IsPhiWithMerge(Node* phi, Node* merge) {
303 return phi && IrOpcode::IsPhiOpcode(phi->opcode()) &&
304 NodeProperties::GetControlInput(phi) == merge;
305}
306
307
308void WasmGraphBuilder::AppendToMerge(Node* merge, Node* from) {
309 DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
310 merge->AppendInput(jsgraph()->zone(), from);
311 int new_size = merge->InputCount();
312 NodeProperties::ChangeOp(
313 merge, jsgraph()->common()->ResizeMergeOrPhi(merge->op(), new_size));
314}
315
316
317void WasmGraphBuilder::AppendToPhi(Node* merge, Node* phi, Node* from) {
318 DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
319 DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
320 int new_size = phi->InputCount();
321 phi->InsertInput(jsgraph()->zone(), phi->InputCount() - 1, from);
322 NodeProperties::ChangeOp(
323 phi, jsgraph()->common()->ResizeMergeOrPhi(phi->op(), new_size));
324}
325
326
327Node* WasmGraphBuilder::Merge(unsigned count, Node** controls) {
328 return graph()->NewNode(jsgraph()->common()->Merge(count), count, controls);
329}
330
331
332Node* WasmGraphBuilder::Phi(wasm::LocalType type, unsigned count, Node** vals,
333 Node* control) {
334 DCHECK(IrOpcode::IsMergeOpcode(control->opcode()));
Ben Murdochda12d292016-06-02 14:46:10 +0100335 Node** buf = Realloc(vals, count, count + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000336 buf[count] = control;
337 return graph()->NewNode(jsgraph()->common()->Phi(type, count), count + 1,
338 buf);
339}
340
341
342Node* WasmGraphBuilder::EffectPhi(unsigned count, Node** effects,
343 Node* control) {
344 DCHECK(IrOpcode::IsMergeOpcode(control->opcode()));
Ben Murdochda12d292016-06-02 14:46:10 +0100345 Node** buf = Realloc(effects, count, count + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000346 buf[count] = control;
347 return graph()->NewNode(jsgraph()->common()->EffectPhi(count), count + 1,
348 buf);
349}
350
351
352Node* WasmGraphBuilder::Int32Constant(int32_t value) {
353 return jsgraph()->Int32Constant(value);
354}
355
356
357Node* WasmGraphBuilder::Int64Constant(int64_t value) {
358 return jsgraph()->Int64Constant(value);
359}
360
361
362Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left,
363 Node* right) {
364 const Operator* op;
365 MachineOperatorBuilder* m = jsgraph()->machine();
366 switch (opcode) {
367 case wasm::kExprI32Add:
368 op = m->Int32Add();
369 break;
370 case wasm::kExprI32Sub:
371 op = m->Int32Sub();
372 break;
373 case wasm::kExprI32Mul:
374 op = m->Int32Mul();
375 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100376 case wasm::kExprI32DivS:
377 return BuildI32DivS(left, right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000378 case wasm::kExprI32DivU:
Ben Murdochda12d292016-06-02 14:46:10 +0100379 return BuildI32DivU(left, right);
380 case wasm::kExprI32RemS:
381 return BuildI32RemS(left, right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000382 case wasm::kExprI32RemU:
Ben Murdochda12d292016-06-02 14:46:10 +0100383 return BuildI32RemU(left, right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000384 case wasm::kExprI32And:
385 op = m->Word32And();
386 break;
387 case wasm::kExprI32Ior:
388 op = m->Word32Or();
389 break;
390 case wasm::kExprI32Xor:
391 op = m->Word32Xor();
392 break;
393 case wasm::kExprI32Shl:
394 op = m->Word32Shl();
Ben Murdochda12d292016-06-02 14:46:10 +0100395 right = MaskShiftCount32(right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000396 break;
397 case wasm::kExprI32ShrU:
398 op = m->Word32Shr();
Ben Murdochda12d292016-06-02 14:46:10 +0100399 right = MaskShiftCount32(right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000400 break;
401 case wasm::kExprI32ShrS:
402 op = m->Word32Sar();
Ben Murdochda12d292016-06-02 14:46:10 +0100403 right = MaskShiftCount32(right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000404 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100405 case wasm::kExprI32Ror:
406 op = m->Word32Ror();
407 right = MaskShiftCount32(right);
408 break;
409 case wasm::kExprI32Rol:
410 right = MaskShiftCount32(right);
411 return BuildI32Rol(left, right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000412 case wasm::kExprI32Eq:
413 op = m->Word32Equal();
414 break;
415 case wasm::kExprI32Ne:
416 return Invert(Binop(wasm::kExprI32Eq, left, right));
417 case wasm::kExprI32LtS:
418 op = m->Int32LessThan();
419 break;
420 case wasm::kExprI32LeS:
421 op = m->Int32LessThanOrEqual();
422 break;
423 case wasm::kExprI32LtU:
424 op = m->Uint32LessThan();
425 break;
426 case wasm::kExprI32LeU:
427 op = m->Uint32LessThanOrEqual();
428 break;
429 case wasm::kExprI32GtS:
430 op = m->Int32LessThan();
431 std::swap(left, right);
432 break;
433 case wasm::kExprI32GeS:
434 op = m->Int32LessThanOrEqual();
435 std::swap(left, right);
436 break;
437 case wasm::kExprI32GtU:
438 op = m->Uint32LessThan();
439 std::swap(left, right);
440 break;
441 case wasm::kExprI32GeU:
442 op = m->Uint32LessThanOrEqual();
443 std::swap(left, right);
444 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100445 case wasm::kExprI64And:
446 op = m->Word64And();
447 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100448 // todo(ahaas): I added a list of missing instructions here to make merging
449 // easier when I do them one by one.
450 // kExprI64Add:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000451 case wasm::kExprI64Add:
452 op = m->Int64Add();
453 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100454 // kExprI64Sub:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000455 case wasm::kExprI64Sub:
456 op = m->Int64Sub();
457 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100458 // kExprI64Mul:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000459 case wasm::kExprI64Mul:
460 op = m->Int64Mul();
461 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100462 // kExprI64DivS:
463 case wasm::kExprI64DivS:
464 return BuildI64DivS(left, right);
465 // kExprI64DivU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000466 case wasm::kExprI64DivU:
Ben Murdochda12d292016-06-02 14:46:10 +0100467 return BuildI64DivU(left, right);
468 // kExprI64RemS:
469 case wasm::kExprI64RemS:
470 return BuildI64RemS(left, right);
471 // kExprI64RemU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000472 case wasm::kExprI64RemU:
Ben Murdochda12d292016-06-02 14:46:10 +0100473 return BuildI64RemU(left, right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000474 case wasm::kExprI64Ior:
475 op = m->Word64Or();
476 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100477// kExprI64Xor:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000478 case wasm::kExprI64Xor:
479 op = m->Word64Xor();
480 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100481// kExprI64Shl:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000482 case wasm::kExprI64Shl:
483 op = m->Word64Shl();
Ben Murdochda12d292016-06-02 14:46:10 +0100484 right = MaskShiftCount64(right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000485 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100486 // kExprI64ShrU:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000487 case wasm::kExprI64ShrU:
488 op = m->Word64Shr();
Ben Murdochda12d292016-06-02 14:46:10 +0100489 right = MaskShiftCount64(right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000490 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100491 // kExprI64ShrS:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000492 case wasm::kExprI64ShrS:
493 op = m->Word64Sar();
Ben Murdochda12d292016-06-02 14:46:10 +0100494 right = MaskShiftCount64(right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000495 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100496 // kExprI64Eq:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000497 case wasm::kExprI64Eq:
498 op = m->Word64Equal();
499 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100500// kExprI64Ne:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000501 case wasm::kExprI64Ne:
502 return Invert(Binop(wasm::kExprI64Eq, left, right));
Ben Murdochda12d292016-06-02 14:46:10 +0100503// kExprI64LtS:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000504 case wasm::kExprI64LtS:
505 op = m->Int64LessThan();
506 break;
507 case wasm::kExprI64LeS:
508 op = m->Int64LessThanOrEqual();
509 break;
510 case wasm::kExprI64LtU:
511 op = m->Uint64LessThan();
512 break;
513 case wasm::kExprI64LeU:
514 op = m->Uint64LessThanOrEqual();
515 break;
516 case wasm::kExprI64GtS:
517 op = m->Int64LessThan();
518 std::swap(left, right);
519 break;
520 case wasm::kExprI64GeS:
521 op = m->Int64LessThanOrEqual();
522 std::swap(left, right);
523 break;
524 case wasm::kExprI64GtU:
525 op = m->Uint64LessThan();
526 std::swap(left, right);
527 break;
528 case wasm::kExprI64GeU:
529 op = m->Uint64LessThanOrEqual();
530 std::swap(left, right);
531 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100532 case wasm::kExprI64Ror:
533 op = m->Word64Ror();
534 right = MaskShiftCount64(right);
535 break;
536 case wasm::kExprI64Rol:
537 return BuildI64Rol(left, right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000538 case wasm::kExprF32CopySign:
539 return BuildF32CopySign(left, right);
540 case wasm::kExprF64CopySign:
541 return BuildF64CopySign(left, right);
542 case wasm::kExprF32Add:
543 op = m->Float32Add();
544 break;
545 case wasm::kExprF32Sub:
546 op = m->Float32Sub();
547 break;
548 case wasm::kExprF32Mul:
549 op = m->Float32Mul();
550 break;
551 case wasm::kExprF32Div:
552 op = m->Float32Div();
553 break;
554 case wasm::kExprF32Eq:
555 op = m->Float32Equal();
556 break;
557 case wasm::kExprF32Ne:
558 return Invert(Binop(wasm::kExprF32Eq, left, right));
559 case wasm::kExprF32Lt:
560 op = m->Float32LessThan();
561 break;
562 case wasm::kExprF32Ge:
563 op = m->Float32LessThanOrEqual();
564 std::swap(left, right);
565 break;
566 case wasm::kExprF32Gt:
567 op = m->Float32LessThan();
568 std::swap(left, right);
569 break;
570 case wasm::kExprF32Le:
571 op = m->Float32LessThanOrEqual();
572 break;
573 case wasm::kExprF64Add:
574 op = m->Float64Add();
575 break;
576 case wasm::kExprF64Sub:
577 op = m->Float64Sub();
578 break;
579 case wasm::kExprF64Mul:
580 op = m->Float64Mul();
581 break;
582 case wasm::kExprF64Div:
583 op = m->Float64Div();
584 break;
585 case wasm::kExprF64Eq:
586 op = m->Float64Equal();
587 break;
588 case wasm::kExprF64Ne:
589 return Invert(Binop(wasm::kExprF64Eq, left, right));
590 case wasm::kExprF64Lt:
591 op = m->Float64LessThan();
592 break;
593 case wasm::kExprF64Le:
594 op = m->Float64LessThanOrEqual();
595 break;
596 case wasm::kExprF64Gt:
597 op = m->Float64LessThan();
598 std::swap(left, right);
599 break;
600 case wasm::kExprF64Ge:
601 op = m->Float64LessThanOrEqual();
602 std::swap(left, right);
603 break;
604 case wasm::kExprF32Min:
605 return BuildF32Min(left, right);
606 case wasm::kExprF64Min:
607 return BuildF64Min(left, right);
608 case wasm::kExprF32Max:
609 return BuildF32Max(left, right);
610 case wasm::kExprF64Max:
611 return BuildF64Max(left, right);
Ben Murdochda12d292016-06-02 14:46:10 +0100612 case wasm::kExprF64Pow: {
613 return BuildF64Pow(left, right);
614 }
615 case wasm::kExprF64Atan2: {
616 return BuildF64Atan2(left, right);
617 }
618 case wasm::kExprF64Mod: {
619 return BuildF64Mod(left, right);
620 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000621 default:
622 op = UnsupportedOpcode(opcode);
623 }
624 return graph()->NewNode(op, left, right);
625}
626
627
628Node* WasmGraphBuilder::Unop(wasm::WasmOpcode opcode, Node* input) {
629 const Operator* op;
630 MachineOperatorBuilder* m = jsgraph()->machine();
631 switch (opcode) {
Ben Murdochda12d292016-06-02 14:46:10 +0100632 case wasm::kExprI32Eqz:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000633 op = m->Word32Equal();
634 return graph()->NewNode(op, input, jsgraph()->Int32Constant(0));
635 case wasm::kExprF32Abs:
636 op = m->Float32Abs();
637 break;
638 case wasm::kExprF32Neg:
639 return BuildF32Neg(input);
640 case wasm::kExprF32Sqrt:
641 op = m->Float32Sqrt();
642 break;
643 case wasm::kExprF64Abs:
644 op = m->Float64Abs();
645 break;
646 case wasm::kExprF64Neg:
647 return BuildF64Neg(input);
648 case wasm::kExprF64Sqrt:
649 op = m->Float64Sqrt();
650 break;
651 case wasm::kExprI32SConvertF64:
652 return BuildI32SConvertF64(input);
653 case wasm::kExprI32UConvertF64:
654 return BuildI32UConvertF64(input);
655 case wasm::kExprF32ConvertF64:
656 op = m->TruncateFloat64ToFloat32();
657 break;
658 case wasm::kExprF64SConvertI32:
659 op = m->ChangeInt32ToFloat64();
660 break;
661 case wasm::kExprF64UConvertI32:
662 op = m->ChangeUint32ToFloat64();
663 break;
664 case wasm::kExprF32SConvertI32:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100665 op = m->RoundInt32ToFloat32();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000666 break;
667 case wasm::kExprF32UConvertI32:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100668 op = m->RoundUint32ToFloat32();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000669 break;
670 case wasm::kExprI32SConvertF32:
671 return BuildI32SConvertF32(input);
672 case wasm::kExprI32UConvertF32:
673 return BuildI32UConvertF32(input);
674 case wasm::kExprF64ConvertF32:
675 op = m->ChangeFloat32ToFloat64();
676 break;
677 case wasm::kExprF32ReinterpretI32:
678 op = m->BitcastInt32ToFloat32();
679 break;
680 case wasm::kExprI32ReinterpretF32:
681 op = m->BitcastFloat32ToInt32();
682 break;
683 case wasm::kExprI32Clz:
684 op = m->Word32Clz();
685 break;
686 case wasm::kExprI32Ctz: {
687 if (m->Word32Ctz().IsSupported()) {
688 op = m->Word32Ctz().op();
689 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100690 } else if (m->Word32ReverseBits().IsSupported()) {
691 Node* reversed = graph()->NewNode(m->Word32ReverseBits().op(), input);
692 Node* result = graph()->NewNode(m->Word32Clz(), reversed);
693 return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000694 } else {
695 return BuildI32Ctz(input);
696 }
697 }
698 case wasm::kExprI32Popcnt: {
699 if (m->Word32Popcnt().IsSupported()) {
700 op = m->Word32Popcnt().op();
701 break;
702 } else {
703 return BuildI32Popcnt(input);
704 }
705 }
706 case wasm::kExprF32Floor: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100707 if (!m->Float32RoundDown().IsSupported()) return BuildF32Floor(input);
708 op = m->Float32RoundDown().op();
709 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000710 }
711 case wasm::kExprF32Ceil: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100712 if (!m->Float32RoundUp().IsSupported()) return BuildF32Ceil(input);
713 op = m->Float32RoundUp().op();
714 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000715 }
716 case wasm::kExprF32Trunc: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100717 if (!m->Float32RoundTruncate().IsSupported()) return BuildF32Trunc(input);
718 op = m->Float32RoundTruncate().op();
719 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000720 }
721 case wasm::kExprF32NearestInt: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100722 if (!m->Float32RoundTiesEven().IsSupported())
723 return BuildF32NearestInt(input);
724 op = m->Float32RoundTiesEven().op();
725 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000726 }
727 case wasm::kExprF64Floor: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100728 if (!m->Float64RoundDown().IsSupported()) return BuildF64Floor(input);
729 op = m->Float64RoundDown().op();
730 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000731 }
732 case wasm::kExprF64Ceil: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100733 if (!m->Float64RoundUp().IsSupported()) return BuildF64Ceil(input);
734 op = m->Float64RoundUp().op();
735 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000736 }
737 case wasm::kExprF64Trunc: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100738 if (!m->Float64RoundTruncate().IsSupported()) return BuildF64Trunc(input);
739 op = m->Float64RoundTruncate().op();
740 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000741 }
742 case wasm::kExprF64NearestInt: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100743 if (!m->Float64RoundTiesEven().IsSupported())
744 return BuildF64NearestInt(input);
745 op = m->Float64RoundTiesEven().op();
746 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000747 }
Ben Murdochda12d292016-06-02 14:46:10 +0100748 case wasm::kExprF64Acos: {
749 return BuildF64Acos(input);
750 }
751 case wasm::kExprF64Asin: {
752 return BuildF64Asin(input);
753 }
754 case wasm::kExprF64Atan: {
755 return BuildF64Atan(input);
756 }
757 case wasm::kExprF64Cos: {
758 return BuildF64Cos(input);
759 }
760 case wasm::kExprF64Sin: {
761 return BuildF64Sin(input);
762 }
763 case wasm::kExprF64Tan: {
764 return BuildF64Tan(input);
765 }
766 case wasm::kExprF64Exp: {
767 return BuildF64Exp(input);
768 }
769 case wasm::kExprF64Log: {
770 return BuildF64Log(input);
771 }
772 // kExprI32ConvertI64:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000773 case wasm::kExprI32ConvertI64:
774 op = m->TruncateInt64ToInt32();
775 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100776 // kExprI64SConvertI32:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000777 case wasm::kExprI64SConvertI32:
778 op = m->ChangeInt32ToInt64();
779 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100780 // kExprI64UConvertI32:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000781 case wasm::kExprI64UConvertI32:
782 op = m->ChangeUint32ToUint64();
783 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100784 // kExprF64ReinterpretI64:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000785 case wasm::kExprF64ReinterpretI64:
786 op = m->BitcastInt64ToFloat64();
787 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100788 // kExprI64ReinterpretF64:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000789 case wasm::kExprI64ReinterpretF64:
790 op = m->BitcastFloat64ToInt64();
791 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100792 // kExprI64Clz:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000793 case wasm::kExprI64Clz:
794 op = m->Word64Clz();
795 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100796 // kExprI64Ctz:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000797 case wasm::kExprI64Ctz: {
798 if (m->Word64Ctz().IsSupported()) {
799 op = m->Word64Ctz().op();
800 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100801 } else if (m->Is32() && m->Word32Ctz().IsSupported()) {
802 op = m->Word64CtzPlaceholder();
803 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100804 } else if (m->Word64ReverseBits().IsSupported()) {
805 Node* reversed = graph()->NewNode(m->Word64ReverseBits().op(), input);
806 Node* result = graph()->NewNode(m->Word64Clz(), reversed);
807 return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000808 } else {
809 return BuildI64Ctz(input);
810 }
811 }
Ben Murdochda12d292016-06-02 14:46:10 +0100812 // kExprI64Popcnt:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000813 case wasm::kExprI64Popcnt: {
814 if (m->Word64Popcnt().IsSupported()) {
815 op = m->Word64Popcnt().op();
Ben Murdochda12d292016-06-02 14:46:10 +0100816 } else if (m->Is32() && m->Word32Popcnt().IsSupported()) {
817 op = m->Word64PopcntPlaceholder();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000818 } else {
819 return BuildI64Popcnt(input);
820 }
Ben Murdochda12d292016-06-02 14:46:10 +0100821 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000822 }
Ben Murdochda12d292016-06-02 14:46:10 +0100823 // kExprF32SConvertI64:
824 case wasm::kExprI64Eqz:
825 op = m->Word64Equal();
826 return graph()->NewNode(op, input, jsgraph()->Int64Constant(0));
827 case wasm::kExprF32SConvertI64:
828 if (m->Is32()) {
829 return BuildF32SConvertI64(input);
830 }
831 op = m->RoundInt64ToFloat32();
832 break;
833 // kExprF32UConvertI64:
834 case wasm::kExprF32UConvertI64:
835 if (m->Is32()) {
836 return BuildF32UConvertI64(input);
837 }
838 op = m->RoundUint64ToFloat32();
839 break;
840 // kExprF64SConvertI64:
841 case wasm::kExprF64SConvertI64:
842 if (m->Is32()) {
843 return BuildF64SConvertI64(input);
844 }
845 op = m->RoundInt64ToFloat64();
846 break;
847 // kExprF64UConvertI64:
848 case wasm::kExprF64UConvertI64:
849 if (m->Is32()) {
850 return BuildF64UConvertI64(input);
851 }
852 op = m->RoundUint64ToFloat64();
853 break;
854// kExprI64SConvertF32:
855 case wasm::kExprI64SConvertF32: {
856 return BuildI64SConvertF32(input);
857 }
858 // kExprI64SConvertF64:
859 case wasm::kExprI64SConvertF64: {
860 return BuildI64SConvertF64(input);
861 }
862 // kExprI64UConvertF32:
863 case wasm::kExprI64UConvertF32: {
864 return BuildI64UConvertF32(input);
865 }
866 // kExprI64UConvertF64:
867 case wasm::kExprI64UConvertF64: {
868 return BuildI64UConvertF64(input);
869 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000870 default:
871 op = UnsupportedOpcode(opcode);
872 }
873 return graph()->NewNode(op, input);
874}
875
876
877Node* WasmGraphBuilder::Float32Constant(float value) {
878 return jsgraph()->Float32Constant(value);
879}
880
881
882Node* WasmGraphBuilder::Float64Constant(double value) {
883 return jsgraph()->Float64Constant(value);
884}
885
886
887Node* WasmGraphBuilder::Constant(Handle<Object> value) {
888 return jsgraph()->Constant(value);
889}
890
891
892Node* WasmGraphBuilder::Branch(Node* cond, Node** true_node,
893 Node** false_node) {
894 DCHECK_NOT_NULL(cond);
895 DCHECK_NOT_NULL(*control_);
896 Node* branch =
897 graph()->NewNode(jsgraph()->common()->Branch(), cond, *control_);
898 *true_node = graph()->NewNode(jsgraph()->common()->IfTrue(), branch);
899 *false_node = graph()->NewNode(jsgraph()->common()->IfFalse(), branch);
900 return branch;
901}
902
903
904Node* WasmGraphBuilder::Switch(unsigned count, Node* key) {
905 return graph()->NewNode(jsgraph()->common()->Switch(count), key, *control_);
906}
907
908
909Node* WasmGraphBuilder::IfValue(int32_t value, Node* sw) {
910 DCHECK_EQ(IrOpcode::kSwitch, sw->opcode());
911 return graph()->NewNode(jsgraph()->common()->IfValue(value), sw);
912}
913
914
915Node* WasmGraphBuilder::IfDefault(Node* sw) {
916 DCHECK_EQ(IrOpcode::kSwitch, sw->opcode());
917 return graph()->NewNode(jsgraph()->common()->IfDefault(), sw);
918}
919
920
921Node* WasmGraphBuilder::Return(unsigned count, Node** vals) {
922 DCHECK_NOT_NULL(*control_);
923 DCHECK_NOT_NULL(*effect_);
924
925 if (count == 0) {
926 // Handle a return of void.
927 vals[0] = jsgraph()->Int32Constant(0);
928 count = 1;
929 }
930
Ben Murdochda12d292016-06-02 14:46:10 +0100931 Node** buf = Realloc(vals, count, count + 2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000932 buf[count] = *effect_;
933 buf[count + 1] = *control_;
934 Node* ret = graph()->NewNode(jsgraph()->common()->Return(), count + 2, vals);
935
936 MergeControlToEnd(jsgraph(), ret);
937 return ret;
938}
939
940
941Node* WasmGraphBuilder::ReturnVoid() { return Return(0, Buffer(0)); }
942
943
944Node* WasmGraphBuilder::Unreachable() {
945 trap_->Unreachable();
946 return nullptr;
947}
948
Ben Murdochda12d292016-06-02 14:46:10 +0100949Node* WasmGraphBuilder::MaskShiftCount32(Node* node) {
950 static const int32_t kMask32 = 0x1f;
951 if (!jsgraph()->machine()->Word32ShiftIsSafe()) {
952 // Shifts by constants are so common we pattern-match them here.
953 Int32Matcher match(node);
954 if (match.HasValue()) {
955 int32_t masked = (match.Value() & kMask32);
956 if (match.Value() != masked) node = jsgraph()->Int32Constant(masked);
957 } else {
958 node = graph()->NewNode(jsgraph()->machine()->Word32And(), node,
959 jsgraph()->Int32Constant(kMask32));
960 }
961 }
962 return node;
963}
964
965Node* WasmGraphBuilder::MaskShiftCount64(Node* node) {
966 static const int64_t kMask64 = 0x3f;
967 if (!jsgraph()->machine()->Word32ShiftIsSafe()) {
968 // Shifts by constants are so common we pattern-match them here.
969 Int64Matcher match(node);
970 if (match.HasValue()) {
971 int64_t masked = (match.Value() & kMask64);
972 if (match.Value() != masked) node = jsgraph()->Int64Constant(masked);
973 } else {
974 node = graph()->NewNode(jsgraph()->machine()->Word64And(), node,
975 jsgraph()->Int64Constant(kMask64));
976 }
977 }
978 return node;
979}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000980
981Node* WasmGraphBuilder::BuildF32Neg(Node* input) {
982 Node* result =
983 Unop(wasm::kExprF32ReinterpretI32,
984 Binop(wasm::kExprI32Xor, Unop(wasm::kExprI32ReinterpretF32, input),
985 jsgraph()->Int32Constant(0x80000000)));
986
987 return result;
988}
989
990
991Node* WasmGraphBuilder::BuildF64Neg(Node* input) {
992#if WASM_64
993 Node* result =
994 Unop(wasm::kExprF64ReinterpretI64,
995 Binop(wasm::kExprI64Xor, Unop(wasm::kExprI64ReinterpretF64, input),
996 jsgraph()->Int64Constant(0x8000000000000000)));
997
998 return result;
999#else
1000 MachineOperatorBuilder* m = jsgraph()->machine();
1001
1002 Node* old_high_word = graph()->NewNode(m->Float64ExtractHighWord32(), input);
1003 Node* new_high_word = Binop(wasm::kExprI32Xor, old_high_word,
1004 jsgraph()->Int32Constant(0x80000000));
1005
1006 return graph()->NewNode(m->Float64InsertHighWord32(), input, new_high_word);
1007#endif
1008}
1009
1010
1011Node* WasmGraphBuilder::BuildF32CopySign(Node* left, Node* right) {
1012 Node* result = Unop(
1013 wasm::kExprF32ReinterpretI32,
1014 Binop(wasm::kExprI32Ior,
1015 Binop(wasm::kExprI32And, Unop(wasm::kExprI32ReinterpretF32, left),
1016 jsgraph()->Int32Constant(0x7fffffff)),
1017 Binop(wasm::kExprI32And, Unop(wasm::kExprI32ReinterpretF32, right),
1018 jsgraph()->Int32Constant(0x80000000))));
1019
1020 return result;
1021}
1022
1023
1024Node* WasmGraphBuilder::BuildF64CopySign(Node* left, Node* right) {
1025#if WASM_64
1026 Node* result = Unop(
1027 wasm::kExprF64ReinterpretI64,
1028 Binop(wasm::kExprI64Ior,
1029 Binop(wasm::kExprI64And, Unop(wasm::kExprI64ReinterpretF64, left),
1030 jsgraph()->Int64Constant(0x7fffffffffffffff)),
1031 Binop(wasm::kExprI64And, Unop(wasm::kExprI64ReinterpretF64, right),
1032 jsgraph()->Int64Constant(0x8000000000000000))));
1033
1034 return result;
1035#else
1036 MachineOperatorBuilder* m = jsgraph()->machine();
1037
1038 Node* high_word_left = graph()->NewNode(m->Float64ExtractHighWord32(), left);
1039 Node* high_word_right =
1040 graph()->NewNode(m->Float64ExtractHighWord32(), right);
1041
1042 Node* new_high_word =
1043 Binop(wasm::kExprI32Ior, Binop(wasm::kExprI32And, high_word_left,
1044 jsgraph()->Int32Constant(0x7fffffff)),
1045 Binop(wasm::kExprI32And, high_word_right,
1046 jsgraph()->Int32Constant(0x80000000)));
1047
1048 return graph()->NewNode(m->Float64InsertHighWord32(), left, new_high_word);
1049#endif
1050}
1051
1052
1053Node* WasmGraphBuilder::BuildF32Min(Node* left, Node* right) {
1054 Diamond left_le_right(graph(), jsgraph()->common(),
1055 Binop(wasm::kExprF32Le, left, right));
1056
1057 Diamond right_lt_left(graph(), jsgraph()->common(),
1058 Binop(wasm::kExprF32Lt, right, left));
1059
1060 Diamond left_is_not_nan(graph(), jsgraph()->common(),
1061 Binop(wasm::kExprF32Eq, left, left));
1062
1063 return left_le_right.Phi(
1064 wasm::kAstF32, left,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001065 right_lt_left.Phi(
1066 wasm::kAstF32, right,
1067 left_is_not_nan.Phi(
1068 wasm::kAstF32,
1069 Binop(wasm::kExprF32Mul, right, Float32Constant(1.0)),
1070 Binop(wasm::kExprF32Mul, left, Float32Constant(1.0)))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001071}
1072
1073
1074Node* WasmGraphBuilder::BuildF32Max(Node* left, Node* right) {
1075 Diamond left_ge_right(graph(), jsgraph()->common(),
1076 Binop(wasm::kExprF32Ge, left, right));
1077
1078 Diamond right_gt_left(graph(), jsgraph()->common(),
1079 Binop(wasm::kExprF32Gt, right, left));
1080
1081 Diamond left_is_not_nan(graph(), jsgraph()->common(),
1082 Binop(wasm::kExprF32Eq, left, left));
1083
1084 return left_ge_right.Phi(
1085 wasm::kAstF32, left,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001086 right_gt_left.Phi(
1087 wasm::kAstF32, right,
1088 left_is_not_nan.Phi(
1089 wasm::kAstF32,
1090 Binop(wasm::kExprF32Mul, right, Float32Constant(1.0)),
1091 Binop(wasm::kExprF32Mul, left, Float32Constant(1.0)))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001092}
1093
1094
1095Node* WasmGraphBuilder::BuildF64Min(Node* left, Node* right) {
1096 Diamond left_le_right(graph(), jsgraph()->common(),
1097 Binop(wasm::kExprF64Le, left, right));
1098
1099 Diamond right_lt_left(graph(), jsgraph()->common(),
1100 Binop(wasm::kExprF64Lt, right, left));
1101
1102 Diamond left_is_not_nan(graph(), jsgraph()->common(),
1103 Binop(wasm::kExprF64Eq, left, left));
1104
1105 return left_le_right.Phi(
1106 wasm::kAstF64, left,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001107 right_lt_left.Phi(
1108 wasm::kAstF64, right,
1109 left_is_not_nan.Phi(
1110 wasm::kAstF64,
1111 Binop(wasm::kExprF64Mul, right, Float64Constant(1.0)),
1112 Binop(wasm::kExprF64Mul, left, Float64Constant(1.0)))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001113}
1114
1115
1116Node* WasmGraphBuilder::BuildF64Max(Node* left, Node* right) {
1117 Diamond left_ge_right(graph(), jsgraph()->common(),
1118 Binop(wasm::kExprF64Ge, left, right));
1119
1120 Diamond right_gt_left(graph(), jsgraph()->common(),
1121 Binop(wasm::kExprF64Lt, right, left));
1122
1123 Diamond left_is_not_nan(graph(), jsgraph()->common(),
1124 Binop(wasm::kExprF64Eq, left, left));
1125
1126 return left_ge_right.Phi(
1127 wasm::kAstF64, left,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001128 right_gt_left.Phi(
1129 wasm::kAstF64, right,
1130 left_is_not_nan.Phi(
1131 wasm::kAstF64,
1132 Binop(wasm::kExprF64Mul, right, Float64Constant(1.0)),
1133 Binop(wasm::kExprF64Mul, left, Float64Constant(1.0)))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001134}
1135
1136
1137Node* WasmGraphBuilder::BuildI32SConvertF32(Node* input) {
1138 MachineOperatorBuilder* m = jsgraph()->machine();
Ben Murdochda12d292016-06-02 14:46:10 +01001139 if (module_ && module_->asm_js()) {
1140 // asm.js must use the wacky JS semantics.
1141 input = graph()->NewNode(m->ChangeFloat32ToFloat64(), input);
1142 return graph()->NewNode(
1143 m->TruncateFloat64ToInt32(TruncationMode::kJavaScript), input);
1144 }
1145
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001146 // Truncation of the input value is needed for the overflow check later.
1147 Node* trunc = Unop(wasm::kExprF32Trunc, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001148 Node* result = graph()->NewNode(m->TruncateFloat32ToInt32(), trunc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001149
1150 // Convert the result back to f64. If we end up at a different value than the
1151 // truncated input value, then there has been an overflow and we trap.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001152 Node* check = Unop(wasm::kExprF32SConvertI32, result);
1153 Node* overflow = Binop(wasm::kExprF32Ne, trunc, check);
Ben Murdochda12d292016-06-02 14:46:10 +01001154 trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001155
1156 return result;
1157}
1158
1159
1160Node* WasmGraphBuilder::BuildI32SConvertF64(Node* input) {
1161 MachineOperatorBuilder* m = jsgraph()->machine();
Ben Murdochda12d292016-06-02 14:46:10 +01001162 if (module_ && module_->asm_js()) {
1163 // asm.js must use the wacky JS semantics.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001164 return graph()->NewNode(
1165 m->TruncateFloat64ToInt32(TruncationMode::kJavaScript), input);
1166 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001167 // Truncation of the input value is needed for the overflow check later.
1168 Node* trunc = Unop(wasm::kExprF64Trunc, input);
1169 Node* result = graph()->NewNode(m->ChangeFloat64ToInt32(), trunc);
1170
1171 // Convert the result back to f64. If we end up at a different value than the
1172 // truncated input value, then there has been an overflow and we trap.
1173 Node* check = Unop(wasm::kExprF64SConvertI32, result);
1174 Node* overflow = Binop(wasm::kExprF64Ne, trunc, check);
Ben Murdochda12d292016-06-02 14:46:10 +01001175 trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001176
1177 return result;
1178}
1179
1180
1181Node* WasmGraphBuilder::BuildI32UConvertF32(Node* input) {
1182 MachineOperatorBuilder* m = jsgraph()->machine();
Ben Murdochda12d292016-06-02 14:46:10 +01001183 if (module_ && module_->asm_js()) {
1184 // asm.js must use the wacky JS semantics.
1185 input = graph()->NewNode(m->ChangeFloat32ToFloat64(), input);
1186 return graph()->NewNode(
1187 m->TruncateFloat64ToInt32(TruncationMode::kJavaScript), input);
1188 }
1189
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001190 // Truncation of the input value is needed for the overflow check later.
1191 Node* trunc = Unop(wasm::kExprF32Trunc, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001192 Node* result = graph()->NewNode(m->TruncateFloat32ToUint32(), trunc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001193
Ben Murdoch097c5b22016-05-18 11:27:45 +01001194 // Convert the result back to f32. If we end up at a different value than the
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001195 // truncated input value, then there has been an overflow and we trap.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001196 Node* check = Unop(wasm::kExprF32UConvertI32, result);
1197 Node* overflow = Binop(wasm::kExprF32Ne, trunc, check);
Ben Murdochda12d292016-06-02 14:46:10 +01001198 trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001199
1200 return result;
1201}
1202
1203
1204Node* WasmGraphBuilder::BuildI32UConvertF64(Node* input) {
1205 MachineOperatorBuilder* m = jsgraph()->machine();
Ben Murdochda12d292016-06-02 14:46:10 +01001206 if (module_ && module_->asm_js()) {
1207 // asm.js must use the wacky JS semantics.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001208 return graph()->NewNode(
1209 m->TruncateFloat64ToInt32(TruncationMode::kJavaScript), input);
1210 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001211 // Truncation of the input value is needed for the overflow check later.
1212 Node* trunc = Unop(wasm::kExprF64Trunc, input);
Ben Murdochda12d292016-06-02 14:46:10 +01001213 Node* result = graph()->NewNode(m->TruncateFloat64ToUint32(), trunc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001214
1215 // Convert the result back to f64. If we end up at a different value than the
1216 // truncated input value, then there has been an overflow and we trap.
1217 Node* check = Unop(wasm::kExprF64UConvertI32, result);
1218 Node* overflow = Binop(wasm::kExprF64Ne, trunc, check);
Ben Murdochda12d292016-06-02 14:46:10 +01001219 trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001220
1221 return result;
1222}
1223
1224
1225Node* WasmGraphBuilder::BuildI32Ctz(Node* input) {
1226 //// Implement the following code as TF graph.
1227 // value = value | (value << 1);
1228 // value = value | (value << 2);
1229 // value = value | (value << 4);
1230 // value = value | (value << 8);
1231 // value = value | (value << 16);
1232 // return CountPopulation32(0xffffffff XOR value);
1233
1234 Node* result =
1235 Binop(wasm::kExprI32Ior, input,
1236 Binop(wasm::kExprI32Shl, input, jsgraph()->Int32Constant(1)));
1237
1238 result = Binop(wasm::kExprI32Ior, result,
1239 Binop(wasm::kExprI32Shl, result, jsgraph()->Int32Constant(2)));
1240
1241 result = Binop(wasm::kExprI32Ior, result,
1242 Binop(wasm::kExprI32Shl, result, jsgraph()->Int32Constant(4)));
1243
1244 result = Binop(wasm::kExprI32Ior, result,
1245 Binop(wasm::kExprI32Shl, result, jsgraph()->Int32Constant(8)));
1246
1247 result =
1248 Binop(wasm::kExprI32Ior, result,
1249 Binop(wasm::kExprI32Shl, result, jsgraph()->Int32Constant(16)));
1250
1251 result = BuildI32Popcnt(
1252 Binop(wasm::kExprI32Xor, jsgraph()->Int32Constant(0xffffffff), result));
1253
1254 return result;
1255}
1256
1257
1258Node* WasmGraphBuilder::BuildI64Ctz(Node* input) {
1259 //// Implement the following code as TF graph.
1260 // value = value | (value << 1);
1261 // value = value | (value << 2);
1262 // value = value | (value << 4);
1263 // value = value | (value << 8);
1264 // value = value | (value << 16);
1265 // value = value | (value << 32);
1266 // return CountPopulation64(0xffffffffffffffff XOR value);
1267
1268 Node* result =
1269 Binop(wasm::kExprI64Ior, input,
1270 Binop(wasm::kExprI64Shl, input, jsgraph()->Int64Constant(1)));
1271
1272 result = Binop(wasm::kExprI64Ior, result,
1273 Binop(wasm::kExprI64Shl, result, jsgraph()->Int64Constant(2)));
1274
1275 result = Binop(wasm::kExprI64Ior, result,
1276 Binop(wasm::kExprI64Shl, result, jsgraph()->Int64Constant(4)));
1277
1278 result = Binop(wasm::kExprI64Ior, result,
1279 Binop(wasm::kExprI64Shl, result, jsgraph()->Int64Constant(8)));
1280
1281 result =
1282 Binop(wasm::kExprI64Ior, result,
1283 Binop(wasm::kExprI64Shl, result, jsgraph()->Int64Constant(16)));
1284
1285 result =
1286 Binop(wasm::kExprI64Ior, result,
1287 Binop(wasm::kExprI64Shl, result, jsgraph()->Int64Constant(32)));
1288
1289 result = BuildI64Popcnt(Binop(
1290 wasm::kExprI64Xor, jsgraph()->Int64Constant(0xffffffffffffffff), result));
1291
1292 return result;
1293}
1294
1295
1296Node* WasmGraphBuilder::BuildI32Popcnt(Node* input) {
1297 //// Implement the following code as a TF graph.
1298 // value = ((value >> 1) & 0x55555555) + (value & 0x55555555);
1299 // value = ((value >> 2) & 0x33333333) + (value & 0x33333333);
1300 // value = ((value >> 4) & 0x0f0f0f0f) + (value & 0x0f0f0f0f);
1301 // value = ((value >> 8) & 0x00ff00ff) + (value & 0x00ff00ff);
1302 // value = ((value >> 16) & 0x0000ffff) + (value & 0x0000ffff);
1303
1304 Node* result = Binop(
1305 wasm::kExprI32Add,
1306 Binop(wasm::kExprI32And,
1307 Binop(wasm::kExprI32ShrU, input, jsgraph()->Int32Constant(1)),
1308 jsgraph()->Int32Constant(0x55555555)),
1309 Binop(wasm::kExprI32And, input, jsgraph()->Int32Constant(0x55555555)));
1310
1311 result = Binop(
1312 wasm::kExprI32Add,
1313 Binop(wasm::kExprI32And,
1314 Binop(wasm::kExprI32ShrU, result, jsgraph()->Int32Constant(2)),
1315 jsgraph()->Int32Constant(0x33333333)),
1316 Binop(wasm::kExprI32And, result, jsgraph()->Int32Constant(0x33333333)));
1317
1318 result = Binop(
1319 wasm::kExprI32Add,
1320 Binop(wasm::kExprI32And,
1321 Binop(wasm::kExprI32ShrU, result, jsgraph()->Int32Constant(4)),
1322 jsgraph()->Int32Constant(0x0f0f0f0f)),
1323 Binop(wasm::kExprI32And, result, jsgraph()->Int32Constant(0x0f0f0f0f)));
1324
1325 result = Binop(
1326 wasm::kExprI32Add,
1327 Binop(wasm::kExprI32And,
1328 Binop(wasm::kExprI32ShrU, result, jsgraph()->Int32Constant(8)),
1329 jsgraph()->Int32Constant(0x00ff00ff)),
1330 Binop(wasm::kExprI32And, result, jsgraph()->Int32Constant(0x00ff00ff)));
1331
1332 result = Binop(
1333 wasm::kExprI32Add,
1334 Binop(wasm::kExprI32And,
1335 Binop(wasm::kExprI32ShrU, result, jsgraph()->Int32Constant(16)),
1336 jsgraph()->Int32Constant(0x0000ffff)),
1337 Binop(wasm::kExprI32And, result, jsgraph()->Int32Constant(0x0000ffff)));
1338
1339 return result;
1340}
1341
1342
1343Node* WasmGraphBuilder::BuildI64Popcnt(Node* input) {
1344 //// Implement the following code as a TF graph.
1345 // value = ((value >> 1) & 0x5555555555555555) + (value & 0x5555555555555555);
1346 // value = ((value >> 2) & 0x3333333333333333) + (value & 0x3333333333333333);
1347 // value = ((value >> 4) & 0x0f0f0f0f0f0f0f0f) + (value & 0x0f0f0f0f0f0f0f0f);
1348 // value = ((value >> 8) & 0x00ff00ff00ff00ff) + (value & 0x00ff00ff00ff00ff);
1349 // value = ((value >> 16) & 0x0000ffff0000ffff) + (value &
1350 // 0x0000ffff0000ffff);
1351 // value = ((value >> 32) & 0x00000000ffffffff) + (value &
1352 // 0x00000000ffffffff);
1353
1354 Node* result =
1355 Binop(wasm::kExprI64Add,
1356 Binop(wasm::kExprI64And,
1357 Binop(wasm::kExprI64ShrU, input, jsgraph()->Int64Constant(1)),
1358 jsgraph()->Int64Constant(0x5555555555555555)),
1359 Binop(wasm::kExprI64And, input,
1360 jsgraph()->Int64Constant(0x5555555555555555)));
1361
1362 result = Binop(wasm::kExprI64Add,
1363 Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result,
1364 jsgraph()->Int64Constant(2)),
1365 jsgraph()->Int64Constant(0x3333333333333333)),
1366 Binop(wasm::kExprI64And, result,
1367 jsgraph()->Int64Constant(0x3333333333333333)));
1368
1369 result = Binop(wasm::kExprI64Add,
1370 Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result,
1371 jsgraph()->Int64Constant(4)),
1372 jsgraph()->Int64Constant(0x0f0f0f0f0f0f0f0f)),
1373 Binop(wasm::kExprI64And, result,
1374 jsgraph()->Int64Constant(0x0f0f0f0f0f0f0f0f)));
1375
1376 result = Binop(wasm::kExprI64Add,
1377 Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result,
1378 jsgraph()->Int64Constant(8)),
1379 jsgraph()->Int64Constant(0x00ff00ff00ff00ff)),
1380 Binop(wasm::kExprI64And, result,
1381 jsgraph()->Int64Constant(0x00ff00ff00ff00ff)));
1382
1383 result = Binop(wasm::kExprI64Add,
1384 Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result,
1385 jsgraph()->Int64Constant(16)),
1386 jsgraph()->Int64Constant(0x0000ffff0000ffff)),
1387 Binop(wasm::kExprI64And, result,
1388 jsgraph()->Int64Constant(0x0000ffff0000ffff)));
1389
1390 result = Binop(wasm::kExprI64Add,
1391 Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result,
1392 jsgraph()->Int64Constant(32)),
1393 jsgraph()->Int64Constant(0x00000000ffffffff)),
1394 Binop(wasm::kExprI64And, result,
1395 jsgraph()->Int64Constant(0x00000000ffffffff)));
1396
1397 return result;
1398}
1399
Ben Murdoch097c5b22016-05-18 11:27:45 +01001400Node* WasmGraphBuilder::BuildF32Trunc(Node* input) {
1401 MachineType type = MachineType::Float32();
1402 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001403 ExternalReference::wasm_f32_trunc(jsgraph()->isolate());
1404
1405 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001406}
1407
1408Node* WasmGraphBuilder::BuildF32Floor(Node* input) {
1409 MachineType type = MachineType::Float32();
1410 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001411 ExternalReference::wasm_f32_floor(jsgraph()->isolate());
1412 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001413}
1414
1415Node* WasmGraphBuilder::BuildF32Ceil(Node* input) {
1416 MachineType type = MachineType::Float32();
1417 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001418 ExternalReference::wasm_f32_ceil(jsgraph()->isolate());
1419 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001420}
1421
1422Node* WasmGraphBuilder::BuildF32NearestInt(Node* input) {
1423 MachineType type = MachineType::Float32();
1424 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001425 ExternalReference::wasm_f32_nearest_int(jsgraph()->isolate());
1426 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001427}
1428
1429Node* WasmGraphBuilder::BuildF64Trunc(Node* input) {
1430 MachineType type = MachineType::Float64();
1431 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001432 ExternalReference::wasm_f64_trunc(jsgraph()->isolate());
1433 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001434}
1435
1436Node* WasmGraphBuilder::BuildF64Floor(Node* input) {
1437 MachineType type = MachineType::Float64();
1438 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001439 ExternalReference::wasm_f64_floor(jsgraph()->isolate());
1440 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001441}
1442
1443Node* WasmGraphBuilder::BuildF64Ceil(Node* input) {
1444 MachineType type = MachineType::Float64();
1445 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001446 ExternalReference::wasm_f64_ceil(jsgraph()->isolate());
1447 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001448}
1449
1450Node* WasmGraphBuilder::BuildF64NearestInt(Node* input) {
1451 MachineType type = MachineType::Float64();
1452 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001453 ExternalReference::wasm_f64_nearest_int(jsgraph()->isolate());
1454 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001455}
1456
Ben Murdochda12d292016-06-02 14:46:10 +01001457Node* WasmGraphBuilder::BuildF64Acos(Node* input) {
1458 MachineType type = MachineType::Float64();
1459 ExternalReference ref =
1460 ExternalReference::f64_acos_wrapper_function(jsgraph()->isolate());
1461 return BuildCFuncInstruction(ref, type, input);
1462}
Ben Murdoch097c5b22016-05-18 11:27:45 +01001463
Ben Murdochda12d292016-06-02 14:46:10 +01001464Node* WasmGraphBuilder::BuildF64Asin(Node* input) {
1465 MachineType type = MachineType::Float64();
1466 ExternalReference ref =
1467 ExternalReference::f64_asin_wrapper_function(jsgraph()->isolate());
1468 return BuildCFuncInstruction(ref, type, input);
1469}
1470
1471Node* WasmGraphBuilder::BuildF64Atan(Node* input) {
1472 MachineType type = MachineType::Float64();
1473 ExternalReference ref =
1474 ExternalReference::f64_atan_wrapper_function(jsgraph()->isolate());
1475 return BuildCFuncInstruction(ref, type, input);
1476}
1477
1478Node* WasmGraphBuilder::BuildF64Cos(Node* input) {
1479 MachineType type = MachineType::Float64();
1480 ExternalReference ref =
1481 ExternalReference::f64_cos_wrapper_function(jsgraph()->isolate());
1482 return BuildCFuncInstruction(ref, type, input);
1483}
1484
1485Node* WasmGraphBuilder::BuildF64Sin(Node* input) {
1486 MachineType type = MachineType::Float64();
1487 ExternalReference ref =
1488 ExternalReference::f64_sin_wrapper_function(jsgraph()->isolate());
1489 return BuildCFuncInstruction(ref, type, input);
1490}
1491
1492Node* WasmGraphBuilder::BuildF64Tan(Node* input) {
1493 MachineType type = MachineType::Float64();
1494 ExternalReference ref =
1495 ExternalReference::f64_tan_wrapper_function(jsgraph()->isolate());
1496 return BuildCFuncInstruction(ref, type, input);
1497}
1498
1499Node* WasmGraphBuilder::BuildF64Exp(Node* input) {
1500 MachineType type = MachineType::Float64();
1501 ExternalReference ref =
1502 ExternalReference::f64_exp_wrapper_function(jsgraph()->isolate());
1503 return BuildCFuncInstruction(ref, type, input);
1504}
1505
1506Node* WasmGraphBuilder::BuildF64Log(Node* input) {
1507 MachineType type = MachineType::Float64();
1508 ExternalReference ref =
1509 ExternalReference::f64_log_wrapper_function(jsgraph()->isolate());
1510 return BuildCFuncInstruction(ref, type, input);
1511}
1512
1513Node* WasmGraphBuilder::BuildF64Atan2(Node* left, Node* right) {
1514 MachineType type = MachineType::Float64();
1515 ExternalReference ref =
1516 ExternalReference::f64_atan2_wrapper_function(jsgraph()->isolate());
1517 return BuildCFuncInstruction(ref, type, left, right);
1518}
1519
1520Node* WasmGraphBuilder::BuildF64Pow(Node* left, Node* right) {
1521 MachineType type = MachineType::Float64();
1522 ExternalReference ref =
1523 ExternalReference::f64_pow_wrapper_function(jsgraph()->isolate());
1524 return BuildCFuncInstruction(ref, type, left, right);
1525}
1526
1527Node* WasmGraphBuilder::BuildF64Mod(Node* left, Node* right) {
1528 MachineType type = MachineType::Float64();
1529 ExternalReference ref =
1530 ExternalReference::f64_mod_wrapper_function(jsgraph()->isolate());
1531 return BuildCFuncInstruction(ref, type, left, right);
1532}
1533
1534Node* WasmGraphBuilder::BuildCFuncInstruction(ExternalReference ref,
1535 MachineType type, Node* input0,
1536 Node* input1) {
1537 // We do truncation by calling a C function which calculates the result.
1538 // The input is passed to the C function as a double*'s to avoid double
1539 // parameters. For this we reserve slots on the stack, store the parameters
1540 // in those slots, pass pointers to the slot to the C function,
1541 // and after calling the C function we collect the return value from
1542 // the stack slot.
1543
1544 Node* stack_slot_param0 =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001545 graph()->NewNode(jsgraph()->machine()->StackSlot(type.representation()));
1546
Ben Murdochda12d292016-06-02 14:46:10 +01001547 const Operator* store_op0 = jsgraph()->machine()->Store(
Ben Murdoch097c5b22016-05-18 11:27:45 +01001548 StoreRepresentation(type.representation(), kNoWriteBarrier));
Ben Murdochda12d292016-06-02 14:46:10 +01001549 *effect_ = graph()->NewNode(store_op0, stack_slot_param0,
1550 jsgraph()->Int32Constant(0), input0, *effect_,
1551 *control_);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001552
Ben Murdoch097c5b22016-05-18 11:27:45 +01001553 Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
Ben Murdochda12d292016-06-02 14:46:10 +01001554 Node** args = Buffer(5);
1555 args[0] = function;
1556 args[1] = stack_slot_param0;
1557 int input_count = 1;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001558
Ben Murdochda12d292016-06-02 14:46:10 +01001559 if (input1 != nullptr) {
1560 Node* stack_slot_param1 = graph()->NewNode(
1561 jsgraph()->machine()->StackSlot(type.representation()));
1562 const Operator* store_op1 = jsgraph()->machine()->Store(
1563 StoreRepresentation(type.representation(), kNoWriteBarrier));
1564 *effect_ = graph()->NewNode(store_op1, stack_slot_param1,
1565 jsgraph()->Int32Constant(0), input1, *effect_,
1566 *control_);
1567 args[2] = stack_slot_param1;
1568 ++input_count;
1569 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001570
Ben Murdochda12d292016-06-02 14:46:10 +01001571 Signature<MachineType>::Builder sig_builder(jsgraph()->zone(), 0,
1572 input_count);
1573 sig_builder.AddParam(MachineType::Pointer());
1574 if (input1 != nullptr) {
1575 sig_builder.AddParam(MachineType::Pointer());
1576 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001577 BuildCCall(sig_builder.Build(), args);
1578
1579 const Operator* load_op = jsgraph()->machine()->Load(type);
1580
1581 Node* load =
Ben Murdochda12d292016-06-02 14:46:10 +01001582 graph()->NewNode(load_op, stack_slot_param0, jsgraph()->Int32Constant(0),
1583 *effect_, *control_);
1584 *effect_ = load;
1585 return load;
1586}
1587
1588Node* WasmGraphBuilder::BuildF32SConvertI64(Node* input) {
1589 // TODO(titzer/bradnelson): Check handlng of asm.js case.
1590 return BuildIntToFloatConversionInstruction(
1591 input, ExternalReference::wasm_int64_to_float32(jsgraph()->isolate()),
1592 MachineRepresentation::kWord64, MachineType::Float32());
1593}
1594Node* WasmGraphBuilder::BuildF32UConvertI64(Node* input) {
1595 // TODO(titzer/bradnelson): Check handlng of asm.js case.
1596 return BuildIntToFloatConversionInstruction(
1597 input, ExternalReference::wasm_uint64_to_float32(jsgraph()->isolate()),
1598 MachineRepresentation::kWord64, MachineType::Float32());
1599}
1600Node* WasmGraphBuilder::BuildF64SConvertI64(Node* input) {
1601 return BuildIntToFloatConversionInstruction(
1602 input, ExternalReference::wasm_int64_to_float64(jsgraph()->isolate()),
1603 MachineRepresentation::kWord64, MachineType::Float64());
1604}
1605Node* WasmGraphBuilder::BuildF64UConvertI64(Node* input) {
1606 return BuildIntToFloatConversionInstruction(
1607 input, ExternalReference::wasm_uint64_to_float64(jsgraph()->isolate()),
1608 MachineRepresentation::kWord64, MachineType::Float64());
1609}
1610
1611Node* WasmGraphBuilder::BuildIntToFloatConversionInstruction(
1612 Node* input, ExternalReference ref,
1613 MachineRepresentation parameter_representation,
1614 const MachineType result_type) {
1615 Node* stack_slot_param = graph()->NewNode(
1616 jsgraph()->machine()->StackSlot(parameter_representation));
1617 Node* stack_slot_result = graph()->NewNode(
1618 jsgraph()->machine()->StackSlot(result_type.representation()));
1619 const Operator* store_op = jsgraph()->machine()->Store(
1620 StoreRepresentation(parameter_representation, kNoWriteBarrier));
1621 *effect_ =
1622 graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0),
1623 input, *effect_, *control_);
1624 MachineSignature::Builder sig_builder(jsgraph()->zone(), 0, 2);
1625 sig_builder.AddParam(MachineType::Pointer());
1626 sig_builder.AddParam(MachineType::Pointer());
1627 Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
1628 Node* args[] = {function, stack_slot_param, stack_slot_result};
1629 BuildCCall(sig_builder.Build(), args);
1630 const Operator* load_op = jsgraph()->machine()->Load(result_type);
1631 Node* load =
1632 graph()->NewNode(load_op, stack_slot_result, jsgraph()->Int32Constant(0),
1633 *effect_, *control_);
1634 *effect_ = load;
1635 return load;
1636}
1637
1638Node* WasmGraphBuilder::BuildI64SConvertF32(Node* input) {
1639 if (jsgraph()->machine()->Is32()) {
1640 return BuildFloatToIntConversionInstruction(
1641 input, ExternalReference::wasm_float32_to_int64(jsgraph()->isolate()),
1642 MachineRepresentation::kFloat32, MachineType::Int64());
1643 } else {
1644 Node* trunc = graph()->NewNode(
1645 jsgraph()->machine()->TryTruncateFloat32ToInt64(), input);
1646 Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc);
1647 Node* overflow =
1648 graph()->NewNode(jsgraph()->common()->Projection(1), trunc);
1649 trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow);
1650 return result;
1651 }
1652}
1653
1654Node* WasmGraphBuilder::BuildI64UConvertF32(Node* input) {
1655 if (jsgraph()->machine()->Is32()) {
1656 return BuildFloatToIntConversionInstruction(
1657 input, ExternalReference::wasm_float32_to_uint64(jsgraph()->isolate()),
1658 MachineRepresentation::kFloat32, MachineType::Int64());
1659 } else {
1660 Node* trunc = graph()->NewNode(
1661 jsgraph()->machine()->TryTruncateFloat32ToUint64(), input);
1662 Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc);
1663 Node* overflow =
1664 graph()->NewNode(jsgraph()->common()->Projection(1), trunc);
1665 trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow);
1666 return result;
1667 }
1668}
1669
1670Node* WasmGraphBuilder::BuildI64SConvertF64(Node* input) {
1671 if (jsgraph()->machine()->Is32()) {
1672 return BuildFloatToIntConversionInstruction(
1673 input, ExternalReference::wasm_float64_to_int64(jsgraph()->isolate()),
1674 MachineRepresentation::kFloat64, MachineType::Int64());
1675 } else {
1676 Node* trunc = graph()->NewNode(
1677 jsgraph()->machine()->TryTruncateFloat64ToInt64(), input);
1678 Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc);
1679 Node* overflow =
1680 graph()->NewNode(jsgraph()->common()->Projection(1), trunc);
1681 trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow);
1682 return result;
1683 }
1684}
1685
1686Node* WasmGraphBuilder::BuildI64UConvertF64(Node* input) {
1687 if (jsgraph()->machine()->Is32()) {
1688 return BuildFloatToIntConversionInstruction(
1689 input, ExternalReference::wasm_float64_to_uint64(jsgraph()->isolate()),
1690 MachineRepresentation::kFloat64, MachineType::Int64());
1691 } else {
1692 Node* trunc = graph()->NewNode(
1693 jsgraph()->machine()->TryTruncateFloat64ToUint64(), input);
1694 Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc);
1695 Node* overflow =
1696 graph()->NewNode(jsgraph()->common()->Projection(1), trunc);
1697 trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow);
1698 return result;
1699 }
1700}
1701
1702Node* WasmGraphBuilder::BuildFloatToIntConversionInstruction(
1703 Node* input, ExternalReference ref,
1704 MachineRepresentation parameter_representation,
1705 const MachineType result_type) {
1706 Node* stack_slot_param = graph()->NewNode(
1707 jsgraph()->machine()->StackSlot(parameter_representation));
1708 Node* stack_slot_result = graph()->NewNode(
1709 jsgraph()->machine()->StackSlot(result_type.representation()));
1710 const Operator* store_op = jsgraph()->machine()->Store(
1711 StoreRepresentation(parameter_representation, kNoWriteBarrier));
1712 *effect_ =
1713 graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0),
1714 input, *effect_, *control_);
1715 MachineSignature::Builder sig_builder(jsgraph()->zone(), 1, 2);
1716 sig_builder.AddReturn(MachineType::Int32());
1717 sig_builder.AddParam(MachineType::Pointer());
1718 sig_builder.AddParam(MachineType::Pointer());
1719 Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
1720 Node* args[] = {function, stack_slot_param, stack_slot_result};
1721 trap_->ZeroCheck32(wasm::kTrapFloatUnrepresentable,
1722 BuildCCall(sig_builder.Build(), args));
1723 const Operator* load_op = jsgraph()->machine()->Load(result_type);
1724 Node* load =
1725 graph()->NewNode(load_op, stack_slot_result, jsgraph()->Int32Constant(0),
1726 *effect_, *control_);
1727 *effect_ = load;
1728 return load;
1729}
1730
1731Node* WasmGraphBuilder::BuildI32DivS(Node* left, Node* right) {
1732 MachineOperatorBuilder* m = jsgraph()->machine();
1733 if (module_ && module_->asm_js()) {
1734 // asm.js semantics return 0 on divide or mod by zero.
1735 if (m->Int32DivIsSafe()) {
1736 // The hardware instruction does the right thing (e.g. arm).
1737 return graph()->NewNode(m->Int32Div(), left, right, graph()->start());
1738 }
1739
1740 // Check denominator for zero.
1741 Diamond z(
1742 graph(), jsgraph()->common(),
1743 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
1744 BranchHint::kFalse);
1745
1746 // Check numerator for -1. (avoid minint / -1 case).
1747 Diamond n(
1748 graph(), jsgraph()->common(),
1749 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
1750 BranchHint::kFalse);
1751
1752 Node* div = graph()->NewNode(m->Int32Div(), left, right, z.if_false);
1753 Node* neg =
1754 graph()->NewNode(m->Int32Sub(), jsgraph()->Int32Constant(0), left);
1755
1756 return n.Phi(MachineRepresentation::kWord32, neg,
1757 z.Phi(MachineRepresentation::kWord32,
1758 jsgraph()->Int32Constant(0), div));
1759 }
1760
1761 trap_->ZeroCheck32(wasm::kTrapDivByZero, right);
1762 Node* before = *control_;
1763 Node* denom_is_m1;
1764 Node* denom_is_not_m1;
1765 Branch(
1766 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
1767 &denom_is_m1, &denom_is_not_m1);
1768 *control_ = denom_is_m1;
1769 trap_->TrapIfEq32(wasm::kTrapDivUnrepresentable, left, kMinInt);
1770 if (*control_ != denom_is_m1) {
1771 *control_ = graph()->NewNode(jsgraph()->common()->Merge(2), denom_is_not_m1,
1772 *control_);
1773 } else {
1774 *control_ = before;
1775 }
1776 return graph()->NewNode(m->Int32Div(), left, right, *control_);
1777}
1778
1779Node* WasmGraphBuilder::BuildI32RemS(Node* left, Node* right) {
1780 MachineOperatorBuilder* m = jsgraph()->machine();
1781 if (module_ && module_->asm_js()) {
1782 // asm.js semantics return 0 on divide or mod by zero.
1783 // Explicit check for x % 0.
1784 Diamond z(
1785 graph(), jsgraph()->common(),
1786 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
1787 BranchHint::kFalse);
1788
1789 // Explicit check for x % -1.
1790 Diamond d(
1791 graph(), jsgraph()->common(),
1792 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
1793 BranchHint::kFalse);
1794 d.Chain(z.if_false);
1795
1796 return z.Phi(
1797 MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
1798 d.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
1799 graph()->NewNode(m->Int32Mod(), left, right, d.if_false)));
1800 }
1801
1802 trap_->ZeroCheck32(wasm::kTrapRemByZero, right);
1803
1804 Diamond d(
1805 graph(), jsgraph()->common(),
1806 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
1807 BranchHint::kFalse);
1808 d.Chain(*control_);
1809
1810 return d.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
1811 graph()->NewNode(m->Int32Mod(), left, right, d.if_false));
1812}
1813
1814Node* WasmGraphBuilder::BuildI32DivU(Node* left, Node* right) {
1815 MachineOperatorBuilder* m = jsgraph()->machine();
1816 if (module_ && module_->asm_js()) {
1817 // asm.js semantics return 0 on divide or mod by zero.
1818 if (m->Uint32DivIsSafe()) {
1819 // The hardware instruction does the right thing (e.g. arm).
1820 return graph()->NewNode(m->Uint32Div(), left, right, graph()->start());
1821 }
1822
1823 // Explicit check for x % 0.
1824 Diamond z(
1825 graph(), jsgraph()->common(),
1826 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
1827 BranchHint::kFalse);
1828
1829 return z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
1830 graph()->NewNode(jsgraph()->machine()->Uint32Div(), left,
1831 right, z.if_false));
1832 }
1833 return graph()->NewNode(m->Uint32Div(), left, right,
1834 trap_->ZeroCheck32(wasm::kTrapDivByZero, right));
1835}
1836
1837Node* WasmGraphBuilder::BuildI32RemU(Node* left, Node* right) {
1838 MachineOperatorBuilder* m = jsgraph()->machine();
1839 if (module_ && module_->asm_js()) {
1840 // asm.js semantics return 0 on divide or mod by zero.
1841 // Explicit check for x % 0.
1842 Diamond z(
1843 graph(), jsgraph()->common(),
1844 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
1845 BranchHint::kFalse);
1846
1847 Node* rem = graph()->NewNode(jsgraph()->machine()->Uint32Mod(), left, right,
1848 z.if_false);
1849 return z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
1850 rem);
1851 }
1852
1853 return graph()->NewNode(m->Uint32Mod(), left, right,
1854 trap_->ZeroCheck32(wasm::kTrapRemByZero, right));
1855}
1856
1857Node* WasmGraphBuilder::BuildI64DivS(Node* left, Node* right) {
1858 if (jsgraph()->machine()->Is32()) {
1859 return BuildDiv64Call(
1860 left, right, ExternalReference::wasm_int64_div(jsgraph()->isolate()),
1861 MachineType::Int64(), wasm::kTrapDivByZero);
1862 }
1863 trap_->ZeroCheck64(wasm::kTrapDivByZero, right);
1864 Node* before = *control_;
1865 Node* denom_is_m1;
1866 Node* denom_is_not_m1;
1867 Branch(graph()->NewNode(jsgraph()->machine()->Word64Equal(), right,
1868 jsgraph()->Int64Constant(-1)),
1869 &denom_is_m1, &denom_is_not_m1);
1870 *control_ = denom_is_m1;
1871 trap_->TrapIfEq64(wasm::kTrapDivUnrepresentable, left,
1872 std::numeric_limits<int64_t>::min());
1873 if (*control_ != denom_is_m1) {
1874 *control_ = graph()->NewNode(jsgraph()->common()->Merge(2), denom_is_not_m1,
1875 *control_);
1876 } else {
1877 *control_ = before;
1878 }
1879 return graph()->NewNode(jsgraph()->machine()->Int64Div(), left, right,
1880 *control_);
1881}
1882
1883Node* WasmGraphBuilder::BuildI64RemS(Node* left, Node* right) {
1884 if (jsgraph()->machine()->Is32()) {
1885 return BuildDiv64Call(
1886 left, right, ExternalReference::wasm_int64_mod(jsgraph()->isolate()),
1887 MachineType::Int64(), wasm::kTrapRemByZero);
1888 }
1889 trap_->ZeroCheck64(wasm::kTrapRemByZero, right);
1890 Diamond d(jsgraph()->graph(), jsgraph()->common(),
1891 graph()->NewNode(jsgraph()->machine()->Word64Equal(), right,
1892 jsgraph()->Int64Constant(-1)));
1893
1894 Node* rem = graph()->NewNode(jsgraph()->machine()->Int64Mod(), left, right,
1895 d.if_false);
1896
1897 return d.Phi(MachineRepresentation::kWord64, jsgraph()->Int64Constant(0),
1898 rem);
1899}
1900
1901Node* WasmGraphBuilder::BuildI64DivU(Node* left, Node* right) {
1902 if (jsgraph()->machine()->Is32()) {
1903 return BuildDiv64Call(
1904 left, right, ExternalReference::wasm_uint64_div(jsgraph()->isolate()),
1905 MachineType::Int64(), wasm::kTrapDivByZero);
1906 }
1907 return graph()->NewNode(jsgraph()->machine()->Uint64Div(), left, right,
1908 trap_->ZeroCheck64(wasm::kTrapDivByZero, right));
1909}
1910Node* WasmGraphBuilder::BuildI64RemU(Node* left, Node* right) {
1911 if (jsgraph()->machine()->Is32()) {
1912 return BuildDiv64Call(
1913 left, right, ExternalReference::wasm_uint64_mod(jsgraph()->isolate()),
1914 MachineType::Int64(), wasm::kTrapRemByZero);
1915 }
1916 return graph()->NewNode(jsgraph()->machine()->Uint64Mod(), left, right,
1917 trap_->ZeroCheck64(wasm::kTrapRemByZero, right));
1918}
1919
1920Node* WasmGraphBuilder::BuildDiv64Call(Node* left, Node* right,
1921 ExternalReference ref,
1922 MachineType result_type, int trap_zero) {
1923 Node* stack_slot_dst = graph()->NewNode(
1924 jsgraph()->machine()->StackSlot(MachineRepresentation::kWord64));
1925 Node* stack_slot_src = graph()->NewNode(
1926 jsgraph()->machine()->StackSlot(MachineRepresentation::kWord64));
1927
1928 const Operator* store_op = jsgraph()->machine()->Store(
1929 StoreRepresentation(MachineRepresentation::kWord64, kNoWriteBarrier));
1930 *effect_ =
1931 graph()->NewNode(store_op, stack_slot_dst, jsgraph()->Int32Constant(0),
1932 left, *effect_, *control_);
1933 *effect_ =
1934 graph()->NewNode(store_op, stack_slot_src, jsgraph()->Int32Constant(0),
1935 right, *effect_, *control_);
1936
1937 MachineSignature::Builder sig_builder(jsgraph()->zone(), 1, 2);
1938 sig_builder.AddReturn(MachineType::Int32());
1939 sig_builder.AddParam(MachineType::Pointer());
1940 sig_builder.AddParam(MachineType::Pointer());
1941
1942 Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
1943 Node* args[] = {function, stack_slot_dst, stack_slot_src};
1944
1945 Node* call = BuildCCall(sig_builder.Build(), args);
1946
1947 // TODO(wasm): This can get simpler if we have a specialized runtime call to
1948 // throw WASM exceptions by trap code instead of by string.
1949 trap_->ZeroCheck32(static_cast<wasm::TrapReason>(trap_zero), call);
1950 trap_->TrapIfEq32(wasm::kTrapDivUnrepresentable, call, -1);
1951 const Operator* load_op = jsgraph()->machine()->Load(result_type);
1952 Node* load =
1953 graph()->NewNode(load_op, stack_slot_dst, jsgraph()->Int32Constant(0),
Ben Murdoch097c5b22016-05-18 11:27:45 +01001954 *effect_, *control_);
1955 *effect_ = load;
1956 return load;
1957}
1958
1959Node* WasmGraphBuilder::BuildCCall(MachineSignature* sig, Node** args) {
1960 const size_t params = sig->parameter_count();
1961 const size_t extra = 2; // effect and control inputs.
1962 const size_t count = 1 + params + extra;
1963
1964 // Reallocate the buffer to make space for extra inputs.
Ben Murdochda12d292016-06-02 14:46:10 +01001965 args = Realloc(args, 1 + params, count);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001966
1967 // Add effect and control inputs.
1968 args[params + 1] = *effect_;
1969 args[params + 2] = *control_;
1970
1971 CallDescriptor* desc =
1972 Linkage::GetSimplifiedCDescriptor(jsgraph()->zone(), sig);
1973
1974 const Operator* op = jsgraph()->common()->Call(desc);
1975 Node* call = graph()->NewNode(op, static_cast<int>(count), args);
1976 *effect_ = call;
1977 return call;
1978}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001979
1980Node* WasmGraphBuilder::BuildWasmCall(wasm::FunctionSig* sig, Node** args) {
1981 const size_t params = sig->parameter_count();
1982 const size_t extra = 2; // effect and control inputs.
1983 const size_t count = 1 + params + extra;
1984
1985 // Reallocate the buffer to make space for extra inputs.
Ben Murdochda12d292016-06-02 14:46:10 +01001986 args = Realloc(args, 1 + params, count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001987
1988 // Add effect and control inputs.
1989 args[params + 1] = *effect_;
1990 args[params + 2] = *control_;
1991
Ben Murdoch097c5b22016-05-18 11:27:45 +01001992 CallDescriptor* descriptor =
1993 wasm::ModuleEnv::GetWasmCallDescriptor(jsgraph()->zone(), sig);
1994 const Operator* op = jsgraph()->common()->Call(descriptor);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001995 Node* call = graph()->NewNode(op, static_cast<int>(count), args);
1996
1997 *effect_ = call;
1998 return call;
1999}
2000
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002001Node* WasmGraphBuilder::CallDirect(uint32_t index, Node** args) {
2002 DCHECK_NULL(args[0]);
2003
2004 // Add code object as constant.
2005 args[0] = Constant(module_->GetFunctionCode(index));
2006 wasm::FunctionSig* sig = module_->GetFunctionSignature(index);
2007
2008 return BuildWasmCall(sig, args);
2009}
2010
Ben Murdoch097c5b22016-05-18 11:27:45 +01002011Node* WasmGraphBuilder::CallImport(uint32_t index, Node** args) {
2012 DCHECK_NULL(args[0]);
2013
2014 // Add code object as constant.
2015 args[0] = Constant(module_->GetImportCode(index));
2016 wasm::FunctionSig* sig = module_->GetImportSignature(index);
2017
2018 return BuildWasmCall(sig, args);
2019}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002020
2021Node* WasmGraphBuilder::CallIndirect(uint32_t index, Node** args) {
2022 DCHECK_NOT_NULL(args[0]);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002023 DCHECK(module_ && module_->instance);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002024
2025 MachineOperatorBuilder* machine = jsgraph()->machine();
2026
2027 // Compute the code object by loading it from the function table.
2028 Node* key = args[0];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002029
2030 // Bounds check the index.
2031 int table_size = static_cast<int>(module_->FunctionTableSize());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002032 if (table_size > 0) {
2033 // Bounds check against the table size.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002034 Node* size = Int32Constant(static_cast<int>(table_size));
2035 Node* in_bounds = graph()->NewNode(machine->Uint32LessThan(), key, size);
Ben Murdochda12d292016-06-02 14:46:10 +01002036 trap_->AddTrapIfFalse(wasm::kTrapFuncInvalid, in_bounds);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002037 } else {
2038 // No function table. Generate a trap and return a constant.
Ben Murdochda12d292016-06-02 14:46:10 +01002039 trap_->AddTrapIfFalse(wasm::kTrapFuncInvalid, Int32Constant(0));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002040 return trap_->GetTrapValue(module_->GetSignature(index));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002041 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002042 Node* table = FunctionTable();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002043
2044 // Load signature from the table and check.
2045 // The table is a FixedArray; signatures are encoded as SMIs.
2046 // [sig1, sig2, sig3, ...., code1, code2, code3 ...]
2047 ElementAccess access = AccessBuilder::ForFixedArrayElement();
2048 const int fixed_offset = access.header_size - access.tag();
2049 {
2050 Node* load_sig = graph()->NewNode(
2051 machine->Load(MachineType::AnyTagged()), table,
2052 graph()->NewNode(machine->Int32Add(),
2053 graph()->NewNode(machine->Word32Shl(), key,
2054 Int32Constant(kPointerSizeLog2)),
2055 Int32Constant(fixed_offset)),
2056 *effect_, *control_);
2057 Node* sig_match = graph()->NewNode(machine->WordEqual(), load_sig,
2058 jsgraph()->SmiConstant(index));
Ben Murdochda12d292016-06-02 14:46:10 +01002059 trap_->AddTrapIfFalse(wasm::kTrapFuncSigMismatch, sig_match);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002060 }
2061
2062 // Load code object from the table.
2063 int offset = fixed_offset + kPointerSize * table_size;
2064 Node* load_code = graph()->NewNode(
2065 machine->Load(MachineType::AnyTagged()), table,
2066 graph()->NewNode(machine->Int32Add(),
2067 graph()->NewNode(machine->Word32Shl(), key,
2068 Int32Constant(kPointerSizeLog2)),
2069 Int32Constant(offset)),
2070 *effect_, *control_);
2071
2072 args[0] = load_code;
2073 wasm::FunctionSig* sig = module_->GetSignature(index);
2074 return BuildWasmCall(sig, args);
2075}
2076
2077
2078Node* WasmGraphBuilder::ToJS(Node* node, Node* context, wasm::LocalType type) {
2079 SimplifiedOperatorBuilder simplified(jsgraph()->zone());
2080 switch (type) {
2081 case wasm::kAstI32:
2082 return graph()->NewNode(simplified.ChangeInt32ToTagged(), node);
2083 case wasm::kAstI64:
2084 // TODO(titzer): i64->JS has no good solution right now. Using lower 32
2085 // bits.
2086 node =
2087 graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(), node);
2088 return graph()->NewNode(simplified.ChangeInt32ToTagged(), node);
2089 case wasm::kAstF32:
2090 node = graph()->NewNode(jsgraph()->machine()->ChangeFloat32ToFloat64(),
2091 node);
2092 return graph()->NewNode(simplified.ChangeFloat64ToTagged(), node);
2093 case wasm::kAstF64:
2094 return graph()->NewNode(simplified.ChangeFloat64ToTagged(), node);
2095 case wasm::kAstStmt:
2096 return jsgraph()->UndefinedConstant();
2097 default:
2098 UNREACHABLE();
2099 return nullptr;
2100 }
2101}
2102
2103
2104Node* WasmGraphBuilder::FromJS(Node* node, Node* context,
2105 wasm::LocalType type) {
2106 // Do a JavaScript ToNumber.
2107 Node* num =
2108 graph()->NewNode(jsgraph()->javascript()->ToNumber(), node, context,
2109 jsgraph()->EmptyFrameState(), *effect_, *control_);
2110 *control_ = num;
2111 *effect_ = num;
2112
2113 // Change representation.
2114 SimplifiedOperatorBuilder simplified(jsgraph()->zone());
2115 num = graph()->NewNode(simplified.ChangeTaggedToFloat64(), num);
2116
2117 switch (type) {
2118 case wasm::kAstI32: {
2119 num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToInt32(
2120 TruncationMode::kJavaScript),
2121 num);
2122 break;
2123 }
2124 case wasm::kAstI64:
2125 // TODO(titzer): JS->i64 has no good solution right now. Using 32 bits.
2126 num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToInt32(
2127 TruncationMode::kJavaScript),
2128 num);
2129 num = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), num);
2130 break;
2131 case wasm::kAstF32:
2132 num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToFloat32(),
2133 num);
2134 break;
2135 case wasm::kAstF64:
2136 break;
2137 case wasm::kAstStmt:
2138 num = jsgraph()->Int32Constant(0);
2139 break;
2140 default:
2141 UNREACHABLE();
2142 return nullptr;
2143 }
2144 return num;
2145}
2146
Ben Murdochda12d292016-06-02 14:46:10 +01002147Node* WasmGraphBuilder::BuildI32Rol(Node* left, Node* right) {
2148 // Implement Rol by Ror since TurboFan does not have Rol opcode.
2149 // TODO(weiliang): support Word32Rol opcode in TurboFan.
2150 Int32Matcher m(right);
2151 if (m.HasValue()) {
2152 return Binop(wasm::kExprI32Ror, left,
2153 jsgraph()->Int32Constant(32 - m.Value()));
2154 } else {
2155 return Binop(wasm::kExprI32Ror, left,
2156 Binop(wasm::kExprI32Sub, jsgraph()->Int32Constant(32), right));
2157 }
2158}
2159
2160Node* WasmGraphBuilder::BuildI64Rol(Node* left, Node* right) {
2161 // Implement Rol by Ror since TurboFan does not have Rol opcode.
2162 // TODO(weiliang): support Word64Rol opcode in TurboFan.
2163 Int64Matcher m(right);
2164 if (m.HasValue()) {
2165 return Binop(wasm::kExprI64Ror, left,
2166 jsgraph()->Int64Constant(64 - m.Value()));
2167 } else {
2168 return Binop(wasm::kExprI64Ror, left,
2169 Binop(wasm::kExprI64Sub, jsgraph()->Int64Constant(64), right));
2170 }
2171}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002172
2173Node* WasmGraphBuilder::Invert(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01002174 return Unop(wasm::kExprI32Eqz, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002175}
2176
2177
2178void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code,
2179 wasm::FunctionSig* sig) {
2180 int params = static_cast<int>(sig->parameter_count());
2181 int count = params + 3;
2182 Node** args = Buffer(count);
2183
2184 // Build the start and the JS parameter nodes.
Ben Murdochda12d292016-06-02 14:46:10 +01002185 Node* start = Start(params + 5);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002186 *control_ = start;
2187 *effect_ = start;
Ben Murdochda12d292016-06-02 14:46:10 +01002188 // Create the context parameter
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002189 Node* context = graph()->NewNode(
Ben Murdochda12d292016-06-02 14:46:10 +01002190 jsgraph()->common()->Parameter(
2191 Linkage::GetJSCallContextParamIndex(params + 1), "%context"),
2192 graph()->start());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002193
2194 int pos = 0;
2195 args[pos++] = Constant(wasm_code);
2196
2197 // Convert JS parameters to WASM numbers.
2198 for (int i = 0; i < params; i++) {
Ben Murdochda12d292016-06-02 14:46:10 +01002199 Node* param =
2200 graph()->NewNode(jsgraph()->common()->Parameter(i + 1), start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002201 args[pos++] = FromJS(param, context, sig->GetParam(i));
2202 }
2203
2204 args[pos++] = *effect_;
2205 args[pos++] = *control_;
2206
2207 // Call the WASM code.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002208 CallDescriptor* desc =
2209 wasm::ModuleEnv::GetWasmCallDescriptor(jsgraph()->zone(), sig);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002210 Node* call = graph()->NewNode(jsgraph()->common()->Call(desc), count, args);
2211 Node* jsval =
2212 ToJS(call, context,
2213 sig->return_count() == 0 ? wasm::kAstStmt : sig->GetReturn());
2214 Node* ret =
2215 graph()->NewNode(jsgraph()->common()->Return(), jsval, call, start);
2216
2217 MergeControlToEnd(jsgraph(), ret);
2218}
2219
2220
2221void WasmGraphBuilder::BuildWasmToJSWrapper(Handle<JSFunction> function,
2222 wasm::FunctionSig* sig) {
2223 int js_count = function->shared()->internal_formal_parameter_count();
2224 int wasm_count = static_cast<int>(sig->parameter_count());
2225
2226 // Build the start and the parameter nodes.
2227 Isolate* isolate = jsgraph()->isolate();
2228 CallDescriptor* desc;
2229 Node* start = Start(wasm_count + 3);
2230 *effect_ = start;
2231 *control_ = start;
2232 // JS context is the last parameter.
2233 Node* context = Constant(Handle<Context>(function->context(), isolate));
2234 Node** args = Buffer(wasm_count + 7);
2235
2236 bool arg_count_before_args = false;
2237 bool add_new_target_undefined = false;
2238
2239 int pos = 0;
2240 if (js_count == wasm_count) {
2241 // exact arity match, just call the function directly.
2242 desc = Linkage::GetJSCallDescriptor(graph()->zone(), false, wasm_count + 1,
2243 CallDescriptor::kNoFlags);
2244 arg_count_before_args = false;
2245 add_new_target_undefined = true;
2246 } else {
2247 // Use the Call builtin.
2248 Callable callable = CodeFactory::Call(isolate);
2249 args[pos++] = jsgraph()->HeapConstant(callable.code());
2250 desc = Linkage::GetStubCallDescriptor(isolate, graph()->zone(),
2251 callable.descriptor(), wasm_count + 1,
2252 CallDescriptor::kNoFlags);
2253 arg_count_before_args = true;
2254 }
2255
2256 args[pos++] = jsgraph()->Constant(function); // JS function.
2257 if (arg_count_before_args) {
2258 args[pos++] = jsgraph()->Int32Constant(wasm_count); // argument count
2259 }
2260 // JS receiver.
2261 Handle<Object> global(function->context()->global_object(), isolate);
2262 args[pos++] = jsgraph()->Constant(global);
2263
2264 // Convert WASM numbers to JS values.
2265 for (int i = 0; i < wasm_count; i++) {
2266 Node* param = graph()->NewNode(jsgraph()->common()->Parameter(i), start);
2267 args[pos++] = ToJS(param, context, sig->GetParam(i));
2268 }
2269
2270 if (add_new_target_undefined) {
2271 args[pos++] = jsgraph()->UndefinedConstant(); // new target
2272 }
2273
2274 if (!arg_count_before_args) {
2275 args[pos++] = jsgraph()->Int32Constant(wasm_count); // argument count
2276 }
2277 args[pos++] = context;
2278 args[pos++] = *effect_;
2279 args[pos++] = *control_;
2280
2281 Node* call = graph()->NewNode(jsgraph()->common()->Call(desc), pos, args);
2282
2283 // Convert the return value back.
2284 Node* val =
2285 FromJS(call, context,
2286 sig->return_count() == 0 ? wasm::kAstStmt : sig->GetReturn());
2287 Node* ret = graph()->NewNode(jsgraph()->common()->Return(), val, call, start);
2288
2289 MergeControlToEnd(jsgraph(), ret);
2290}
2291
2292
2293Node* WasmGraphBuilder::MemBuffer(uint32_t offset) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002294 DCHECK(module_ && module_->instance);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002295 if (offset == 0) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002296 if (!mem_buffer_) {
2297 mem_buffer_ = jsgraph()->IntPtrConstant(
2298 reinterpret_cast<uintptr_t>(module_->instance->mem_start));
2299 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002300 return mem_buffer_;
2301 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002302 return jsgraph()->IntPtrConstant(
2303 reinterpret_cast<uintptr_t>(module_->instance->mem_start + offset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002304 }
2305}
2306
2307
2308Node* WasmGraphBuilder::MemSize(uint32_t offset) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002309 DCHECK(module_ && module_->instance);
2310 uint32_t size = static_cast<uint32_t>(module_->instance->mem_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002311 if (offset == 0) {
2312 if (!mem_size_) mem_size_ = jsgraph()->Int32Constant(size);
2313 return mem_size_;
2314 } else {
2315 return jsgraph()->Int32Constant(size + offset);
2316 }
2317}
2318
2319
2320Node* WasmGraphBuilder::FunctionTable() {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002321 DCHECK(module_ && module_->instance &&
2322 !module_->instance->function_table.is_null());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002323 if (!function_table_) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002324 function_table_ = jsgraph()->Constant(module_->instance->function_table);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002325 }
2326 return function_table_;
2327}
2328
2329
2330Node* WasmGraphBuilder::LoadGlobal(uint32_t index) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002331 DCHECK(module_ && module_->instance && module_->instance->globals_start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002332 MachineType mem_type = module_->GetGlobalType(index);
2333 Node* addr = jsgraph()->IntPtrConstant(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002334 reinterpret_cast<uintptr_t>(module_->instance->globals_start +
Ben Murdochda12d292016-06-02 14:46:10 +01002335 module_->module->globals[index].offset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002336 const Operator* op = jsgraph()->machine()->Load(mem_type);
2337 Node* node = graph()->NewNode(op, addr, jsgraph()->Int32Constant(0), *effect_,
2338 *control_);
2339 *effect_ = node;
2340 return node;
2341}
2342
2343
2344Node* WasmGraphBuilder::StoreGlobal(uint32_t index, Node* val) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002345 DCHECK(module_ && module_->instance && module_->instance->globals_start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002346 MachineType mem_type = module_->GetGlobalType(index);
2347 Node* addr = jsgraph()->IntPtrConstant(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002348 reinterpret_cast<uintptr_t>(module_->instance->globals_start +
Ben Murdochda12d292016-06-02 14:46:10 +01002349 module_->module->globals[index].offset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002350 const Operator* op = jsgraph()->machine()->Store(
2351 StoreRepresentation(mem_type.representation(), kNoWriteBarrier));
2352 Node* node = graph()->NewNode(op, addr, jsgraph()->Int32Constant(0), val,
2353 *effect_, *control_);
2354 *effect_ = node;
2355 return node;
2356}
2357
2358
2359void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index,
2360 uint32_t offset) {
2361 // TODO(turbofan): fold bounds checks for constant indexes.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002362 DCHECK(module_ && module_->instance);
2363 size_t size = module_->instance->mem_size;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002364 byte memsize = wasm::WasmOpcodes::MemSize(memtype);
2365 Node* cond;
Ben Murdoch097c5b22016-05-18 11:27:45 +01002366 if (offset >= size || (static_cast<uint64_t>(offset) + memsize) > size) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002367 // The access will always throw.
2368 cond = jsgraph()->Int32Constant(0);
2369 } else {
2370 // Check against the limit.
2371 size_t limit = size - offset - memsize;
2372 CHECK(limit <= kMaxUInt32);
2373 cond = graph()->NewNode(
2374 jsgraph()->machine()->Uint32LessThanOrEqual(), index,
2375 jsgraph()->Int32Constant(static_cast<uint32_t>(limit)));
2376 }
2377
Ben Murdochda12d292016-06-02 14:46:10 +01002378 trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002379}
2380
2381
2382Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype,
2383 Node* index, uint32_t offset) {
2384 Node* load;
2385
Ben Murdochda12d292016-06-02 14:46:10 +01002386 if (module_ && module_->asm_js()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002387 // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish).
2388 DCHECK_EQ(0, offset);
2389 const Operator* op = jsgraph()->machine()->CheckedLoad(memtype);
2390 load = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), *effect_,
2391 *control_);
2392 } else {
2393 // WASM semantics throw on OOB. Introduce explicit bounds check.
2394 BoundsCheckMem(memtype, index, offset);
2395 load = graph()->NewNode(jsgraph()->machine()->Load(memtype),
2396 MemBuffer(offset), index, *effect_, *control_);
2397 }
2398
2399 *effect_ = load;
2400
2401 if (type == wasm::kAstI64 &&
2402 ElementSizeLog2Of(memtype.representation()) < 3) {
2403 // TODO(titzer): TF zeroes the upper bits of 64-bit loads for subword sizes.
2404 if (memtype.IsSigned()) {
2405 // sign extend
2406 load = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load);
2407 } else {
2408 // zero extend
2409 load =
2410 graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), load);
2411 }
2412 }
2413
2414 return load;
2415}
2416
2417
2418Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index,
2419 uint32_t offset, Node* val) {
2420 Node* store;
Ben Murdochda12d292016-06-02 14:46:10 +01002421 if (module_ && module_->asm_js()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002422 // asm.js semantics use CheckedStore (i.e. ignore OOB writes).
2423 DCHECK_EQ(0, offset);
2424 const Operator* op =
2425 jsgraph()->machine()->CheckedStore(memtype.representation());
2426 store = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), val, *effect_,
2427 *control_);
2428 } else {
2429 // WASM semantics throw on OOB. Introduce explicit bounds check.
2430 BoundsCheckMem(memtype, index, offset);
2431 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier);
2432 store =
2433 graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset),
2434 index, val, *effect_, *control_);
2435 }
2436 *effect_ = store;
2437 return store;
2438}
2439
2440
2441void WasmGraphBuilder::PrintDebugName(Node* node) {
2442 PrintF("#%d:%s", node->id(), node->op()->mnemonic());
2443}
2444
2445
2446Node* WasmGraphBuilder::String(const char* string) {
2447 return jsgraph()->Constant(
2448 jsgraph()->isolate()->factory()->NewStringFromAsciiChecked(string));
2449}
2450
2451
2452Graph* WasmGraphBuilder::graph() { return jsgraph()->graph(); }
2453
Ben Murdoch097c5b22016-05-18 11:27:45 +01002454void WasmGraphBuilder::Int64LoweringForTesting() {
Ben Murdochda12d292016-06-02 14:46:10 +01002455 if (jsgraph()->machine()->Is32()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002456 Int64Lowering r(jsgraph()->graph(), jsgraph()->machine(),
2457 jsgraph()->common(), jsgraph()->zone(),
2458 function_signature_);
2459 r.LowerGraph();
2460 }
2461}
2462
2463static void RecordFunctionCompilation(Logger::LogEventsAndTags tag,
2464 CompilationInfo* info,
2465 const char* message, uint32_t index,
Ben Murdochda12d292016-06-02 14:46:10 +01002466 wasm::WasmName func_name) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002467 Isolate* isolate = info->isolate();
2468 if (isolate->logger()->is_logging_code_events() ||
2469 isolate->cpu_profiler()->is_profiling()) {
2470 ScopedVector<char> buffer(128);
Ben Murdochda12d292016-06-02 14:46:10 +01002471 SNPrintF(buffer, "%s#%d:%.*s", message, index, func_name.length,
2472 func_name.name);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002473 Handle<String> name_str =
2474 isolate->factory()->NewStringFromAsciiChecked(buffer.start());
2475 Handle<String> script_str =
2476 isolate->factory()->NewStringFromAsciiChecked("(WASM)");
2477 Handle<Code> code = info->code();
2478 Handle<SharedFunctionInfo> shared =
2479 isolate->factory()->NewSharedFunctionInfo(name_str, code, false);
Ben Murdochda12d292016-06-02 14:46:10 +01002480 PROFILE(isolate, CodeCreateEvent(tag, AbstractCode::cast(*code), *shared,
2481 info, *script_str, 0, 0));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002482 }
2483}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002484
2485Handle<JSFunction> CompileJSToWasmWrapper(
2486 Isolate* isolate, wasm::ModuleEnv* module, Handle<String> name,
2487 Handle<Code> wasm_code, Handle<JSObject> module_object, uint32_t index) {
Ben Murdochda12d292016-06-02 14:46:10 +01002488 wasm::WasmFunction* func = &module->module->functions[index];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002489
2490 //----------------------------------------------------------------------------
2491 // Create the JSFunction object.
2492 //----------------------------------------------------------------------------
2493 Handle<SharedFunctionInfo> shared =
2494 isolate->factory()->NewSharedFunctionInfo(name, wasm_code, false);
2495 int params = static_cast<int>(func->sig->parameter_count());
2496 shared->set_length(params);
Ben Murdochda12d292016-06-02 14:46:10 +01002497 shared->set_internal_formal_parameter_count(params);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002498 Handle<JSFunction> function = isolate->factory()->NewFunction(
2499 isolate->wasm_function_map(), name, MaybeHandle<Code>());
2500 function->SetInternalField(0, *module_object);
2501 function->set_shared(*shared);
2502
2503 //----------------------------------------------------------------------------
2504 // Create the Graph
2505 //----------------------------------------------------------------------------
Ben Murdochda12d292016-06-02 14:46:10 +01002506 Zone zone(isolate->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002507 Graph graph(&zone);
2508 CommonOperatorBuilder common(&zone);
2509 JSOperatorBuilder javascript(&zone);
2510 MachineOperatorBuilder machine(&zone);
2511 JSGraph jsgraph(isolate, &graph, &common, &javascript, nullptr, &machine);
2512
2513 Node* control = nullptr;
2514 Node* effect = nullptr;
2515
2516 WasmGraphBuilder builder(&zone, &jsgraph, func->sig);
2517 builder.set_control_ptr(&control);
2518 builder.set_effect_ptr(&effect);
2519 builder.set_module(module);
2520 builder.BuildJSToWasmWrapper(wasm_code, func->sig);
2521
2522 //----------------------------------------------------------------------------
2523 // Run the compilation pipeline.
2524 //----------------------------------------------------------------------------
2525 {
2526 // Changes lowering requires types.
2527 Typer typer(isolate, &graph);
2528 NodeVector roots(&zone);
2529 jsgraph.GetCachedNodes(&roots);
2530 typer.Run(roots);
2531
2532 // Run generic and change lowering.
2533 JSGenericLowering generic(true, &jsgraph);
2534 ChangeLowering changes(&jsgraph);
2535 GraphReducer graph_reducer(&zone, &graph, jsgraph.Dead());
2536 graph_reducer.AddReducer(&changes);
2537 graph_reducer.AddReducer(&generic);
2538 graph_reducer.ReduceGraph();
2539
2540 if (FLAG_trace_turbo_graph) { // Simple textual RPO.
2541 OFStream os(stdout);
2542 os << "-- Graph after change lowering -- " << std::endl;
2543 os << AsRPO(graph);
2544 }
2545
2546 // Schedule and compile to machine code.
2547 int params = static_cast<int>(
2548 module->GetFunctionSignature(index)->parameter_count());
2549 CallDescriptor* incoming = Linkage::GetJSCallDescriptor(
2550 &zone, false, params + 1, CallDescriptor::kNoFlags);
Ben Murdochda12d292016-06-02 14:46:10 +01002551 Code::Flags flags = Code::ComputeFlags(Code::JS_TO_WASM_FUNCTION);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002552 bool debugging =
2553#if DEBUG
2554 true;
2555#else
2556 FLAG_print_opt_code || FLAG_trace_turbo || FLAG_trace_turbo_graph;
2557#endif
2558 const char* func_name = "js-to-wasm";
2559
2560 static unsigned id = 0;
2561 Vector<char> buffer;
2562 if (debugging) {
2563 buffer = Vector<char>::New(128);
2564 SNPrintF(buffer, "js-to-wasm#%d", id);
2565 func_name = buffer.start();
2566 }
2567
2568 CompilationInfo info(func_name, isolate, &zone, flags);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002569 Handle<Code> code =
2570 Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr);
Ben Murdochda12d292016-06-02 14:46:10 +01002571#ifdef ENABLE_DISASSEMBLER
2572 if (FLAG_print_opt_code && !code.is_null()) {
2573 OFStream os(stdout);
2574 code->Disassemble(buffer.start(), os);
2575 }
2576#endif
Ben Murdoch097c5b22016-05-18 11:27:45 +01002577 if (debugging) {
2578 buffer.Dispose();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002579 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002580
Ben Murdochda12d292016-06-02 14:46:10 +01002581 RecordFunctionCompilation(
2582 Logger::FUNCTION_TAG, &info, "js-to-wasm", index,
2583 module->module->GetName(func->name_offset, func->name_length));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002584 // Set the JSFunction's machine code.
2585 function->set_code(*code);
2586 }
2587 return function;
2588}
2589
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002590Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, wasm::ModuleEnv* module,
2591 Handle<JSFunction> function,
Ben Murdochda12d292016-06-02 14:46:10 +01002592 wasm::FunctionSig* sig,
2593 wasm::WasmName module_name,
2594 wasm::WasmName function_name) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002595 //----------------------------------------------------------------------------
2596 // Create the Graph
2597 //----------------------------------------------------------------------------
Ben Murdochda12d292016-06-02 14:46:10 +01002598 Zone zone(isolate->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002599 Graph graph(&zone);
2600 CommonOperatorBuilder common(&zone);
2601 JSOperatorBuilder javascript(&zone);
2602 MachineOperatorBuilder machine(&zone);
2603 JSGraph jsgraph(isolate, &graph, &common, &javascript, nullptr, &machine);
2604
2605 Node* control = nullptr;
2606 Node* effect = nullptr;
2607
Ben Murdoch097c5b22016-05-18 11:27:45 +01002608 WasmGraphBuilder builder(&zone, &jsgraph, sig);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002609 builder.set_control_ptr(&control);
2610 builder.set_effect_ptr(&effect);
2611 builder.set_module(module);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002612 builder.BuildWasmToJSWrapper(function, sig);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002613
2614 Handle<Code> code = Handle<Code>::null();
2615 {
2616 // Changes lowering requires types.
2617 Typer typer(isolate, &graph);
2618 NodeVector roots(&zone);
2619 jsgraph.GetCachedNodes(&roots);
2620 typer.Run(roots);
2621
2622 // Run generic and change lowering.
2623 JSGenericLowering generic(true, &jsgraph);
2624 ChangeLowering changes(&jsgraph);
2625 GraphReducer graph_reducer(&zone, &graph, jsgraph.Dead());
2626 graph_reducer.AddReducer(&changes);
2627 graph_reducer.AddReducer(&generic);
2628 graph_reducer.ReduceGraph();
2629
2630 if (FLAG_trace_turbo_graph) { // Simple textual RPO.
2631 OFStream os(stdout);
2632 os << "-- Graph after change lowering -- " << std::endl;
2633 os << AsRPO(graph);
2634 }
2635
2636 // Schedule and compile to machine code.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002637 CallDescriptor* incoming =
2638 wasm::ModuleEnv::GetWasmCallDescriptor(&zone, sig);
Ben Murdochda12d292016-06-02 14:46:10 +01002639 Code::Flags flags = Code::ComputeFlags(Code::WASM_TO_JS_FUNCTION);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002640 bool debugging =
2641#if DEBUG
2642 true;
2643#else
2644 FLAG_print_opt_code || FLAG_trace_turbo || FLAG_trace_turbo_graph;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002645#endif
Ben Murdoch097c5b22016-05-18 11:27:45 +01002646 const char* func_name = "wasm-to-js";
2647 static unsigned id = 0;
2648 Vector<char> buffer;
2649 if (debugging) {
2650 buffer = Vector<char>::New(128);
2651 SNPrintF(buffer, "wasm-to-js#%d", id);
2652 func_name = buffer.start();
2653 }
2654
2655 CompilationInfo info(func_name, isolate, &zone, flags);
2656 code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr);
Ben Murdochda12d292016-06-02 14:46:10 +01002657#ifdef ENABLE_DISASSEMBLER
2658 if (FLAG_print_opt_code && !code.is_null()) {
2659 OFStream os(stdout);
2660 code->Disassemble(buffer.start(), os);
2661 }
2662#endif
Ben Murdoch097c5b22016-05-18 11:27:45 +01002663 if (debugging) {
2664 buffer.Dispose();
2665 }
2666
2667 RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, "wasm-to-js", 0,
Ben Murdochda12d292016-06-02 14:46:10 +01002668 module_name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002669 }
2670 return code;
2671}
2672
2673
2674// Helper function to compile a single function.
2675Handle<Code> CompileWasmFunction(wasm::ErrorThrower& thrower, Isolate* isolate,
2676 wasm::ModuleEnv* module_env,
Ben Murdoch097c5b22016-05-18 11:27:45 +01002677 const wasm::WasmFunction& function) {
Ben Murdochda12d292016-06-02 14:46:10 +01002678 if (FLAG_trace_wasm_compiler) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002679 OFStream os(stdout);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002680 os << "Compiling WASM function "
2681 << wasm::WasmFunctionName(&function, module_env) << std::endl;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002682 os << std::endl;
2683 }
Ben Murdochda12d292016-06-02 14:46:10 +01002684
2685 double decode_ms = 0;
2686 base::ElapsedTimer decode_timer;
2687 if (FLAG_trace_wasm_decode_time) {
2688 decode_timer.Start();
2689 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002690
2691 // Create a TF graph during decoding.
Ben Murdochda12d292016-06-02 14:46:10 +01002692 Zone zone(isolate->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002693 Graph graph(&zone);
2694 CommonOperatorBuilder common(&zone);
2695 MachineOperatorBuilder machine(
2696 &zone, MachineType::PointerRepresentation(),
2697 InstructionSelector::SupportedMachineOperatorFlags());
2698 JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
2699 WasmGraphBuilder builder(&zone, &jsgraph, function.sig);
Ben Murdochda12d292016-06-02 14:46:10 +01002700 wasm::FunctionBody body = {
2701 module_env, function.sig, module_env->module->module_start,
2702 module_env->module->module_start + function.code_start_offset,
2703 module_env->module->module_start + function.code_end_offset};
2704 wasm::TreeResult result =
2705 wasm::BuildTFGraph(isolate->allocator(), &builder, body);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002706
2707 if (result.failed()) {
2708 if (FLAG_trace_wasm_compiler) {
2709 OFStream os(stdout);
2710 os << "Compilation failed: " << result << std::endl;
2711 }
2712 // Add the function as another context for the exception
Ben Murdoch097c5b22016-05-18 11:27:45 +01002713 ScopedVector<char> buffer(128);
Ben Murdochda12d292016-06-02 14:46:10 +01002714 wasm::WasmName name =
2715 module_env->module->GetName(function.name_offset, function.name_length);
2716 SNPrintF(buffer, "Compiling WASM function #%d:%.*s failed:",
2717 function.func_index, name.length, name.name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002718 thrower.Failed(buffer.start(), result);
2719 return Handle<Code>::null();
2720 }
2721
Ben Murdochda12d292016-06-02 14:46:10 +01002722 int index = static_cast<int>(function.func_index);
2723 if (index >= FLAG_trace_wasm_ast_start && index < FLAG_trace_wasm_ast_end) {
2724 PrintAst(isolate->allocator(), body);
2725 }
2726
2727 if (FLAG_trace_wasm_decode_time) {
2728 decode_ms = decode_timer.Elapsed().InMillisecondsF();
2729 }
2730
2731 base::ElapsedTimer compile_timer;
2732 if (FLAG_trace_wasm_decode_time) {
2733 compile_timer.Start();
2734 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002735 // Run the compiler pipeline to generate machine code.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002736 CallDescriptor* descriptor =
2737 wasm::ModuleEnv::GetWasmCallDescriptor(&zone, function.sig);
Ben Murdochda12d292016-06-02 14:46:10 +01002738 if (machine.Is32()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002739 descriptor = module_env->GetI32WasmCallDescriptor(&zone, descriptor);
2740 }
2741 Code::Flags flags = Code::ComputeFlags(Code::WASM_FUNCTION);
2742 // add flags here if a meaningful name is helpful for debugging.
2743 bool debugging =
2744#if DEBUG
2745 true;
2746#else
2747 FLAG_print_opt_code || FLAG_trace_turbo || FLAG_trace_turbo_graph;
2748#endif
2749 const char* func_name = "wasm";
2750 Vector<char> buffer;
2751 if (debugging) {
2752 buffer = Vector<char>::New(128);
Ben Murdochda12d292016-06-02 14:46:10 +01002753 wasm::WasmName name =
2754 module_env->module->GetName(function.name_offset, function.name_length);
2755 SNPrintF(buffer, "WASM_function_#%d:%.*s", function.func_index, name.length,
2756 name.name);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002757 func_name = buffer.start();
2758 }
2759 CompilationInfo info(func_name, isolate, &zone, flags);
2760
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002761 Handle<Code> code =
2762 Pipeline::GenerateCodeForTesting(&info, descriptor, &graph);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002763 if (debugging) {
2764 buffer.Dispose();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002765 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002766 if (!code.is_null()) {
Ben Murdochda12d292016-06-02 14:46:10 +01002767 RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, "WASM_function",
2768 function.func_index,
2769 module_env->module->GetName(
2770 function.name_offset, function.name_length));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002771 }
2772
Ben Murdochda12d292016-06-02 14:46:10 +01002773 if (FLAG_trace_wasm_decode_time) {
2774 double compile_ms = compile_timer.Elapsed().InMillisecondsF();
2775 PrintF(
2776 "wasm-compile ok: %d bytes, %0.3f ms decode, %d nodes, %0.3f ms "
2777 "compile\n",
2778 static_cast<int>(function.code_end_offset - function.code_start_offset),
2779 decode_ms, static_cast<int>(graph.NodeCount()), compile_ms);
2780 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002781 return code;
2782}
2783
2784
2785} // namespace compiler
2786} // namespace internal
2787} // namespace v8