Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(679)

Side by Side Diff: src/compiler/wasm-compiler.cc

Issue 1504713014: Initial import of v8-native WASM. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // 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
6 #include "src/compiler/access-builder.h"
7 #include "src/compiler/change-lowering.h"
8 #include "src/compiler/common-operator.h"
9 #include "src/compiler/diamond.h"
10 #include "src/compiler/graph.h"
11 #include "src/compiler/graph-visualizer.h"
12 #include "src/compiler/instruction-selector.h"
13 #include "src/compiler/js-generic-lowering.h"
14 #include "src/compiler/js-graph.h"
15 #include "src/compiler/js-operator.h"
16 #include "src/compiler/linkage.h"
17 #include "src/compiler/machine-operator.h"
18 #include "src/compiler/node-matchers.h"
19 #include "src/compiler/pipeline.h"
20 #include "src/compiler/simplified-lowering.h"
21 #include "src/compiler/simplified-operator.h"
22 #include "src/compiler/source-position.h"
23 #include "src/compiler/typer.h"
24 #include "src/compiler/wasm-compiler.h"
25
26 #include "src/code-factory.h"
27 #include "src/code-stubs.h"
28
29 #include "src/wasm/ast-decoder.h"
30 #include "src/wasm/wasm-module.h"
31 #include "src/wasm/wasm-opcodes.h"
32
33 // TODO(titzer): pull WASM_64 up to a common header.
34 #if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64
35 #define WASM_64 1
36 #else
37 #define WASM_64 0
38 #endif
39
40 namespace v8 {
41 namespace internal {
42 namespace compiler {
43
44 namespace {
45 const Operator* UnsupportedOpcode(wasm::WasmOpcode opcode) {
46 if (wasm::WasmOpcodes::IsSupported(opcode)) {
47 V8_Fatal(__FILE__, __LINE__,
48 "Unsupported opcode #%d:%s reported as supported", opcode,
49 wasm::WasmOpcodes::OpcodeName(opcode));
50 }
51 V8_Fatal(__FILE__, __LINE__, "Unsupported opcode #%d:%s", opcode,
52 wasm::WasmOpcodes::OpcodeName(opcode));
53 return nullptr;
54 }
55
56
57 void MergeControlToEnd(JSGraph* graph, Node* node) {
58 Graph* g = graph->graph();
59 if (g->end()) {
60 NodeProperties::MergeControlToEnd(g, graph->common(), node);
61 } else {
62 g->SetEnd(g->NewNode(graph->common()->End(1), node));
63 }
64 }
65
66
67 enum TrapReason {
68 kTrapUnreachable,
69 kTrapMemOutOfBounds,
70 kTrapDivByZero,
71 kTrapDivUnrepresentable,
72 kTrapRemByZero,
73 kTrapFloatUnrepresentable,
74 kTrapFuncInvalid,
75 kTrapFuncSigMismatch,
76 kTrapCount
77 };
78
79
80 static const char* kTrapMessages[] = {
81 "unreachable", "memory access out of bounds",
82 "divide by zero", "divide result unrepresentable",
83 "remainder by zero", "integer result unrepresentable",
84 "invalid function", "function signature mismatch"};
85 } // namespace
86
87
88 // A helper that handles building graph fragments for trapping.
89 // To avoid generating a ton of redundant code that just calls the runtime
90 // to trap, we generate a per-trap-reason block of code that all trap sites
91 // in this function will branch to.
92 class WasmTrapHelper : public ZoneObject {
93 public:
94 explicit WasmTrapHelper(WasmGraphBuilder* b)
95 : builder(b), graph(b->graph), g(b->graph ? b->graph->graph() : nullptr) {
96 for (int i = 0; i < kTrapCount; i++) traps[i] = nullptr;
97 }
98
99 // Make the current control path trap to unreachable.
100 void Unreachable() { ConnectTrap(kTrapUnreachable); }
101 // Add a check that traps if {node} is equal to {val}.
102 Node* TrapIfEq32(TrapReason reason, Node* node, int32_t val) {
103 Int32Matcher m(node);
104 if (m.HasValue() && !m.Is(val)) return g->start();
105 if (val == 0) {
106 AddTrapIfFalse(reason, node);
107 } else {
108 AddTrapIfTrue(reason, g->NewNode(graph->machine()->Word32Equal(), node,
109 graph->Int32Constant(val)));
110 }
111 return *(builder->control);
112 }
113 // Add a check that traps if {node} is zero.
114 Node* ZeroCheck32(TrapReason reason, Node* node) {
115 return TrapIfEq32(reason, node, 0);
116 }
117 // Add a check that traps if {node} is equal to {val}.
118 Node* TrapIfEq64(TrapReason reason, Node* node, int64_t val) {
119 Int64Matcher m(node);
120 if (m.HasValue() && !m.Is(val)) return g->start();
121 AddTrapIfTrue(reason, g->NewNode(graph->machine()->Word64Equal(), node,
122 graph->Int64Constant(val)));
123 return *(builder->control);
124 }
125 // Add a check that traps if {node} is zero.
126 Node* ZeroCheck64(TrapReason reason, Node* node) {
127 return TrapIfEq64(reason, node, 0);
128 }
129 // Add a trap if {cond} is true.
130 void AddTrapIfTrue(TrapReason reason, Node* cond) {
131 AddTrapIf(reason, cond, true);
132 }
133 // Add a trap if {cond} is false.
134 void AddTrapIfFalse(TrapReason reason, Node* cond) {
135 AddTrapIf(reason, cond, false);
136 }
137 // Add a trap if {cond} is true or false according to {iftrue}.
138 void AddTrapIf(TrapReason reason, Node* cond, bool iftrue) {
139 DCHECK_NOT_NULL(graph);
140 Node** effect = builder->effect;
141 Node** control = builder->control;
142 Node* before = *effect;
143 BranchHint hint = iftrue ? BranchHint::kFalse : BranchHint::kTrue;
144 Node* branch =
145 g->NewNode(graph->common()->Branch(hint), cond, *(builder->control));
146 Node* if_true = g->NewNode(graph->common()->IfTrue(), branch);
147 Node* if_false = g->NewNode(graph->common()->IfFalse(), branch);
148
149 *control = iftrue ? if_true : if_false;
150 ConnectTrap(reason);
151 *control = iftrue ? if_false : if_true;
152 *effect = before;
153 }
154
155 private:
156 WasmGraphBuilder* builder;
Michael Starzinger 2015/12/11 09:15:14 nit: Fields don't follow the style guide, missing
titzer 2015/12/11 10:16:20 Done.
157 JSGraph* graph;
158 Graph* g;
159 Node* traps[kTrapCount];
160 Node* effects[kTrapCount];
161
162 void ConnectTrap(TrapReason reason) {
163 if (traps[reason] == nullptr) {
164 // Create trap code for the first time this trap is used.
165 return BuildTrapCode(reason);
166 }
167 // Connect the current control and effect to the existing trap code.
168 builder->AppendToMerge(traps[reason], *(builder->control));
169 builder->AppendToPhi(traps[reason], effects[reason], *(builder->effect));
170 }
171
172 void BuildTrapCode(TrapReason reason) {
173 Node* exception = builder->String(kTrapMessages[reason]);
174 Node* end;
175 Node** control = builder->control;
176 Node** effect = builder->effect;
177 wasm::ModuleEnv* module = builder->module;
178 *control = traps[reason] = g->NewNode(graph->common()->Merge(1), *control);
179 *effect = effects[reason] =
180 g->NewNode(graph->common()->EffectPhi(1), *effect, *control);
181
182 if (module && !module->context.is_null()) {
183 // Use the module context to call the runtime to throw an exception.
184 Runtime::FunctionId f = Runtime::kThrow;
185 const Runtime::Function* fun = Runtime::FunctionForId(f);
186 CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
187 graph->zone(), f, fun->nargs, Operator::kNoProperties,
188 CallDescriptor::kNoFlags);
189 Node* inputs[] = {graph->CEntryStubConstant(fun->result_size), // C entry
190 exception, // exception
191 graph->ExternalConstant(
192 ExternalReference(f, graph->isolate())), // ref
193 graph->Int32Constant(fun->nargs), // arity
194 graph->Constant(module->context), // context
195 *effect,
196 *control};
197
198 Node* node = g->NewNode(graph->common()->Call(desc),
199 static_cast<int>(arraysize(inputs)), inputs);
200 *control = node;
201 *effect = node;
202 }
203 if (false) {
204 // End the control flow with a throw
205 Node* thrw = g->NewNode(graph->common()->Throw(), graph->ZeroConstant(),
206 *effect, *control);
207 end = thrw;
208 } else {
209 // End the control flow with returning 0xdeadbeef
210 Node* ret_dead =
211 g->NewNode(graph->common()->Return(),
212 graph->Int32Constant(0xdeadbeef), *effect, *control);
213 end = ret_dead;
214 }
215
216 MergeControlToEnd(graph, end);
217 }
218 };
219
220
221 WasmGraphBuilder::WasmGraphBuilder(Zone* z, JSGraph* g)
222 : zone(z),
223 graph(g),
224 module(nullptr),
225 mem_buffer(nullptr),
226 mem_size(nullptr),
227 function_table(nullptr),
228 control(nullptr),
229 effect(nullptr),
230 cur_buffer(def_buffer),
231 cur_bufsize(kDefaultBufferSize),
232 trap(new (z) WasmTrapHelper(this)) {}
233
234 Node* WasmGraphBuilder::Error() {
235 DCHECK_NOT_NULL(graph);
236 return graph->Dead();
237 }
238
239
240 Node* WasmGraphBuilder::Start(unsigned params) {
241 DCHECK_NOT_NULL(graph);
242 Graph* g = graph->graph();
243 Node* start = g->NewNode(graph->common()->Start(params));
244 g->SetStart(start);
245 return start;
246 }
247
248
249 Node* WasmGraphBuilder::Param(unsigned index, wasm::LocalType type) {
250 DCHECK_NOT_NULL(graph);
251 Graph* g = graph->graph();
252 return g->NewNode(graph->common()->Parameter(index), g->start());
253 }
254
255
256 Node* WasmGraphBuilder::Loop(Node* entry) {
257 DCHECK_NOT_NULL(graph);
258 return graph->graph()->NewNode(graph->common()->Loop(1), entry);
259 }
260
261
262 Node* WasmGraphBuilder::Terminate(Node* effect, Node* control) {
263 DCHECK_NOT_NULL(graph);
264 Node* terminate =
265 graph->graph()->NewNode(graph->common()->Terminate(), effect, control);
266 MergeControlToEnd(graph, terminate);
267 return terminate;
268 }
269
270
271 unsigned WasmGraphBuilder::InputCount(Node* node) {
272 return static_cast<unsigned>(node->InputCount());
273 }
274
275
276 bool WasmGraphBuilder::IsPhiWithMerge(Node* phi, Node* merge) {
277 return phi && IrOpcode::IsPhiOpcode(phi->opcode()) &&
278 NodeProperties::GetControlInput(phi) == merge;
279 }
280
281
282 void WasmGraphBuilder::AppendToMerge(Node* merge, Node* from) {
283 DCHECK_NOT_NULL(graph);
284 DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
285 merge->AppendInput(graph->zone(), from);
286 int new_size = merge->InputCount();
287 NodeProperties::ChangeOp(
288 merge, graph->common()->ResizeMergeOrPhi(merge->op(), new_size));
289 }
290
291
292 void WasmGraphBuilder::AppendToPhi(Node* merge, Node* phi, Node* from) {
293 DCHECK_NOT_NULL(graph);
294 DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
295 DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
296 int new_size = phi->InputCount();
297 phi->InsertInput(graph->zone(), phi->InputCount() - 1, from);
298 NodeProperties::ChangeOp(
299 phi, graph->common()->ResizeMergeOrPhi(phi->op(), new_size));
300 }
301
302
303 Node* WasmGraphBuilder::Merge(unsigned count, Node** controls) {
304 DCHECK_NOT_NULL(graph);
305 return graph->graph()->NewNode(graph->common()->Merge(count), count,
306 controls);
307 }
308
309
310 Node* WasmGraphBuilder::Phi(wasm::LocalType type, unsigned count, Node** vals,
311 Node* control) {
312 DCHECK(IrOpcode::IsMergeOpcode(control->opcode()));
313 Node** buf = Realloc(vals, count + 1);
314 buf[count] = control;
315 return graph->graph()->NewNode(graph->common()->Phi(type, count), count + 1,
316 buf);
317 }
318
319
320 Node* WasmGraphBuilder::EffectPhi(unsigned count, Node** effects,
321 Node* control) {
322 DCHECK_NOT_NULL(graph);
323 DCHECK(IrOpcode::IsMergeOpcode(control->opcode()));
324 Node** buf = Realloc(effects, count + 1);
325 buf[count] = control;
326 return graph->graph()->NewNode(graph->common()->EffectPhi(count), count + 1,
327 buf);
328 }
329
330
331 Node* WasmGraphBuilder::Int32Constant(int32_t value) {
332 DCHECK_NOT_NULL(graph);
333 return graph->Int32Constant(value);
334 }
335
336
337 Node* WasmGraphBuilder::Int64Constant(int64_t value) {
338 DCHECK_NOT_NULL(graph);
339 return graph->Int64Constant(value);
340 }
341
342
343 Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left,
344 Node* right) {
345 DCHECK_NOT_NULL(graph);
346 const Operator* op;
347 MachineOperatorBuilder* m = graph->machine();
348 switch (opcode) {
349 case wasm::kExprI32Add:
350 op = m->Int32Add();
351 break;
352 case wasm::kExprI32Sub:
353 op = m->Int32Sub();
354 break;
355 case wasm::kExprI32Mul:
356 op = m->Int32Mul();
357 break;
358 case wasm::kExprI32DivS: {
359 trap->ZeroCheck32(kTrapDivByZero, right);
360 Node* before = *control;
361 Node* denom_is_m1;
362 Node* denom_is_not_m1;
363 Branch(graph->graph()->NewNode(graph->machine()->Word32Equal(), right,
364 graph->Int32Constant(-1)),
365 &denom_is_m1, &denom_is_not_m1);
366 *control = denom_is_m1;
367 trap->TrapIfEq32(kTrapDivUnrepresentable, left, kMinInt);
368 if (*control != denom_is_m1) {
369 *control = graph->graph()->NewNode(graph->common()->Merge(2),
370 denom_is_not_m1, *control);
371 } else {
372 *control = before;
373 }
374 return graph->graph()->NewNode(m->Int32Div(), left, right, *control);
375 }
376 case wasm::kExprI32DivU:
377 op = m->Uint32Div();
378 return graph->graph()->NewNode(op, left, right,
379 trap->ZeroCheck32(kTrapDivByZero, right));
380 case wasm::kExprI32RemS: {
381 trap->ZeroCheck32(kTrapRemByZero, right);
382 Diamond d(graph->graph(), graph->common(),
383 graph->graph()->NewNode(graph->machine()->Word32Equal(), right,
384 graph->Int32Constant(-1)));
385
386 Node* rem =
387 graph->graph()->NewNode(m->Int32Mod(), left, right, d.if_false);
388
389 return d.Phi(MachineRepresentation::kWord32, graph->Int32Constant(0),
390 rem);
391 }
392 case wasm::kExprI32RemU:
393 op = m->Uint32Mod();
394 return graph->graph()->NewNode(op, left, right,
395 trap->ZeroCheck32(kTrapRemByZero, right));
396 case wasm::kExprI32And:
397 op = m->Word32And();
398 break;
399 case wasm::kExprI32Ior:
400 op = m->Word32Or();
401 break;
402 case wasm::kExprI32Xor:
403 op = m->Word32Xor();
404 break;
405 case wasm::kExprI32Shl:
406 op = m->Word32Shl();
407 break;
408 case wasm::kExprI32ShrU:
409 op = m->Word32Shr();
410 break;
411 case wasm::kExprI32ShrS:
412 op = m->Word32Sar();
413 break;
414 case wasm::kExprI32Eq:
415 op = m->Word32Equal();
416 break;
417 case wasm::kExprI32Ne:
418 return Invert(Binop(wasm::kExprI32Eq, left, right));
419 case wasm::kExprI32LtS:
420 op = m->Int32LessThan();
421 break;
422 case wasm::kExprI32LeS:
423 op = m->Int32LessThanOrEqual();
424 break;
425 case wasm::kExprI32LtU:
426 op = m->Uint32LessThan();
427 break;
428 case wasm::kExprI32LeU:
429 op = m->Uint32LessThanOrEqual();
430 break;
431 case wasm::kExprI32GtS:
432 op = m->Int32LessThan();
433 std::swap(left, right);
434 break;
435 case wasm::kExprI32GeS:
436 op = m->Int32LessThanOrEqual();
437 std::swap(left, right);
438 break;
439 case wasm::kExprI32GtU:
440 op = m->Uint32LessThan();
441 std::swap(left, right);
442 break;
443 case wasm::kExprI32GeU:
444 op = m->Uint32LessThanOrEqual();
445 std::swap(left, right);
446 break;
447 #if WASM_64
448 // Opcodes only supported on 64-bit platforms.
449 // TODO(titzer): query the machine operator builder here instead of #ifdef.
450 case wasm::kExprI64Add:
451 op = m->Int64Add();
452 break;
453 case wasm::kExprI64Sub:
454 op = m->Int64Sub();
455 break;
456 case wasm::kExprI64Mul:
457 op = m->Int64Mul();
458 break;
459 case wasm::kExprI64DivS: {
460 trap->ZeroCheck64(kTrapDivByZero, right);
461 Node* before = *control;
462 Node* denom_is_m1;
463 Node* denom_is_not_m1;
464 Branch(graph->graph()->NewNode(graph->machine()->Word64Equal(), right,
465 graph->Int64Constant(-1)),
466 &denom_is_m1, &denom_is_not_m1);
467 *control = denom_is_m1;
468 trap->TrapIfEq64(kTrapDivUnrepresentable, left,
469 std::numeric_limits<int64_t>::min());
470 if (*control != denom_is_m1) {
471 *control = graph->graph()->NewNode(graph->common()->Merge(2),
472 denom_is_not_m1, *control);
473 } else {
474 *control = before;
475 }
476 return graph->graph()->NewNode(m->Int64Div(), left, right, *control);
477 }
478 case wasm::kExprI64DivU:
479 op = m->Uint64Div();
480 return graph->graph()->NewNode(op, left, right,
481 trap->ZeroCheck64(kTrapDivByZero, right));
482 case wasm::kExprI64RemS: {
483 trap->ZeroCheck64(kTrapRemByZero, right);
484 Diamond d(graph->graph(), graph->common(),
485 graph->graph()->NewNode(graph->machine()->Word64Equal(), right,
486 graph->Int64Constant(-1)));
487
488 Node* rem =
489 graph->graph()->NewNode(m->Int64Mod(), left, right, d.if_false);
490
491 return d.Phi(MachineRepresentation::kWord64, graph->Int64Constant(0),
492 rem);
493 }
494 case wasm::kExprI64RemU:
495 op = m->Uint64Mod();
496 return graph->graph()->NewNode(op, left, right,
497 trap->ZeroCheck64(kTrapRemByZero, right));
498 case wasm::kExprI64And:
499 op = m->Word64And();
500 break;
501 case wasm::kExprI64Ior:
502 op = m->Word64Or();
503 break;
504 case wasm::kExprI64Xor:
505 op = m->Word64Xor();
506 break;
507 case wasm::kExprI64Shl:
508 op = m->Word64Shl();
509 break;
510 case wasm::kExprI64ShrU:
511 op = m->Word64Shr();
512 break;
513 case wasm::kExprI64ShrS:
514 op = m->Word64Sar();
515 break;
516 case wasm::kExprI64Eq:
517 op = m->Word64Equal();
518 break;
519 case wasm::kExprI64Ne:
520 return Invert(Binop(wasm::kExprI64Eq, left, right));
521 case wasm::kExprI64LtS:
522 op = m->Int64LessThan();
523 break;
524 case wasm::kExprI64LeS:
525 op = m->Int64LessThanOrEqual();
526 break;
527 case wasm::kExprI64LtU:
528 op = m->Uint64LessThan();
529 break;
530 case wasm::kExprI64LeU:
531 op = m->Uint64LessThanOrEqual();
532 break;
533 case wasm::kExprI64GtS:
534 op = m->Int64LessThan();
535 std::swap(left, right);
536 break;
537 case wasm::kExprI64GeS:
538 op = m->Int64LessThanOrEqual();
539 std::swap(left, right);
540 break;
541 case wasm::kExprI64GtU:
542 op = m->Uint64LessThan();
543 std::swap(left, right);
544 break;
545 case wasm::kExprI64GeU:
546 op = m->Uint64LessThanOrEqual();
547 std::swap(left, right);
548 break;
549 #endif
550
551 case wasm::kExprF32CopySign:
552 return BuildF32CopySign(left, right);
553 case wasm::kExprF64CopySign:
554 return BuildF64CopySign(left, right);
555 case wasm::kExprF32Add:
556 op = m->Float32Add();
557 break;
558 case wasm::kExprF32Sub:
559 op = m->Float32Sub();
560 break;
561 case wasm::kExprF32Mul:
562 op = m->Float32Mul();
563 break;
564 case wasm::kExprF32Div:
565 op = m->Float32Div();
566 break;
567 case wasm::kExprF32Eq:
568 op = m->Float32Equal();
569 break;
570 case wasm::kExprF32Ne:
571 return Invert(Binop(wasm::kExprF32Eq, left, right));
572 case wasm::kExprF32Lt:
573 op = m->Float32LessThan();
574 break;
575 case wasm::kExprF32Ge:
576 op = m->Float32LessThanOrEqual();
577 std::swap(left, right);
578 break;
579 case wasm::kExprF32Gt:
580 op = m->Float32LessThan();
581 std::swap(left, right);
582 break;
583 case wasm::kExprF32Le:
584 op = m->Float32LessThanOrEqual();
585 break;
586 case wasm::kExprF64Add:
587 op = m->Float64Add();
588 break;
589 case wasm::kExprF64Sub:
590 op = m->Float64Sub();
591 break;
592 case wasm::kExprF64Mul:
593 op = m->Float64Mul();
594 break;
595 case wasm::kExprF64Div:
596 op = m->Float64Div();
597 break;
598 case wasm::kExprF64Eq:
599 op = m->Float64Equal();
600 break;
601 case wasm::kExprF64Ne:
602 return Invert(Binop(wasm::kExprF64Eq, left, right));
603 case wasm::kExprF64Lt:
604 op = m->Float64LessThan();
605 break;
606 case wasm::kExprF64Le:
607 op = m->Float64LessThanOrEqual();
608 break;
609 case wasm::kExprF64Gt:
610 op = m->Float64LessThan();
611 std::swap(left, right);
612 break;
613 case wasm::kExprF64Ge:
614 op = m->Float64LessThanOrEqual();
615 std::swap(left, right);
616 break;
617 case wasm::kExprF32Min: {
618 if (m->Float32Min().IsSupported()) {
619 op = m->Float32Min().op();
620 break;
621 } else {
622 op = UnsupportedOpcode(opcode);
623 break;
624 }
625 }
626 case wasm::kExprF64Min: {
627 if (m->Float64Min().IsSupported()) {
628 op = m->Float64Min().op();
629 break;
630 } else {
631 op = UnsupportedOpcode(opcode);
632 break;
633 }
634 }
635 case wasm::kExprF32Max: {
636 if (m->Float32Max().IsSupported()) {
637 op = m->Float32Max().op();
638 break;
639 } else {
640 op = UnsupportedOpcode(opcode);
641 break;
642 }
643 }
644 case wasm::kExprF64Max: {
645 if (m->Float64Max().IsSupported()) {
646 op = m->Float64Max().op();
647 break;
648 } else {
649 op = UnsupportedOpcode(opcode);
650 break;
651 }
652 }
653 default:
654 op = UnsupportedOpcode(opcode);
655 }
656 return graph->graph()->NewNode(op, left, right);
657 }
658
659
660 Node* WasmGraphBuilder::Unop(wasm::WasmOpcode opcode, Node* input) {
661 DCHECK_NOT_NULL(graph);
662 const Operator* op;
663 MachineOperatorBuilder* m = graph->machine();
664 switch (opcode) {
665 case wasm::kExprBoolNot:
666 op = m->Word32Equal();
667 return graph->graph()->NewNode(op, input, graph->Int32Constant(0));
668 case wasm::kExprF32Abs:
669 op = m->Float32Abs();
670 break;
671 case wasm::kExprF32Neg:
672 op = m->Float32Sub();
673 return graph->graph()->NewNode(op, graph->Float32Constant(0), input);
674 case wasm::kExprF32Sqrt:
675 op = m->Float32Sqrt();
676 break;
677 case wasm::kExprF64Abs:
678 op = m->Float64Abs();
679 break;
680 case wasm::kExprF64Neg:
681 op = m->Float64Sub();
682 return graph->graph()->NewNode(op, graph->Float64Constant(0), input);
683 case wasm::kExprF64Sqrt:
684 op = m->Float64Sqrt();
685 break;
686 case wasm::kExprI32SConvertF64:
687 op = m->ChangeFloat64ToInt32();
688 break;
689 case wasm::kExprI32UConvertF64:
690 op = m->ChangeFloat64ToUint32();
691 break;
692 case wasm::kExprF32ConvertF64:
693 op = m->TruncateFloat64ToFloat32();
694 break;
695 case wasm::kExprF64SConvertI32:
696 op = m->ChangeInt32ToFloat64();
697 break;
698 case wasm::kExprF64UConvertI32:
699 op = m->ChangeUint32ToFloat64();
700 break;
701 case wasm::kExprF32SConvertI32:
702 op = m->ChangeInt32ToFloat64(); // TODO(titzer): two conversions
703 input = graph->graph()->NewNode(op, input);
704 op = m->TruncateFloat64ToFloat32();
705 break;
706 case wasm::kExprF32UConvertI32:
707 op = m->ChangeUint32ToFloat64(); // TODO(titzer): two conversions
708 input = graph->graph()->NewNode(op, input);
709 op = m->TruncateFloat64ToFloat32();
710 break;
711 case wasm::kExprI32SConvertF32:
712 op = m->ChangeFloat32ToFloat64(); // TODO(titzer): two conversions
713 input = graph->graph()->NewNode(op, input);
714 op = m->ChangeFloat64ToInt32();
715 break;
716 case wasm::kExprI32UConvertF32:
717 op = m->ChangeFloat32ToFloat64(); // TODO(titzer): two conversions
718 input = graph->graph()->NewNode(op, input);
719 op = m->ChangeFloat64ToUint32();
720 break;
721 case wasm::kExprF64ConvertF32:
722 op = m->ChangeFloat32ToFloat64();
723 break;
724 case wasm::kExprF32ReinterpretI32:
725 op = m->BitcastInt32ToFloat32();
726 break;
727 case wasm::kExprI32ReinterpretF32:
728 op = m->BitcastFloat32ToInt32();
729 break;
730 case wasm::kExprI32Clz:
731 op = m->Word32Clz();
732 break;
733 case wasm::kExprI32Ctz: {
734 if (m->Word32Ctz().IsSupported()) {
735 op = m->Word32Ctz().op();
736 break;
737 } else {
738 return BuildI32Ctz(input);
739 }
740 }
741 case wasm::kExprI32Popcnt: {
742 if (m->Word32Popcnt().IsSupported()) {
743 op = m->Word32Popcnt().op();
744 break;
745 } else {
746 return BuildI32Popcnt(input);
747 }
748 }
749 case wasm::kExprF32Floor: {
750 if (m->Float32RoundDown().IsSupported()) {
751 op = m->Float32RoundDown().op();
752 break;
753 } else {
754 op = UnsupportedOpcode(opcode);
755 break;
756 }
757 }
758 case wasm::kExprF32Ceil: {
759 if (m->Float32RoundUp().IsSupported()) {
760 op = m->Float32RoundUp().op();
761 break;
762 } else {
763 op = UnsupportedOpcode(opcode);
764 break;
765 }
766 }
767 case wasm::kExprF32Trunc: {
768 if (m->Float32RoundTruncate().IsSupported()) {
769 op = m->Float32RoundTruncate().op();
770 break;
771 } else {
772 op = UnsupportedOpcode(opcode);
773 break;
774 }
775 }
776 case wasm::kExprF32NearestInt: {
777 if (m->Float32RoundTiesEven().IsSupported()) {
778 op = m->Float32RoundTiesEven().op();
779 break;
780 } else {
781 op = UnsupportedOpcode(opcode);
782 break;
783 }
784 }
785 case wasm::kExprF64Floor: {
786 if (m->Float64RoundDown().IsSupported()) {
787 op = m->Float64RoundDown().op();
788 break;
789 } else {
790 op = UnsupportedOpcode(opcode);
791 break;
792 }
793 }
794 case wasm::kExprF64Ceil: {
795 if (m->Float64RoundUp().IsSupported()) {
796 op = m->Float64RoundUp().op();
797 break;
798 } else {
799 op = UnsupportedOpcode(opcode);
800 break;
801 }
802 }
803 case wasm::kExprF64Trunc: {
804 if (m->Float64RoundTruncate().IsSupported()) {
805 op = m->Float64RoundTruncate().op();
806 break;
807 } else {
808 op = UnsupportedOpcode(opcode);
809 break;
810 }
811 }
812 case wasm::kExprF64NearestInt: {
813 if (m->Float64RoundTiesEven().IsSupported()) {
814 op = m->Float64RoundTiesEven().op();
815 break;
816 } else {
817 op = UnsupportedOpcode(opcode);
818 break;
819 }
820 }
821
822 #if WASM_64
823 // Opcodes only supported on 64-bit platforms.
824 // TODO(titzer): query the machine operator builder here instead of #ifdef.
825 case wasm::kExprI32ConvertI64:
826 op = m->TruncateInt64ToInt32();
827 break;
828 case wasm::kExprI64SConvertI32:
829 op = m->ChangeInt32ToInt64();
830 break;
831 case wasm::kExprI64UConvertI32:
832 op = m->ChangeUint32ToUint64();
833 break;
834 case wasm::kExprF32SConvertI64:
835 op = m->RoundInt64ToFloat32();
836 break;
837 case wasm::kExprF32UConvertI64:
838 op = m->RoundUint64ToFloat32();
839 break;
840 case wasm::kExprF64SConvertI64:
841 op = m->RoundInt64ToFloat64();
842 break;
843 case wasm::kExprF64UConvertI64:
844 op = m->RoundUint64ToFloat64();
845 break;
846 case wasm::kExprF64ReinterpretI64:
847 op = m->BitcastInt64ToFloat64();
848 break;
849 case wasm::kExprI64ReinterpretF64:
850 op = m->BitcastFloat64ToInt64();
851 break;
852 case wasm::kExprI64Clz:
853 op = m->Word64Clz();
854 break;
855 case wasm::kExprI64Ctz: {
856 if (m->Word64Ctz().IsSupported()) {
857 op = m->Word64Ctz().op();
858 break;
859 } else {
860 return BuildI64Ctz(input);
861 }
862 }
863 case wasm::kExprI64Popcnt: {
864 if (m->Word64Popcnt().IsSupported()) {
865 op = m->Word64Popcnt().op();
866 break;
867 } else {
868 return BuildI64Popcnt(input);
869 }
870 }
871 #endif
872 default:
873 op = UnsupportedOpcode(opcode);
874 }
875 return graph->graph()->NewNode(op, input);
876 }
877
878
879 Node* WasmGraphBuilder::Float32Constant(float value) {
880 DCHECK_NOT_NULL(graph);
881 return graph->Float32Constant(value);
882 }
883
884
885 Node* WasmGraphBuilder::Float64Constant(double value) {
886 DCHECK_NOT_NULL(graph);
887 return graph->Float64Constant(value);
888 }
889
890
891 Node* WasmGraphBuilder::Constant(Handle<Object> value) {
892 DCHECK_NOT_NULL(graph);
893 return graph->Constant(value);
894 }
895
896
897 Node* WasmGraphBuilder::Branch(Node* cond, Node** true_node,
898 Node** false_node) {
899 DCHECK_NOT_NULL(graph);
900 DCHECK_NOT_NULL(cond);
901 DCHECK_NOT_NULL(*control);
902 Node* branch =
903 graph->graph()->NewNode(graph->common()->Branch(), cond, *control);
904 *true_node = graph->graph()->NewNode(graph->common()->IfTrue(), branch);
905 *false_node = graph->graph()->NewNode(graph->common()->IfFalse(), branch);
906 return branch;
907 }
908
909
910 Node* WasmGraphBuilder::Switch(unsigned count, Node* key) {
911 DCHECK_NOT_NULL(graph);
912 return graph->graph()->NewNode(graph->common()->Switch(count), key, *control);
913 }
914
915
916 Node* WasmGraphBuilder::IfValue(int32_t value, Node* sw) {
917 DCHECK_NOT_NULL(graph);
918 DCHECK_EQ(IrOpcode::kSwitch, sw->opcode());
919 return graph->graph()->NewNode(graph->common()->IfValue(value), sw);
920 }
921
922
923 Node* WasmGraphBuilder::IfDefault(Node* sw) {
924 DCHECK_NOT_NULL(graph);
925 DCHECK_EQ(IrOpcode::kSwitch, sw->opcode());
926 return graph->graph()->NewNode(graph->common()->IfDefault(), sw);
927 }
928
929
930 Node* WasmGraphBuilder::Return(unsigned count, Node** vals) {
931 DCHECK_NOT_NULL(graph);
932 DCHECK_NOT_NULL(*control);
933 DCHECK_NOT_NULL(*effect);
934
935 if (count == 0) {
936 // Handle a return of void.
937 vals[0] = graph->Int32Constant(0);
938 count = 1;
939 }
940
941 Graph* g = graph->graph();
942 Node** buf = Realloc(vals, count + 2);
943 buf[count] = *effect;
944 buf[count + 1] = *control;
945 Node* ret = g->NewNode(graph->common()->Return(), count + 2, vals);
946
947 MergeControlToEnd(graph, ret);
948 return ret;
949 }
950
951
952 Node* WasmGraphBuilder::ReturnVoid() { return Return(0, Buffer(0)); }
953
954
955 Node* WasmGraphBuilder::Unreachable() {
956 DCHECK_NOT_NULL(graph);
957 trap->Unreachable();
958 return nullptr;
959 }
960
961
962 Node* WasmGraphBuilder::BuildF32CopySign(Node* left, Node* right) {
963 Node* result = Unop(
964 wasm::kExprF32ReinterpretI32,
965 Binop(wasm::kExprI32Ior,
966 Binop(wasm::kExprI32And, Unop(wasm::kExprI32ReinterpretF32, left),
967 graph->Int32Constant(0x7fffffff)),
968 Binop(wasm::kExprI32And, Unop(wasm::kExprI32ReinterpretF32, right),
969 graph->Int32Constant(0x80000000))));
970
971 return result;
972 }
973
974
975 Node* WasmGraphBuilder::BuildF64CopySign(Node* left, Node* right) {
976 #if WASM_64
977 Node* result = Unop(
978 wasm::kExprF64ReinterpretI64,
979 Binop(wasm::kExprI64Ior,
980 Binop(wasm::kExprI64And, Unop(wasm::kExprI64ReinterpretF64, left),
981 graph->Int64Constant(0x7fffffffffffffff)),
982 Binop(wasm::kExprI64And, Unop(wasm::kExprI64ReinterpretF64, right),
983 graph->Int64Constant(0x8000000000000000))));
984
985 return result;
986 #else
987 MachineOperatorBuilder* m = graph->machine();
988
989 Node* high_word_left =
990 graph->graph()->NewNode(m->Float64ExtractHighWord32(), left);
991 Node* high_word_right =
992 graph->graph()->NewNode(m->Float64ExtractHighWord32(), right);
993
994 Node* new_high_word =
995 Binop(wasm::kExprI32Ior, Binop(wasm::kExprI32And, high_word_left,
996 graph->Int32Constant(0x7fffffff)),
997 Binop(wasm::kExprI32And, high_word_right,
998 graph->Int32Constant(0x80000000)));
999
1000 return graph->graph()->NewNode(m->Float64InsertHighWord32(), left,
1001 new_high_word);
1002 #endif
1003 }
1004
1005
1006 Node* WasmGraphBuilder::BuildI32Ctz(Node* input) {
1007 DCHECK_NOT_NULL(graph);
1008 //// Implement the following code as TF graph.
1009 // value = value | (value << 1);
1010 // value = value | (value << 2);
1011 // value = value | (value << 4);
1012 // value = value | (value << 8);
1013 // value = value | (value << 16);
1014 // return CountPopulation32(0xffffffff XOR value);
1015
1016 Node* result =
1017 Binop(wasm::kExprI32Ior, input,
1018 Binop(wasm::kExprI32Shl, input, graph->Int32Constant(1)));
1019
1020 result = Binop(wasm::kExprI32Ior, result,
1021 Binop(wasm::kExprI32Shl, result, graph->Int32Constant(2)));
1022
1023 result = Binop(wasm::kExprI32Ior, result,
1024 Binop(wasm::kExprI32Shl, result, graph->Int32Constant(4)));
1025
1026 result = Binop(wasm::kExprI32Ior, result,
1027 Binop(wasm::kExprI32Shl, result, graph->Int32Constant(8)));
1028
1029 result = Binop(wasm::kExprI32Ior, result,
1030 Binop(wasm::kExprI32Shl, result, graph->Int32Constant(16)));
1031
1032 result = BuildI32Popcnt(
1033 Binop(wasm::kExprI32Xor, graph->Int32Constant(0xffffffff), result));
1034
1035 return result;
1036 }
1037
1038
1039 Node* WasmGraphBuilder::BuildI64Ctz(Node* input) {
1040 //// Implement the following code as TF graph.
1041 // value = value | (value << 1);
1042 // value = value | (value << 2);
1043 // value = value | (value << 4);
1044 // value = value | (value << 8);
1045 // value = value | (value << 16);
1046 // value = value | (value << 32);
1047 // return CountPopulation64(0xffffffffffffffff XOR value);
1048
1049 Node* result =
1050 Binop(wasm::kExprI64Ior, input,
1051 Binop(wasm::kExprI64Shl, input, graph->Int64Constant(1)));
1052
1053 result = Binop(wasm::kExprI64Ior, result,
1054 Binop(wasm::kExprI64Shl, result, graph->Int64Constant(2)));
1055
1056 result = Binop(wasm::kExprI64Ior, result,
1057 Binop(wasm::kExprI64Shl, result, graph->Int64Constant(4)));
1058
1059 result = Binop(wasm::kExprI64Ior, result,
1060 Binop(wasm::kExprI64Shl, result, graph->Int64Constant(8)));
1061
1062 result = Binop(wasm::kExprI64Ior, result,
1063 Binop(wasm::kExprI64Shl, result, graph->Int64Constant(16)));
1064
1065 result = Binop(wasm::kExprI64Ior, result,
1066 Binop(wasm::kExprI64Shl, result, graph->Int64Constant(32)));
1067
1068 result = BuildI64Popcnt(Binop(
1069 wasm::kExprI64Xor, graph->Int64Constant(0xffffffffffffffff), result));
1070
1071 return result;
1072 }
1073
1074
1075 Node* WasmGraphBuilder::BuildI32Popcnt(Node* input) {
1076 DCHECK_NOT_NULL(graph);
1077 //// Implement the following code as a TF graph.
1078 // value = ((value >> 1) & 0x55555555) + (value & 0x55555555);
1079 // value = ((value >> 2) & 0x33333333) + (value & 0x33333333);
1080 // value = ((value >> 4) & 0x0f0f0f0f) + (value & 0x0f0f0f0f);
1081 // value = ((value >> 8) & 0x00ff00ff) + (value & 0x00ff00ff);
1082 // value = ((value >> 16) & 0x0000ffff) + (value & 0x0000ffff);
1083
1084 Node* result =
1085 Binop(wasm::kExprI32Add,
1086 Binop(wasm::kExprI32And,
1087 Binop(wasm::kExprI32ShrU, input, graph->Int32Constant(1)),
1088 graph->Int32Constant(0x55555555)),
1089 Binop(wasm::kExprI32And, input, graph->Int32Constant(0x55555555)));
1090
1091 result =
1092 Binop(wasm::kExprI32Add,
1093 Binop(wasm::kExprI32And,
1094 Binop(wasm::kExprI32ShrU, result, graph->Int32Constant(2)),
1095 graph->Int32Constant(0x33333333)),
1096 Binop(wasm::kExprI32And, result, graph->Int32Constant(0x33333333)));
1097
1098 result =
1099 Binop(wasm::kExprI32Add,
1100 Binop(wasm::kExprI32And,
1101 Binop(wasm::kExprI32ShrU, result, graph->Int32Constant(4)),
1102 graph->Int32Constant(0x0f0f0f0f)),
1103 Binop(wasm::kExprI32And, result, graph->Int32Constant(0x0f0f0f0f)));
1104
1105 result =
1106 Binop(wasm::kExprI32Add,
1107 Binop(wasm::kExprI32And,
1108 Binop(wasm::kExprI32ShrU, result, graph->Int32Constant(8)),
1109 graph->Int32Constant(0x00ff00ff)),
1110 Binop(wasm::kExprI32And, result, graph->Int32Constant(0x00ff00ff)));
1111
1112 result =
1113 Binop(wasm::kExprI32Add,
1114 Binop(wasm::kExprI32And,
1115 Binop(wasm::kExprI32ShrU, result, graph->Int32Constant(16)),
1116 graph->Int32Constant(0x0000ffff)),
1117 Binop(wasm::kExprI32And, result, graph->Int32Constant(0x0000ffff)));
1118
1119 return result;
1120 }
1121
1122
1123 Node* WasmGraphBuilder::BuildI64Popcnt(Node* input) {
1124 DCHECK_NOT_NULL(graph);
1125 //// Implement the following code as a TF graph.
1126 // value = ((value >> 1) & 0x5555555555555555) + (value & 0x5555555555555555);
1127 // value = ((value >> 2) & 0x3333333333333333) + (value & 0x3333333333333333);
1128 // value = ((value >> 4) & 0x0f0f0f0f0f0f0f0f) + (value & 0x0f0f0f0f0f0f0f0f);
1129 // value = ((value >> 8) & 0x00ff00ff00ff00ff) + (value & 0x00ff00ff00ff00ff);
1130 // value = ((value >> 16) & 0x0000ffff0000ffff) + (value &
1131 // 0x0000ffff0000ffff);
1132 // value = ((value >> 32) & 0x00000000ffffffff) + (value &
1133 // 0x00000000ffffffff);
1134
1135 Node* result = Binop(wasm::kExprI64Add,
1136 Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, input,
1137 graph->Int64Constant(1)),
1138 graph->Int64Constant(0x5555555555555555)),
1139 Binop(wasm::kExprI64And, input,
1140 graph->Int64Constant(0x5555555555555555)));
1141
1142 result = Binop(wasm::kExprI64Add,
1143 Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result,
1144 graph->Int64Constant(2)),
1145 graph->Int64Constant(0x3333333333333333)),
1146 Binop(wasm::kExprI64And, result,
1147 graph->Int64Constant(0x3333333333333333)));
1148
1149 result = Binop(wasm::kExprI64Add,
1150 Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result,
1151 graph->Int64Constant(4)),
1152 graph->Int64Constant(0x0f0f0f0f0f0f0f0f)),
1153 Binop(wasm::kExprI64And, result,
1154 graph->Int64Constant(0x0f0f0f0f0f0f0f0f)));
1155
1156 result = Binop(wasm::kExprI64Add,
1157 Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result,
1158 graph->Int64Constant(8)),
1159 graph->Int64Constant(0x00ff00ff00ff00ff)),
1160 Binop(wasm::kExprI64And, result,
1161 graph->Int64Constant(0x00ff00ff00ff00ff)));
1162
1163 result = Binop(wasm::kExprI64Add,
1164 Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result,
1165 graph->Int64Constant(16)),
1166 graph->Int64Constant(0x0000ffff0000ffff)),
1167 Binop(wasm::kExprI64And, result,
1168 graph->Int64Constant(0x0000ffff0000ffff)));
1169
1170 result = Binop(wasm::kExprI64Add,
1171 Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result,
1172 graph->Int64Constant(32)),
1173 graph->Int64Constant(0x00000000ffffffff)),
1174 Binop(wasm::kExprI64And, result,
1175 graph->Int64Constant(0x00000000ffffffff)));
1176
1177 return result;
1178 }
1179
1180
1181 Node* WasmGraphBuilder::BuildWasmCall(wasm::FunctionSig* sig, Node** args) {
1182 const size_t params = sig->parameter_count();
1183 const size_t extra = 2; // effect and control inputs.
1184 const size_t count = 1 + params + extra;
1185
1186 // Reallocate the buffer to make space for extra inputs.
1187 args = Realloc(args, count);
1188
1189 // Add effect and control inputs.
1190 args[params + 1] = *effect;
1191 args[params + 2] = *control;
1192
1193 const Operator* op =
1194 graph->common()->Call(module->GetWasmCallDescriptor(graph->zone(), sig));
1195 Node* call = graph->graph()->NewNode(op, static_cast<int>(count), args);
1196
1197 *effect = call;
1198 return call;
1199 }
1200
1201
1202 Node* WasmGraphBuilder::CallDirect(uint32_t index, Node** args) {
1203 DCHECK_NOT_NULL(graph);
1204 DCHECK_NULL(args[0]);
1205
1206 // Add code object as constant.
1207 args[0] = Constant(module->GetFunctionCode(index));
1208 wasm::FunctionSig* sig = module->GetFunctionSignature(index);
1209
1210 return BuildWasmCall(sig, args);
1211 }
1212
1213
1214 Node* WasmGraphBuilder::CallIndirect(uint32_t index, Node** args) {
1215 DCHECK_NOT_NULL(graph);
1216 DCHECK_NOT_NULL(args[0]);
1217
1218 Graph* g = graph->graph();
1219 MachineOperatorBuilder* machine = graph->machine();
1220
1221 // Compute the code object by loading it from the function table.
1222 Node* key = args[0];
1223 Node* table = FunctionTable();
1224
1225 // Bounds check the index.
1226 int table_size = static_cast<int>(module->FunctionTableSize());
1227 {
1228 Node* size = Int32Constant(static_cast<int>(table_size));
1229 Node* in_bounds = g->NewNode(machine->Uint32LessThan(), key, size);
1230 trap->AddTrapIfFalse(kTrapFuncInvalid, in_bounds);
1231 }
1232
1233 // Load signature from the table and check.
1234 // The table is a FixedArray; signatures are encoded as SMIs.
1235 // [sig1, sig2, sig3, ...., code1, code2, code3 ...]
1236 ElementAccess access = AccessBuilder::ForFixedArrayElement();
1237 const int fixed_offset = access.header_size - access.tag();
1238 {
1239 Node* load_sig =
1240 g->NewNode(machine->Load(MachineType::AnyTagged()), table,
1241 g->NewNode(machine->Int32Add(),
1242 g->NewNode(machine->Word32Shl(), key,
1243 Int32Constant(kPointerSizeLog2)),
1244 Int32Constant(fixed_offset)),
1245 *effect, *control);
1246 Node* sig_match =
1247 g->NewNode(machine->WordEqual(), load_sig, graph->SmiConstant(index));
1248 trap->AddTrapIfFalse(kTrapFuncSigMismatch, sig_match);
1249 }
1250
1251 // Load code object from the table.
1252 int offset = fixed_offset + kPointerSize * table_size;
1253 Node* load_code =
1254 g->NewNode(machine->Load(MachineType::AnyTagged()), table,
1255 g->NewNode(machine->Int32Add(),
1256 g->NewNode(machine->Word32Shl(), key,
1257 Int32Constant(kPointerSizeLog2)),
1258 Int32Constant(offset)),
1259 *effect, *control);
1260
1261 args[0] = load_code;
1262 wasm::FunctionSig* sig = module->GetSignature(index);
1263 return BuildWasmCall(sig, args);
1264 }
1265
1266
1267 Node* WasmGraphBuilder::ToJS(Node* node, Node* context, wasm::LocalType type) {
1268 DCHECK_NOT_NULL(graph);
1269 Graph* g = graph->graph();
1270 SimplifiedOperatorBuilder simplified(graph->zone());
1271 switch (type) {
1272 case wasm::kAstI32:
1273 return g->NewNode(simplified.ChangeInt32ToTagged(), node);
1274 case wasm::kAstI64:
1275 // TODO(titzer): i64->JS has no good solution right now. Using lower 32
1276 // bits.
1277 node = g->NewNode(graph->machine()->TruncateInt64ToInt32(), node);
1278 return g->NewNode(simplified.ChangeInt32ToTagged(), node);
1279 case wasm::kAstF32:
1280 node = g->NewNode(graph->machine()->ChangeFloat32ToFloat64(), node);
1281 return g->NewNode(simplified.ChangeFloat64ToTagged(), node);
1282 case wasm::kAstF64:
1283 return g->NewNode(simplified.ChangeFloat64ToTagged(), node);
1284 case wasm::kAstStmt:
1285 return graph->UndefinedConstant();
1286 default:
1287 UNREACHABLE();
1288 return nullptr;
1289 }
1290 }
1291
1292
1293 Node* WasmGraphBuilder::FromJS(Node* node, Node* context,
1294 wasm::LocalType type) {
1295 DCHECK_NOT_NULL(graph);
1296 Graph* g = graph->graph();
1297 // Do a JavaScript ToNumber.
1298 Node* num = g->NewNode(graph->javascript()->ToNumber(), node, context,
1299 graph->EmptyFrameState(), *effect, *control);
1300 *control = num;
1301 *effect = num;
1302
1303 // Change representation.
1304 SimplifiedOperatorBuilder simplified(graph->zone());
1305 num = g->NewNode(simplified.ChangeTaggedToFloat64(), num);
1306
1307 switch (type) {
1308 case wasm::kAstI32: {
1309 num = g->NewNode(
1310 graph->machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript),
1311 num);
1312 break;
1313 }
1314 case wasm::kAstI64:
1315 // TODO(titzer): JS->i64 has no good solution right now. Using 32 bits.
1316 num = g->NewNode(
1317 graph->machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript),
1318 num);
1319 num = g->NewNode(graph->machine()->ChangeInt32ToInt64(), num);
1320 break;
1321 case wasm::kAstF32:
1322 num = g->NewNode(graph->machine()->TruncateFloat64ToFloat32(), num);
1323 break;
1324 case wasm::kAstF64:
1325 break;
1326 case wasm::kAstStmt:
1327 num = graph->Int32Constant(0);
1328 break;
1329 default:
1330 UNREACHABLE();
1331 return nullptr;
1332 }
1333 return num;
1334 }
1335
1336
1337 Node* WasmGraphBuilder::Invert(Node* node) {
1338 DCHECK_NOT_NULL(graph);
1339 return Unop(wasm::kExprBoolNot, node);
1340 }
1341
1342
1343 void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code,
1344 wasm::FunctionSig* sig) {
1345 DCHECK_NOT_NULL(graph);
1346
1347 int params = static_cast<int>(sig->parameter_count());
1348 Graph* g = graph->graph();
1349 int count = params + 3;
1350 Node** args = Buffer(count);
1351
1352 // Build the start and the JS parameter nodes.
1353 Node* start = Start(params + 3);
1354 *control = start;
1355 *effect = start;
1356 // JS context is the last parameter.
1357 Node* context =
1358 g->NewNode(graph->common()->Parameter(params + 1, "context"), start);
1359
1360 int pos = 0;
1361 args[pos++] = Constant(wasm_code);
1362
1363 // Convert JS parameters to WASM numbers.
1364 for (int i = 0; i < params; i++) {
1365 Node* param = g->NewNode(graph->common()->Parameter(i), start);
1366 args[pos++] = FromJS(param, context, sig->GetParam(i));
1367 }
1368
1369 args[pos++] = *effect;
1370 args[pos++] = *control;
1371
1372 // Call the WASM code.
1373 CallDescriptor* desc = module->GetWasmCallDescriptor(graph->zone(), sig);
1374 Node* call = g->NewNode(graph->common()->Call(desc), count, args);
1375 Node* jsval =
1376 ToJS(call, context,
1377 sig->return_count() == 0 ? wasm::kAstStmt : sig->GetReturn());
1378 Node* ret = g->NewNode(graph->common()->Return(), jsval, call, start);
1379
1380 MergeControlToEnd(graph, ret);
1381 }
1382
1383
1384 void WasmGraphBuilder::BuildWasmToJSWrapper(Handle<JSFunction> function,
1385 wasm::FunctionSig* sig) {
1386 DCHECK_NOT_NULL(graph);
1387 CHECK_NOT_NULL(graph);
1388 int js_count = function->shared()->internal_formal_parameter_count();
1389 int wasm_count = static_cast<int>(sig->parameter_count());
1390
1391 // Build the start and the parameter nodes.
1392 Isolate* isolate = graph->isolate();
1393 Graph* g = graph->graph();
1394 CallDescriptor* desc;
1395 Node* start = Start(wasm_count + 3);
1396 *effect = start;
1397 *control = start;
1398 // JS context is the last parameter.
1399 Node* context = Constant(Handle<Context>(function->context(), isolate));
1400 Node** args = Buffer(wasm_count + 7);
1401
1402 bool arg_count_before_args = false;
1403 bool add_new_target_undefined = false;
1404
1405 int pos = 0;
1406 if (js_count == wasm_count) {
1407 // exact arity match, just call the function directly.
1408 desc = Linkage::GetJSCallDescriptor(g->zone(), false, wasm_count + 1,
1409 CallDescriptor::kNoFlags);
1410 arg_count_before_args = false;
1411 add_new_target_undefined = true;
1412 } else {
1413 // Use the Call builtin.
1414 Callable callable = CodeFactory::Call(isolate);
1415 args[pos++] = graph->HeapConstant(callable.code());
1416 desc = Linkage::GetStubCallDescriptor(isolate, g->zone(),
1417 callable.descriptor(), wasm_count + 1,
1418 CallDescriptor::kNoFlags);
1419 arg_count_before_args = true;
1420 }
1421
1422 args[pos++] = graph->Constant(function); // JS function.
1423 if (arg_count_before_args) {
1424 args[pos++] = graph->Int32Constant(wasm_count); // argument count
1425 }
1426 args[pos++] = graph->UndefinedConstant(); // JS receiver.
1427
1428 // Convert WASM numbers to JS values.
1429 for (int i = 0; i < wasm_count; i++) {
1430 Node* param = g->NewNode(graph->common()->Parameter(i), start);
1431 args[pos++] = ToJS(param, context, sig->GetParam(i));
1432 }
1433
1434 if (add_new_target_undefined) {
1435 args[pos++] = graph->UndefinedConstant(); // new target
1436 }
1437
1438 if (!arg_count_before_args) {
1439 args[pos++] = graph->Int32Constant(wasm_count); // argument count
1440 }
1441 args[pos++] = context;
1442 args[pos++] = *effect;
1443 args[pos++] = *control;
1444
1445 Node* call = g->NewNode(graph->common()->Call(desc), pos, args);
1446
1447 // Convert the return value back.
1448 Node* val =
1449 FromJS(call, context,
1450 sig->return_count() == 0 ? wasm::kAstStmt : sig->GetReturn());
1451 Node* ret = g->NewNode(graph->common()->Return(), val, call, start);
1452
1453 MergeControlToEnd(graph, ret);
1454 }
1455
1456
1457 Node* WasmGraphBuilder::MemBuffer(uint32_t offset) {
1458 if (!graph) return nullptr;
1459 if (offset == 0) {
1460 if (!mem_buffer) mem_buffer = graph->IntPtrConstant(module->mem_start);
1461 return mem_buffer;
1462 } else {
1463 return graph->IntPtrConstant(module->mem_start + offset);
1464 }
1465 }
1466
1467
1468 Node* WasmGraphBuilder::MemSize(uint32_t offset) {
1469 if (!graph) return nullptr;
1470 int32_t size = static_cast<int>(module->mem_end - module->mem_start);
1471 if (offset == 0) {
1472 if (!mem_size) mem_size = graph->Int32Constant(size);
1473 return mem_size;
1474 } else {
1475 return graph->Int32Constant(size + offset);
1476 }
1477 }
1478
1479
1480 Node* WasmGraphBuilder::FunctionTable() {
1481 if (!graph) return nullptr;
1482 if (!function_table) {
1483 DCHECK(!module->function_table.is_null());
1484 function_table = graph->Constant(module->function_table);
1485 }
1486 return function_table;
1487 }
1488
1489
1490 Node* WasmGraphBuilder::LoadGlobal(uint32_t index) {
1491 DCHECK_NOT_NULL(graph);
1492 MachineType mem_type = module->GetGlobalType(index);
1493 Node* addr = graph->IntPtrConstant(module->globals_area +
1494 module->module->globals->at(index).offset);
1495 const Operator* op = graph->machine()->Load(mem_type);
1496 Node* node = graph->graph()->NewNode(op, addr, graph->Int32Constant(0),
1497 *effect, *control);
1498 *effect = node;
1499 return node;
1500 }
1501
1502
1503 Node* WasmGraphBuilder::StoreGlobal(uint32_t index, Node* val) {
1504 DCHECK_NOT_NULL(graph);
1505 MachineType mem_type = module->GetGlobalType(index);
1506 Node* addr = graph->IntPtrConstant(module->globals_area +
1507 module->module->globals->at(index).offset);
1508 const Operator* op =
1509 graph->machine()->Store(StoreRepresentation(mem_type, kNoWriteBarrier));
1510 Node* node = graph->graph()->NewNode(op, addr, graph->Int32Constant(0), val,
1511 *effect, *control);
1512 *effect = node;
1513 return node;
1514 }
1515
1516
1517 void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index,
1518 uint32_t offset) {
1519 // TODO(turbofan): fold bounds checks for constant indexes.
1520 Graph* g = graph->graph();
1521 CHECK_GE(module->mem_end, module->mem_start);
1522 ptrdiff_t size = module->mem_end - module->mem_start;
1523 byte memsize = wasm::WasmOpcodes::MemSize(memtype);
1524 Node* cond;
1525 if (offset >= size || (offset + memsize) > size) {
1526 // The access will always throw.
1527 cond = graph->Int32Constant(0);
1528 } else {
1529 // Check against the limit.
1530 size_t limit = size - offset - memsize;
1531 CHECK(limit <= kMaxUInt32);
1532 cond = g->NewNode(graph->machine()->Uint32LessThanOrEqual(), index,
1533 graph->Int32Constant(static_cast<uint32_t>(limit)));
1534 }
1535
1536 trap->AddTrapIfFalse(kTrapMemOutOfBounds, cond);
1537 }
1538
1539
1540 Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype,
1541 Node* index, uint32_t offset) {
1542 if (!graph) return nullptr;
1543
1544 Graph* g = graph->graph();
1545 Node* load;
1546
1547 if (module && module->asm_js) {
1548 // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish).
1549 DCHECK_EQ(0, offset);
1550 const Operator* op = graph->machine()->CheckedLoad(memtype);
1551 load = g->NewNode(op, MemBuffer(0), index, MemSize(0), *effect, *control);
1552 } else {
1553 // WASM semantics throw on OOB. Introduce explicit bounds check.
1554 BoundsCheckMem(memtype, index, offset);
1555 load = g->NewNode(graph->machine()->Load(memtype), MemBuffer(offset), index,
1556 *effect, *control);
1557 }
1558
1559 *effect = load;
1560
1561 if (type == wasm::kAstI64 &&
1562 ElementSizeLog2Of(memtype.representation()) < 3) {
1563 // TODO(titzer): TF zeroes the upper bits of 64-bit loads for subword sizes.
1564 if (memtype.IsSigned()) {
1565 // sign extend
1566 load = g->NewNode(graph->machine()->ChangeInt32ToInt64(), load);
1567 } else {
1568 // zero extend
1569 load = g->NewNode(graph->machine()->ChangeUint32ToUint64(), load);
1570 }
1571 }
1572
1573 return load;
1574 }
1575
1576
1577 Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index,
1578 uint32_t offset, Node* val) {
1579 if (!graph) return nullptr;
1580
1581 Node* store;
1582 if (module && module->asm_js) {
1583 // asm.js semantics use CheckedStore (i.e. ignore OOB writes).
1584 DCHECK_EQ(0, offset);
1585 const Operator* op = graph->machine()->CheckedStore(memtype);
1586 store = graph->graph()->NewNode(op, MemBuffer(0), index, MemSize(0), val,
1587 *effect, *control);
1588 } else {
1589 // WASM semantics throw on OOB. Introduce explicit bounds check.
1590 BoundsCheckMem(memtype, index, offset);
1591 StoreRepresentation rep(memtype, kNoWriteBarrier);
1592 store =
1593 graph->graph()->NewNode(graph->machine()->Store(rep), MemBuffer(offset),
1594 index, val, *effect, *control);
1595 }
1596 *effect = store;
1597 return store;
1598 }
1599
1600
1601 void WasmGraphBuilder::PrintDebugName(Node* node) {
1602 PrintF("#%d:%s", node->id(), node->op()->mnemonic());
1603 }
1604
1605
1606 Node* WasmGraphBuilder::String(const char* string) {
1607 DCHECK_NOT_NULL(graph);
1608 return graph->Constant(
1609 graph->isolate()->factory()->NewStringFromAsciiChecked(string));
1610 }
1611
1612
1613 Handle<JSFunction> CompileJSToWasmWrapper(Isolate* isolate,
1614 wasm::ModuleEnv* module,
1615 Handle<String> name,
1616 Handle<Code> wasm_code,
1617 uint32_t index) {
1618 wasm::WasmFunction* func = &module->module->functions->at(index);
1619
1620 //----------------------------------------------------------------------------
1621 // Create the JSFunction object.
1622 //----------------------------------------------------------------------------
1623 Handle<SharedFunctionInfo> shared =
1624 isolate->factory()->NewSharedFunctionInfo(name, wasm_code, false);
1625 int params = static_cast<int>(func->sig->parameter_count());
1626 shared->set_length(params);
1627 shared->set_internal_formal_parameter_count(1 + params);
1628 Handle<JSFunction> function = isolate->factory()->NewFunction(name);
1629 function->set_shared(*shared);
1630
1631 //----------------------------------------------------------------------------
1632 // Create the Graph
1633 //----------------------------------------------------------------------------
1634 Zone zone;
1635 Graph graph(&zone);
1636 CommonOperatorBuilder common(&zone);
1637 JSOperatorBuilder javascript(&zone);
1638 MachineOperatorBuilder machine(&zone);
1639 JSGraph jsgraph(isolate, &graph, &common, &javascript, nullptr, &machine);
1640
1641 Node* control = nullptr;
1642 Node* effect = nullptr;
1643
1644 WasmGraphBuilder builder(&zone, &jsgraph);
1645 builder.set_control_ptr(&control);
1646 builder.set_effect_ptr(&effect);
1647 builder.set_module(module);
1648 builder.BuildJSToWasmWrapper(wasm_code, func->sig);
1649
1650 //----------------------------------------------------------------------------
1651 // Run the compilation pipeline.
1652 //----------------------------------------------------------------------------
1653 {
1654 // Changes lowering requires types.
1655 Typer typer(isolate, &graph);
1656 NodeVector roots(&zone);
1657 jsgraph.GetCachedNodes(&roots);
1658 typer.Run(roots);
1659
1660 // Run generic and change lowering.
1661 JSGenericLowering generic(true, &jsgraph);
1662 ChangeLowering changes(&jsgraph);
1663 GraphReducer graph_reducer(&zone, &graph, jsgraph.Dead());
1664 graph_reducer.AddReducer(&changes);
1665 graph_reducer.AddReducer(&generic);
1666 graph_reducer.ReduceGraph();
1667
1668 if (FLAG_trace_turbo_graph) { // Simple textual RPO.
1669 OFStream os(stdout);
1670 os << "-- Graph after change lowering -- " << std::endl;
1671 os << AsRPO(graph);
1672 }
1673
1674 // Schedule and compile to machine code.
1675 int params = static_cast<int>(
1676 module->GetFunctionSignature(index)->parameter_count());
1677 CallDescriptor* incoming = Linkage::GetJSCallDescriptor(
1678 &zone, false, params + 1, CallDescriptor::kNoFlags);
1679 CompilationInfo info("js-to-wasm", isolate, &zone);
1680 // TODO(titzer): this is technically a WASM wrapper, not a wasm function.
1681 info.set_output_code_kind(Code::WASM_FUNCTION);
1682 Handle<Code> code =
1683 Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr);
1684
1685 #ifdef ENABLE_DISASSEMBLER
1686 // Disassemble the wrapper code for debugging.
1687 if (!code.is_null() && FLAG_print_opt_code) {
1688 static const int kBufferSize = 128;
1689 char buffer[kBufferSize];
1690 const char* name = "";
1691 if (func->name_offset > 0) {
1692 const byte* ptr = module->module->module_start + func->name_offset;
1693 name = reinterpret_cast<const char*>(ptr);
1694 }
1695 snprintf(buffer, kBufferSize, "JS->WASM function wrapper #%d:%s", index,
1696 name);
1697 OFStream os(stdout);
1698 code->Disassemble(buffer, os);
1699 }
1700 #endif
1701 // Set the JSFunction's machine code.
1702 function->set_code(*code);
1703 }
1704 return function;
1705 }
1706
1707
1708 Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, wasm::ModuleEnv* module,
1709 Handle<JSFunction> function,
1710 uint32_t index) {
1711 wasm::WasmFunction* func = &module->module->functions->at(index);
1712
1713 //----------------------------------------------------------------------------
1714 // Create the Graph
1715 //----------------------------------------------------------------------------
1716 Zone zone;
1717 Graph graph(&zone);
1718 CommonOperatorBuilder common(&zone);
1719 JSOperatorBuilder javascript(&zone);
1720 MachineOperatorBuilder machine(&zone);
1721 JSGraph jsgraph(isolate, &graph, &common, &javascript, nullptr, &machine);
1722
1723 Node* control = nullptr;
1724 Node* effect = nullptr;
1725
1726 WasmGraphBuilder builder(&zone, &jsgraph);
1727 builder.set_control_ptr(&control);
1728 builder.set_effect_ptr(&effect);
1729 builder.set_module(module);
1730 builder.BuildWasmToJSWrapper(function, func->sig);
1731
1732 Handle<Code> code = Handle<Code>::null();
1733 {
1734 // Changes lowering requires types.
1735 Typer typer(isolate, &graph);
1736 NodeVector roots(&zone);
1737 jsgraph.GetCachedNodes(&roots);
1738 typer.Run(roots);
1739
1740 // Run generic and change lowering.
1741 JSGenericLowering generic(true, &jsgraph);
1742 ChangeLowering changes(&jsgraph);
1743 GraphReducer graph_reducer(&zone, &graph, jsgraph.Dead());
1744 graph_reducer.AddReducer(&changes);
1745 graph_reducer.AddReducer(&generic);
1746 graph_reducer.ReduceGraph();
1747
1748 if (FLAG_trace_turbo_graph) { // Simple textual RPO.
1749 OFStream os(stdout);
1750 os << "-- Graph after change lowering -- " << std::endl;
1751 os << AsRPO(graph);
1752 }
1753
1754 // Schedule and compile to machine code.
1755 CallDescriptor* incoming = module->GetWasmCallDescriptor(&zone, func->sig);
1756 CompilationInfo info("wasm-to-js", isolate, &zone);
1757 // TODO(titzer): this is technically a WASM wrapper, not a wasm function.
1758 info.set_output_code_kind(Code::WASM_FUNCTION);
1759 code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr);
1760
1761 #ifdef ENABLE_DISASSEMBLER
1762 // Disassemble the wrapper code for debugging.
1763 if (!code.is_null() && FLAG_print_opt_code) {
1764 static const int kBufferSize = 128;
1765 char buffer[kBufferSize];
1766 const char* name = "";
1767 if (func->name_offset > 0) {
1768 const byte* ptr = module->module->module_start + func->name_offset;
1769 name = reinterpret_cast<const char*>(ptr);
1770 }
1771 snprintf(buffer, kBufferSize, "WASM->JS function wrapper #%d:%s", index,
1772 name);
1773 OFStream os(stdout);
1774 code->Disassemble(buffer, os);
1775 }
1776 #endif
1777 }
1778 return code;
1779 }
1780
1781
1782 // Helper function to compile a single function.
1783 Handle<Code> CompileWasmFunction(wasm::ErrorThrower& thrower, Isolate* isolate,
1784 wasm::ModuleEnv* module_env,
1785 const wasm::WasmFunction& function,
1786 int index) {
1787 if (FLAG_trace_wasm_compiler || FLAG_trace_wasm_decode_time) {
1788 // TODO(titzer): clean me up a bit.
1789 OFStream os(stdout);
1790 os << "Compiling WASM function #" << index << ":";
1791 if (function.name_offset > 0) {
1792 os << module_env->module->GetName(function.name_offset);
1793 }
1794 os << std::endl;
1795 }
1796 // Initialize the function environment for decoding.
1797 wasm::FunctionEnv env;
1798 env.module = module_env;
1799 env.sig = function.sig;
1800 env.local_int32_count = function.local_int32_count;
1801 env.local_int64_count = function.local_int64_count;
1802 env.local_float32_count = function.local_float32_count;
1803 env.local_float64_count = function.local_float64_count;
1804 env.SumLocals();
1805
1806 // Create a TF graph during decoding.
1807 Zone zone;
1808 Graph graph(&zone);
1809 CommonOperatorBuilder common(&zone);
1810 MachineOperatorBuilder machine(
1811 &zone, MachineType::PointerRepresentation(),
1812 InstructionSelector::SupportedMachineOperatorFlags());
1813 JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
1814 WasmGraphBuilder builder(&zone, &jsgraph);
1815 wasm::TreeResult result = wasm::BuildTFGraph(
1816 &builder, &env, // --
1817 module_env->module->module_start, // --
1818 module_env->module->module_start + function.code_start_offset, // --
1819 module_env->module->module_start + function.code_end_offset); // --
1820
1821 if (result.failed()) {
1822 if (FLAG_trace_wasm_compiler) {
1823 OFStream os(stdout);
1824 os << "Compilation failed: " << result << std::endl;
1825 }
1826 // Add the function as another context for the exception
1827 const int kBufSize = 256;
1828 char buffer[kBufSize];
1829 snprintf(buffer, kBufSize, "Compiling WASM function #%d:%s failed:", index,
1830 module_env->module->GetName(function.name_offset));
1831 thrower.Failed(buffer, result);
1832 return Handle<Code>::null();
1833 }
1834
1835 // Run the compiler pipeline to generate machine code.
1836 CallDescriptor* descriptor = const_cast<CallDescriptor*>(
1837 module_env->GetWasmCallDescriptor(&zone, function.sig));
1838 CompilationInfo info("wasm", isolate, &zone);
1839 info.set_output_code_kind(Code::WASM_FUNCTION);
1840 Handle<Code> code =
1841 Pipeline::GenerateCodeForTesting(&info, descriptor, &graph);
1842
1843 #ifdef ENABLE_DISASSEMBLER
1844 // Disassemble the code for debugging.
1845 if (!code.is_null() && FLAG_print_opt_code) {
1846 static const int kBufferSize = 128;
1847 char buffer[kBufferSize];
1848 const char* name = "";
1849 if (function.name_offset > 0) {
1850 const byte* ptr = module_env->module->module_start + function.name_offset;
1851 name = reinterpret_cast<const char*>(ptr);
1852 }
1853 snprintf(buffer, kBufferSize, "WASM function #%d:%s", index, name);
1854 OFStream os(stdout);
1855 code->Disassemble(buffer, os);
1856 }
1857 #endif
1858 return code;
1859 }
1860 } // namespace compiler
1861 } // namespace internal
1862 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698