blob: 619e639e1509a2a73e2e0908bd397869838c08f4 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/compiler/wasm-compiler.h"
6
7#include "src/isolate-inl.h"
8
Ben Murdochda12d292016-06-02 14:46:10 +01009#include "src/base/platform/elapsed-timer.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010#include "src/base/platform/platform.h"
11
12#include "src/compiler/access-builder.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013#include "src/compiler/common-operator.h"
14#include "src/compiler/diamond.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015#include "src/compiler/graph-visualizer.h"
Ben Murdochc5610432016-08-08 18:44:38 +010016#include "src/compiler/graph.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017#include "src/compiler/instruction-selector.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010018#include "src/compiler/int64-lowering.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019#include "src/compiler/js-generic-lowering.h"
20#include "src/compiler/js-graph.h"
21#include "src/compiler/js-operator.h"
22#include "src/compiler/linkage.h"
23#include "src/compiler/machine-operator.h"
24#include "src/compiler/node-matchers.h"
25#include "src/compiler/pipeline.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000026#include "src/compiler/source-position.h"
Ben Murdochc5610432016-08-08 18:44:38 +010027#include "src/compiler/zone-pool.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000028
29#include "src/code-factory.h"
30#include "src/code-stubs.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010031#include "src/factory.h"
32#include "src/log-inl.h"
33#include "src/profiler/cpu-profiler.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000034
35#include "src/wasm/ast-decoder.h"
36#include "src/wasm/wasm-module.h"
37#include "src/wasm/wasm-opcodes.h"
38
39// TODO(titzer): pull WASM_64 up to a common header.
40#if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64
41#define WASM_64 1
42#else
43#define WASM_64 0
44#endif
45
46namespace v8 {
47namespace internal {
48namespace compiler {
49
50namespace {
51const Operator* UnsupportedOpcode(wasm::WasmOpcode opcode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000052 V8_Fatal(__FILE__, __LINE__, "Unsupported opcode #%d:%s", opcode,
53 wasm::WasmOpcodes::OpcodeName(opcode));
54 return nullptr;
55}
56
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000057void MergeControlToEnd(JSGraph* jsgraph, Node* node) {
58 Graph* g = jsgraph->graph();
59 if (g->end()) {
60 NodeProperties::MergeControlToEnd(g, jsgraph->common(), node);
61 } else {
62 g->SetEnd(g->NewNode(jsgraph->common()->End(1), node));
63 }
64}
65
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000066} // namespace
67
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000068// A helper that handles building graph fragments for trapping.
69// To avoid generating a ton of redundant code that just calls the runtime
70// to trap, we generate a per-trap-reason block of code that all trap sites
71// in this function will branch to.
72class WasmTrapHelper : public ZoneObject {
73 public:
74 explicit WasmTrapHelper(WasmGraphBuilder* builder)
75 : builder_(builder),
76 jsgraph_(builder->jsgraph()),
Ben Murdochc5610432016-08-08 18:44:38 +010077 graph_(builder->jsgraph() ? builder->jsgraph()->graph() : nullptr) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000078
79 // Make the current control path trap to unreachable.
Ben Murdochc5610432016-08-08 18:44:38 +010080 void Unreachable(wasm::WasmCodePosition position) {
81 ConnectTrap(wasm::kTrapUnreachable, position);
82 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000083
Ben Murdoch097c5b22016-05-18 11:27:45 +010084 // Always trap with the given reason.
Ben Murdochc5610432016-08-08 18:44:38 +010085 void TrapAlways(wasm::TrapReason reason, wasm::WasmCodePosition position) {
86 ConnectTrap(reason, position);
87 }
Ben Murdoch097c5b22016-05-18 11:27:45 +010088
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000089 // Add a check that traps if {node} is equal to {val}.
Ben Murdochc5610432016-08-08 18:44:38 +010090 Node* TrapIfEq32(wasm::TrapReason reason, Node* node, int32_t val,
91 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000092 Int32Matcher m(node);
93 if (m.HasValue() && !m.Is(val)) return graph()->start();
94 if (val == 0) {
Ben Murdochc5610432016-08-08 18:44:38 +010095 AddTrapIfFalse(reason, node, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000096 } else {
97 AddTrapIfTrue(reason,
98 graph()->NewNode(jsgraph()->machine()->Word32Equal(), node,
Ben Murdochc5610432016-08-08 18:44:38 +010099 jsgraph()->Int32Constant(val)),
100 position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000101 }
102 return builder_->Control();
103 }
104
105 // Add a check that traps if {node} is zero.
Ben Murdochc5610432016-08-08 18:44:38 +0100106 Node* ZeroCheck32(wasm::TrapReason reason, Node* node,
107 wasm::WasmCodePosition position) {
108 return TrapIfEq32(reason, node, 0, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000109 }
110
111 // Add a check that traps if {node} is equal to {val}.
Ben Murdochc5610432016-08-08 18:44:38 +0100112 Node* TrapIfEq64(wasm::TrapReason reason, Node* node, int64_t val,
113 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000114 Int64Matcher m(node);
115 if (m.HasValue() && !m.Is(val)) return graph()->start();
Ben Murdochc5610432016-08-08 18:44:38 +0100116 AddTrapIfTrue(reason, graph()->NewNode(jsgraph()->machine()->Word64Equal(),
117 node, jsgraph()->Int64Constant(val)),
118 position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000119 return builder_->Control();
120 }
121
122 // Add a check that traps if {node} is zero.
Ben Murdochc5610432016-08-08 18:44:38 +0100123 Node* ZeroCheck64(wasm::TrapReason reason, Node* node,
124 wasm::WasmCodePosition position) {
125 return TrapIfEq64(reason, node, 0, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000126 }
127
128 // Add a trap if {cond} is true.
Ben Murdochc5610432016-08-08 18:44:38 +0100129 void AddTrapIfTrue(wasm::TrapReason reason, Node* cond,
130 wasm::WasmCodePosition position) {
131 AddTrapIf(reason, cond, true, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000132 }
133
134 // Add a trap if {cond} is false.
Ben Murdochc5610432016-08-08 18:44:38 +0100135 void AddTrapIfFalse(wasm::TrapReason reason, Node* cond,
136 wasm::WasmCodePosition position) {
137 AddTrapIf(reason, cond, false, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000138 }
139
140 // Add a trap if {cond} is true or false according to {iftrue}.
Ben Murdochc5610432016-08-08 18:44:38 +0100141 void AddTrapIf(wasm::TrapReason reason, Node* cond, bool iftrue,
142 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000143 Node** effect_ptr = builder_->effect_;
144 Node** control_ptr = builder_->control_;
145 Node* before = *effect_ptr;
146 BranchHint hint = iftrue ? BranchHint::kFalse : BranchHint::kTrue;
147 Node* branch = graph()->NewNode(common()->Branch(hint), cond, *control_ptr);
148 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
149 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
150
151 *control_ptr = iftrue ? if_true : if_false;
Ben Murdochc5610432016-08-08 18:44:38 +0100152 ConnectTrap(reason, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000153 *control_ptr = iftrue ? if_false : if_true;
154 *effect_ptr = before;
155 }
156
Ben Murdoch097c5b22016-05-18 11:27:45 +0100157 Node* GetTrapValue(wasm::FunctionSig* sig) {
158 if (sig->return_count() > 0) {
159 switch (sig->GetReturn()) {
160 case wasm::kAstI32:
161 return jsgraph()->Int32Constant(0xdeadbeef);
162 case wasm::kAstI64:
163 return jsgraph()->Int64Constant(0xdeadbeefdeadbeef);
164 case wasm::kAstF32:
165 return jsgraph()->Float32Constant(bit_cast<float>(0xdeadbeef));
166 case wasm::kAstF64:
167 return jsgraph()->Float64Constant(
168 bit_cast<double>(0xdeadbeefdeadbeef));
169 break;
170 default:
171 UNREACHABLE();
172 return nullptr;
173 }
174 } else {
175 return jsgraph()->Int32Constant(0xdeadbeef);
176 }
177 }
178
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000179 private:
180 WasmGraphBuilder* builder_;
181 JSGraph* jsgraph_;
182 Graph* graph_;
Ben Murdochc5610432016-08-08 18:44:38 +0100183 Node* trap_merge_ = nullptr;
184 Node* trap_effect_;
185 Node* trap_reason_;
186 Node* trap_position_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000187
188 JSGraph* jsgraph() { return jsgraph_; }
189 Graph* graph() { return jsgraph_->graph(); }
190 CommonOperatorBuilder* common() { return jsgraph()->common(); }
191
Ben Murdochc5610432016-08-08 18:44:38 +0100192 void ConnectTrap(wasm::TrapReason reason, wasm::WasmCodePosition position) {
193 DCHECK(position != wasm::kNoCodePosition);
194 Node* reason_node = builder_->Int32Constant(
195 wasm::WasmOpcodes::TrapReasonToMessageId(reason));
196 Node* position_node = builder_->Int32Constant(position);
197 if (trap_merge_ == nullptr) {
198 // Create trap code for the first time.
199 return BuildTrapCode(reason_node, position_node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000200 }
201 // Connect the current control and effect to the existing trap code.
Ben Murdochc5610432016-08-08 18:44:38 +0100202 builder_->AppendToMerge(trap_merge_, builder_->Control());
203 builder_->AppendToPhi(trap_effect_, builder_->Effect());
204 builder_->AppendToPhi(trap_reason_, reason_node);
205 builder_->AppendToPhi(trap_position_, position_node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000206 }
207
Ben Murdochc5610432016-08-08 18:44:38 +0100208 void BuildTrapCode(Node* reason_node, Node* position_node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000209 Node* end;
210 Node** control_ptr = builder_->control_;
211 Node** effect_ptr = builder_->effect_;
212 wasm::ModuleEnv* module = builder_->module_;
Ben Murdochc5610432016-08-08 18:44:38 +0100213 DCHECK(trap_merge_ == NULL);
214 *control_ptr = trap_merge_ =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000215 graph()->NewNode(common()->Merge(1), *control_ptr);
Ben Murdochc5610432016-08-08 18:44:38 +0100216 *effect_ptr = trap_effect_ =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000217 graph()->NewNode(common()->EffectPhi(1), *effect_ptr, *control_ptr);
Ben Murdochc5610432016-08-08 18:44:38 +0100218 trap_reason_ =
219 graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 1),
220 reason_node, *control_ptr);
221 trap_position_ =
222 graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 1),
223 position_node, *control_ptr);
224
225 Node* trap_reason_smi = builder_->BuildChangeInt32ToSmi(trap_reason_);
226 Node* trap_position_smi = builder_->BuildChangeInt32ToSmi(trap_position_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000227
Ben Murdoch097c5b22016-05-18 11:27:45 +0100228 if (module && !module->instance->context.is_null()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000229 // Use the module context to call the runtime to throw an exception.
Ben Murdochc5610432016-08-08 18:44:38 +0100230 Runtime::FunctionId f = Runtime::kThrowWasmError;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000231 const Runtime::Function* fun = Runtime::FunctionForId(f);
232 CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
233 jsgraph()->zone(), f, fun->nargs, Operator::kNoProperties,
234 CallDescriptor::kNoFlags);
Ben Murdochc5610432016-08-08 18:44:38 +0100235 // CEntryStubConstant nodes have to be created and cached in the main
236 // thread. At the moment this is only done for CEntryStubConstant(1).
237 DCHECK_EQ(1, fun->result_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000238 Node* inputs[] = {
239 jsgraph()->CEntryStubConstant(fun->result_size), // C entry
Ben Murdochc5610432016-08-08 18:44:38 +0100240 trap_reason_smi, // message id
241 trap_position_smi, // byte position
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000242 jsgraph()->ExternalConstant(
Ben Murdochc5610432016-08-08 18:44:38 +0100243 ExternalReference(f, jsgraph()->isolate())), // ref
244 jsgraph()->Int32Constant(fun->nargs), // arity
245 builder_->HeapConstant(module->instance->context), // context
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000246 *effect_ptr,
247 *control_ptr};
248
249 Node* node = graph()->NewNode(
250 common()->Call(desc), static_cast<int>(arraysize(inputs)), inputs);
251 *control_ptr = node;
252 *effect_ptr = node;
253 }
254 if (false) {
255 // End the control flow with a throw
256 Node* thrw =
257 graph()->NewNode(common()->Throw(), jsgraph()->ZeroConstant(),
258 *effect_ptr, *control_ptr);
259 end = thrw;
260 } else {
261 // End the control flow with returning 0xdeadbeef
Ben Murdoch097c5b22016-05-18 11:27:45 +0100262 Node* ret_value = GetTrapValue(builder_->GetFunctionSignature());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000263 end = graph()->NewNode(jsgraph()->common()->Return(), ret_value,
264 *effect_ptr, *control_ptr);
265 }
266
267 MergeControlToEnd(jsgraph(), end);
268 }
269};
270
Ben Murdochc5610432016-08-08 18:44:38 +0100271WasmGraphBuilder::WasmGraphBuilder(
272 Zone* zone, JSGraph* jsgraph, wasm::FunctionSig* function_signature,
273 compiler::SourcePositionTable* source_position_table)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000274 : zone_(zone),
275 jsgraph_(jsgraph),
276 module_(nullptr),
277 mem_buffer_(nullptr),
278 mem_size_(nullptr),
279 function_table_(nullptr),
280 control_(nullptr),
281 effect_(nullptr),
282 cur_buffer_(def_buffer_),
283 cur_bufsize_(kDefaultBufferSize),
284 trap_(new (zone) WasmTrapHelper(this)),
Ben Murdochc5610432016-08-08 18:44:38 +0100285 function_signature_(function_signature),
286 source_position_table_(source_position_table) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000287 DCHECK_NOT_NULL(jsgraph_);
288}
289
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000290Node* WasmGraphBuilder::Error() { return jsgraph()->Dead(); }
291
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000292Node* WasmGraphBuilder::Start(unsigned params) {
293 Node* start = graph()->NewNode(jsgraph()->common()->Start(params));
294 graph()->SetStart(start);
295 return start;
296}
297
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000298Node* WasmGraphBuilder::Param(unsigned index, wasm::LocalType type) {
299 return graph()->NewNode(jsgraph()->common()->Parameter(index),
300 graph()->start());
301}
302
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000303Node* WasmGraphBuilder::Loop(Node* entry) {
304 return graph()->NewNode(jsgraph()->common()->Loop(1), entry);
305}
306
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000307Node* WasmGraphBuilder::Terminate(Node* effect, Node* control) {
308 Node* terminate =
309 graph()->NewNode(jsgraph()->common()->Terminate(), effect, control);
310 MergeControlToEnd(jsgraph(), terminate);
311 return terminate;
312}
313
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000314unsigned WasmGraphBuilder::InputCount(Node* node) {
315 return static_cast<unsigned>(node->InputCount());
316}
317
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000318bool WasmGraphBuilder::IsPhiWithMerge(Node* phi, Node* merge) {
319 return phi && IrOpcode::IsPhiOpcode(phi->opcode()) &&
320 NodeProperties::GetControlInput(phi) == merge;
321}
322
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000323void WasmGraphBuilder::AppendToMerge(Node* merge, Node* from) {
324 DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
325 merge->AppendInput(jsgraph()->zone(), from);
326 int new_size = merge->InputCount();
327 NodeProperties::ChangeOp(
328 merge, jsgraph()->common()->ResizeMergeOrPhi(merge->op(), new_size));
329}
330
Ben Murdochc5610432016-08-08 18:44:38 +0100331void WasmGraphBuilder::AppendToPhi(Node* phi, Node* from) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000332 DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000333 int new_size = phi->InputCount();
334 phi->InsertInput(jsgraph()->zone(), phi->InputCount() - 1, from);
335 NodeProperties::ChangeOp(
336 phi, jsgraph()->common()->ResizeMergeOrPhi(phi->op(), new_size));
337}
338
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000339Node* WasmGraphBuilder::Merge(unsigned count, Node** controls) {
340 return graph()->NewNode(jsgraph()->common()->Merge(count), count, controls);
341}
342
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000343Node* WasmGraphBuilder::Phi(wasm::LocalType type, unsigned count, Node** vals,
344 Node* control) {
345 DCHECK(IrOpcode::IsMergeOpcode(control->opcode()));
Ben Murdochda12d292016-06-02 14:46:10 +0100346 Node** buf = Realloc(vals, count, count + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000347 buf[count] = control;
348 return graph()->NewNode(jsgraph()->common()->Phi(type, count), count + 1,
349 buf);
350}
351
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000352Node* WasmGraphBuilder::EffectPhi(unsigned count, Node** effects,
353 Node* control) {
354 DCHECK(IrOpcode::IsMergeOpcode(control->opcode()));
Ben Murdochda12d292016-06-02 14:46:10 +0100355 Node** buf = Realloc(effects, count, count + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000356 buf[count] = control;
357 return graph()->NewNode(jsgraph()->common()->EffectPhi(count), count + 1,
358 buf);
359}
360
Ben Murdochc5610432016-08-08 18:44:38 +0100361Node* WasmGraphBuilder::NumberConstant(int32_t value) {
362 return jsgraph()->Constant(value);
363}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000364
365Node* WasmGraphBuilder::Int32Constant(int32_t value) {
366 return jsgraph()->Int32Constant(value);
367}
368
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000369Node* WasmGraphBuilder::Int64Constant(int64_t value) {
370 return jsgraph()->Int64Constant(value);
371}
372
Ben Murdochc5610432016-08-08 18:44:38 +0100373Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left, Node* right,
374 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000375 const Operator* op;
376 MachineOperatorBuilder* m = jsgraph()->machine();
377 switch (opcode) {
378 case wasm::kExprI32Add:
379 op = m->Int32Add();
380 break;
381 case wasm::kExprI32Sub:
382 op = m->Int32Sub();
383 break;
384 case wasm::kExprI32Mul:
385 op = m->Int32Mul();
386 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100387 case wasm::kExprI32DivS:
Ben Murdochc5610432016-08-08 18:44:38 +0100388 return BuildI32DivS(left, right, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000389 case wasm::kExprI32DivU:
Ben Murdochc5610432016-08-08 18:44:38 +0100390 return BuildI32DivU(left, right, position);
Ben Murdochda12d292016-06-02 14:46:10 +0100391 case wasm::kExprI32RemS:
Ben Murdochc5610432016-08-08 18:44:38 +0100392 return BuildI32RemS(left, right, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000393 case wasm::kExprI32RemU:
Ben Murdochc5610432016-08-08 18:44:38 +0100394 return BuildI32RemU(left, right, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000395 case wasm::kExprI32And:
396 op = m->Word32And();
397 break;
398 case wasm::kExprI32Ior:
399 op = m->Word32Or();
400 break;
401 case wasm::kExprI32Xor:
402 op = m->Word32Xor();
403 break;
404 case wasm::kExprI32Shl:
405 op = m->Word32Shl();
Ben Murdochda12d292016-06-02 14:46:10 +0100406 right = MaskShiftCount32(right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000407 break;
408 case wasm::kExprI32ShrU:
409 op = m->Word32Shr();
Ben Murdochda12d292016-06-02 14:46:10 +0100410 right = MaskShiftCount32(right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000411 break;
412 case wasm::kExprI32ShrS:
413 op = m->Word32Sar();
Ben Murdochda12d292016-06-02 14:46:10 +0100414 right = MaskShiftCount32(right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000415 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100416 case wasm::kExprI32Ror:
417 op = m->Word32Ror();
418 right = MaskShiftCount32(right);
419 break;
420 case wasm::kExprI32Rol:
421 right = MaskShiftCount32(right);
422 return BuildI32Rol(left, right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000423 case wasm::kExprI32Eq:
424 op = m->Word32Equal();
425 break;
426 case wasm::kExprI32Ne:
427 return Invert(Binop(wasm::kExprI32Eq, left, right));
428 case wasm::kExprI32LtS:
429 op = m->Int32LessThan();
430 break;
431 case wasm::kExprI32LeS:
432 op = m->Int32LessThanOrEqual();
433 break;
434 case wasm::kExprI32LtU:
435 op = m->Uint32LessThan();
436 break;
437 case wasm::kExprI32LeU:
438 op = m->Uint32LessThanOrEqual();
439 break;
440 case wasm::kExprI32GtS:
441 op = m->Int32LessThan();
442 std::swap(left, right);
443 break;
444 case wasm::kExprI32GeS:
445 op = m->Int32LessThanOrEqual();
446 std::swap(left, right);
447 break;
448 case wasm::kExprI32GtU:
449 op = m->Uint32LessThan();
450 std::swap(left, right);
451 break;
452 case wasm::kExprI32GeU:
453 op = m->Uint32LessThanOrEqual();
454 std::swap(left, right);
455 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100456 case wasm::kExprI64And:
457 op = m->Word64And();
458 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000459 case wasm::kExprI64Add:
460 op = m->Int64Add();
461 break;
462 case wasm::kExprI64Sub:
463 op = m->Int64Sub();
464 break;
465 case wasm::kExprI64Mul:
466 op = m->Int64Mul();
467 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100468 case wasm::kExprI64DivS:
Ben Murdochc5610432016-08-08 18:44:38 +0100469 return BuildI64DivS(left, right, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000470 case wasm::kExprI64DivU:
Ben Murdochc5610432016-08-08 18:44:38 +0100471 return BuildI64DivU(left, right, position);
Ben Murdochda12d292016-06-02 14:46:10 +0100472 case wasm::kExprI64RemS:
Ben Murdochc5610432016-08-08 18:44:38 +0100473 return BuildI64RemS(left, right, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000474 case wasm::kExprI64RemU:
Ben Murdochc5610432016-08-08 18:44:38 +0100475 return BuildI64RemU(left, right, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000476 case wasm::kExprI64Ior:
477 op = m->Word64Or();
478 break;
479 case wasm::kExprI64Xor:
480 op = m->Word64Xor();
481 break;
482 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;
486 case wasm::kExprI64ShrU:
487 op = m->Word64Shr();
Ben Murdochda12d292016-06-02 14:46:10 +0100488 right = MaskShiftCount64(right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000489 break;
490 case wasm::kExprI64ShrS:
491 op = m->Word64Sar();
Ben Murdochda12d292016-06-02 14:46:10 +0100492 right = MaskShiftCount64(right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000493 break;
494 case wasm::kExprI64Eq:
495 op = m->Word64Equal();
496 break;
497 case wasm::kExprI64Ne:
498 return Invert(Binop(wasm::kExprI64Eq, left, right));
499 case wasm::kExprI64LtS:
500 op = m->Int64LessThan();
501 break;
502 case wasm::kExprI64LeS:
503 op = m->Int64LessThanOrEqual();
504 break;
505 case wasm::kExprI64LtU:
506 op = m->Uint64LessThan();
507 break;
508 case wasm::kExprI64LeU:
509 op = m->Uint64LessThanOrEqual();
510 break;
511 case wasm::kExprI64GtS:
512 op = m->Int64LessThan();
513 std::swap(left, right);
514 break;
515 case wasm::kExprI64GeS:
516 op = m->Int64LessThanOrEqual();
517 std::swap(left, right);
518 break;
519 case wasm::kExprI64GtU:
520 op = m->Uint64LessThan();
521 std::swap(left, right);
522 break;
523 case wasm::kExprI64GeU:
524 op = m->Uint64LessThanOrEqual();
525 std::swap(left, right);
526 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100527 case wasm::kExprI64Ror:
528 op = m->Word64Ror();
529 right = MaskShiftCount64(right);
530 break;
531 case wasm::kExprI64Rol:
532 return BuildI64Rol(left, right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000533 case wasm::kExprF32CopySign:
534 return BuildF32CopySign(left, right);
535 case wasm::kExprF64CopySign:
536 return BuildF64CopySign(left, right);
537 case wasm::kExprF32Add:
538 op = m->Float32Add();
539 break;
540 case wasm::kExprF32Sub:
Ben Murdochc5610432016-08-08 18:44:38 +0100541 op = m->Float32SubPreserveNan();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000542 break;
543 case wasm::kExprF32Mul:
544 op = m->Float32Mul();
545 break;
546 case wasm::kExprF32Div:
547 op = m->Float32Div();
548 break;
549 case wasm::kExprF32Eq:
550 op = m->Float32Equal();
551 break;
552 case wasm::kExprF32Ne:
553 return Invert(Binop(wasm::kExprF32Eq, left, right));
554 case wasm::kExprF32Lt:
555 op = m->Float32LessThan();
556 break;
557 case wasm::kExprF32Ge:
558 op = m->Float32LessThanOrEqual();
559 std::swap(left, right);
560 break;
561 case wasm::kExprF32Gt:
562 op = m->Float32LessThan();
563 std::swap(left, right);
564 break;
565 case wasm::kExprF32Le:
566 op = m->Float32LessThanOrEqual();
567 break;
568 case wasm::kExprF64Add:
569 op = m->Float64Add();
570 break;
571 case wasm::kExprF64Sub:
Ben Murdochc5610432016-08-08 18:44:38 +0100572 op = m->Float64SubPreserveNan();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000573 break;
574 case wasm::kExprF64Mul:
575 op = m->Float64Mul();
576 break;
577 case wasm::kExprF64Div:
578 op = m->Float64Div();
579 break;
580 case wasm::kExprF64Eq:
581 op = m->Float64Equal();
582 break;
583 case wasm::kExprF64Ne:
584 return Invert(Binop(wasm::kExprF64Eq, left, right));
585 case wasm::kExprF64Lt:
586 op = m->Float64LessThan();
587 break;
588 case wasm::kExprF64Le:
589 op = m->Float64LessThanOrEqual();
590 break;
591 case wasm::kExprF64Gt:
592 op = m->Float64LessThan();
593 std::swap(left, right);
594 break;
595 case wasm::kExprF64Ge:
596 op = m->Float64LessThanOrEqual();
597 std::swap(left, right);
598 break;
599 case wasm::kExprF32Min:
600 return BuildF32Min(left, right);
601 case wasm::kExprF64Min:
602 return BuildF64Min(left, right);
603 case wasm::kExprF32Max:
604 return BuildF32Max(left, right);
605 case wasm::kExprF64Max:
606 return BuildF64Max(left, right);
Ben Murdochc5610432016-08-08 18:44:38 +0100607 case wasm::kExprF64Pow:
Ben Murdochda12d292016-06-02 14:46:10 +0100608 return BuildF64Pow(left, right);
Ben Murdochc5610432016-08-08 18:44:38 +0100609 case wasm::kExprF64Atan2:
Ben Murdochda12d292016-06-02 14:46:10 +0100610 return BuildF64Atan2(left, right);
Ben Murdochc5610432016-08-08 18:44:38 +0100611 case wasm::kExprF64Mod:
Ben Murdochda12d292016-06-02 14:46:10 +0100612 return BuildF64Mod(left, right);
Ben Murdochc5610432016-08-08 18:44:38 +0100613 case wasm::kExprI32AsmjsDivS:
614 return BuildI32AsmjsDivS(left, right);
615 case wasm::kExprI32AsmjsDivU:
616 return BuildI32AsmjsDivU(left, right);
617 case wasm::kExprI32AsmjsRemS:
618 return BuildI32AsmjsRemS(left, right);
619 case wasm::kExprI32AsmjsRemU:
620 return BuildI32AsmjsRemU(left, right);
621 case wasm::kExprI32AsmjsStoreMem8:
622 return BuildAsmjsStoreMem(MachineType::Int8(), left, right);
623 case wasm::kExprI32AsmjsStoreMem16:
624 return BuildAsmjsStoreMem(MachineType::Int16(), left, right);
625 case wasm::kExprI32AsmjsStoreMem:
626 return BuildAsmjsStoreMem(MachineType::Int32(), left, right);
627 case wasm::kExprF32AsmjsStoreMem:
628 return BuildAsmjsStoreMem(MachineType::Float32(), left, right);
629 case wasm::kExprF64AsmjsStoreMem:
630 return BuildAsmjsStoreMem(MachineType::Float64(), left, right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000631 default:
632 op = UnsupportedOpcode(opcode);
633 }
634 return graph()->NewNode(op, left, right);
635}
636
Ben Murdochc5610432016-08-08 18:44:38 +0100637Node* WasmGraphBuilder::Unop(wasm::WasmOpcode opcode, Node* input,
638 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000639 const Operator* op;
640 MachineOperatorBuilder* m = jsgraph()->machine();
641 switch (opcode) {
Ben Murdochda12d292016-06-02 14:46:10 +0100642 case wasm::kExprI32Eqz:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000643 op = m->Word32Equal();
644 return graph()->NewNode(op, input, jsgraph()->Int32Constant(0));
645 case wasm::kExprF32Abs:
646 op = m->Float32Abs();
647 break;
648 case wasm::kExprF32Neg:
649 return BuildF32Neg(input);
650 case wasm::kExprF32Sqrt:
651 op = m->Float32Sqrt();
652 break;
653 case wasm::kExprF64Abs:
654 op = m->Float64Abs();
655 break;
656 case wasm::kExprF64Neg:
657 return BuildF64Neg(input);
658 case wasm::kExprF64Sqrt:
659 op = m->Float64Sqrt();
660 break;
661 case wasm::kExprI32SConvertF64:
Ben Murdochc5610432016-08-08 18:44:38 +0100662 return BuildI32SConvertF64(input, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000663 case wasm::kExprI32UConvertF64:
Ben Murdochc5610432016-08-08 18:44:38 +0100664 return BuildI32UConvertF64(input, position);
665 case wasm::kExprI32AsmjsSConvertF64:
666 return BuildI32AsmjsSConvertF64(input);
667 case wasm::kExprI32AsmjsUConvertF64:
668 return BuildI32AsmjsUConvertF64(input);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000669 case wasm::kExprF32ConvertF64:
670 op = m->TruncateFloat64ToFloat32();
671 break;
672 case wasm::kExprF64SConvertI32:
673 op = m->ChangeInt32ToFloat64();
674 break;
675 case wasm::kExprF64UConvertI32:
676 op = m->ChangeUint32ToFloat64();
677 break;
678 case wasm::kExprF32SConvertI32:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100679 op = m->RoundInt32ToFloat32();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000680 break;
681 case wasm::kExprF32UConvertI32:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100682 op = m->RoundUint32ToFloat32();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000683 break;
684 case wasm::kExprI32SConvertF32:
Ben Murdochc5610432016-08-08 18:44:38 +0100685 return BuildI32SConvertF32(input, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000686 case wasm::kExprI32UConvertF32:
Ben Murdochc5610432016-08-08 18:44:38 +0100687 return BuildI32UConvertF32(input, position);
688 case wasm::kExprI32AsmjsSConvertF32:
689 return BuildI32AsmjsSConvertF32(input);
690 case wasm::kExprI32AsmjsUConvertF32:
691 return BuildI32AsmjsUConvertF32(input);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000692 case wasm::kExprF64ConvertF32:
693 op = m->ChangeFloat32ToFloat64();
694 break;
695 case wasm::kExprF32ReinterpretI32:
696 op = m->BitcastInt32ToFloat32();
697 break;
698 case wasm::kExprI32ReinterpretF32:
699 op = m->BitcastFloat32ToInt32();
700 break;
701 case wasm::kExprI32Clz:
702 op = m->Word32Clz();
703 break;
704 case wasm::kExprI32Ctz: {
705 if (m->Word32Ctz().IsSupported()) {
706 op = m->Word32Ctz().op();
707 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100708 } else if (m->Word32ReverseBits().IsSupported()) {
709 Node* reversed = graph()->NewNode(m->Word32ReverseBits().op(), input);
710 Node* result = graph()->NewNode(m->Word32Clz(), reversed);
711 return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000712 } else {
713 return BuildI32Ctz(input);
714 }
715 }
716 case wasm::kExprI32Popcnt: {
717 if (m->Word32Popcnt().IsSupported()) {
718 op = m->Word32Popcnt().op();
719 break;
720 } else {
721 return BuildI32Popcnt(input);
722 }
723 }
724 case wasm::kExprF32Floor: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100725 if (!m->Float32RoundDown().IsSupported()) return BuildF32Floor(input);
726 op = m->Float32RoundDown().op();
727 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000728 }
729 case wasm::kExprF32Ceil: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100730 if (!m->Float32RoundUp().IsSupported()) return BuildF32Ceil(input);
731 op = m->Float32RoundUp().op();
732 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000733 }
734 case wasm::kExprF32Trunc: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100735 if (!m->Float32RoundTruncate().IsSupported()) return BuildF32Trunc(input);
736 op = m->Float32RoundTruncate().op();
737 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000738 }
739 case wasm::kExprF32NearestInt: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100740 if (!m->Float32RoundTiesEven().IsSupported())
741 return BuildF32NearestInt(input);
742 op = m->Float32RoundTiesEven().op();
743 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000744 }
745 case wasm::kExprF64Floor: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100746 if (!m->Float64RoundDown().IsSupported()) return BuildF64Floor(input);
747 op = m->Float64RoundDown().op();
748 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000749 }
750 case wasm::kExprF64Ceil: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100751 if (!m->Float64RoundUp().IsSupported()) return BuildF64Ceil(input);
752 op = m->Float64RoundUp().op();
753 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000754 }
755 case wasm::kExprF64Trunc: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100756 if (!m->Float64RoundTruncate().IsSupported()) return BuildF64Trunc(input);
757 op = m->Float64RoundTruncate().op();
758 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000759 }
760 case wasm::kExprF64NearestInt: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100761 if (!m->Float64RoundTiesEven().IsSupported())
762 return BuildF64NearestInt(input);
763 op = m->Float64RoundTiesEven().op();
764 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000765 }
Ben Murdochda12d292016-06-02 14:46:10 +0100766 case wasm::kExprF64Acos: {
767 return BuildF64Acos(input);
768 }
769 case wasm::kExprF64Asin: {
770 return BuildF64Asin(input);
771 }
772 case wasm::kExprF64Atan: {
773 return BuildF64Atan(input);
774 }
775 case wasm::kExprF64Cos: {
776 return BuildF64Cos(input);
777 }
778 case wasm::kExprF64Sin: {
779 return BuildF64Sin(input);
780 }
781 case wasm::kExprF64Tan: {
782 return BuildF64Tan(input);
783 }
784 case wasm::kExprF64Exp: {
785 return BuildF64Exp(input);
786 }
787 case wasm::kExprF64Log: {
788 return BuildF64Log(input);
789 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000790 case wasm::kExprI32ConvertI64:
791 op = m->TruncateInt64ToInt32();
792 break;
793 case wasm::kExprI64SConvertI32:
794 op = m->ChangeInt32ToInt64();
795 break;
796 case wasm::kExprI64UConvertI32:
797 op = m->ChangeUint32ToUint64();
798 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000799 case wasm::kExprF64ReinterpretI64:
800 op = m->BitcastInt64ToFloat64();
801 break;
802 case wasm::kExprI64ReinterpretF64:
803 op = m->BitcastFloat64ToInt64();
804 break;
805 case wasm::kExprI64Clz:
806 op = m->Word64Clz();
807 break;
808 case wasm::kExprI64Ctz: {
809 if (m->Word64Ctz().IsSupported()) {
810 op = m->Word64Ctz().op();
811 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100812 } else if (m->Is32() && m->Word32Ctz().IsSupported()) {
813 op = m->Word64CtzPlaceholder();
814 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100815 } else if (m->Word64ReverseBits().IsSupported()) {
816 Node* reversed = graph()->NewNode(m->Word64ReverseBits().op(), input);
817 Node* result = graph()->NewNode(m->Word64Clz(), reversed);
818 return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000819 } else {
820 return BuildI64Ctz(input);
821 }
822 }
823 case wasm::kExprI64Popcnt: {
824 if (m->Word64Popcnt().IsSupported()) {
825 op = m->Word64Popcnt().op();
Ben Murdochda12d292016-06-02 14:46:10 +0100826 } else if (m->Is32() && m->Word32Popcnt().IsSupported()) {
827 op = m->Word64PopcntPlaceholder();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000828 } else {
829 return BuildI64Popcnt(input);
830 }
Ben Murdochda12d292016-06-02 14:46:10 +0100831 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000832 }
Ben Murdochda12d292016-06-02 14:46:10 +0100833 case wasm::kExprI64Eqz:
834 op = m->Word64Equal();
835 return graph()->NewNode(op, input, jsgraph()->Int64Constant(0));
836 case wasm::kExprF32SConvertI64:
837 if (m->Is32()) {
838 return BuildF32SConvertI64(input);
839 }
840 op = m->RoundInt64ToFloat32();
841 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100842 case wasm::kExprF32UConvertI64:
843 if (m->Is32()) {
844 return BuildF32UConvertI64(input);
845 }
846 op = m->RoundUint64ToFloat32();
847 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100848 case wasm::kExprF64SConvertI64:
849 if (m->Is32()) {
850 return BuildF64SConvertI64(input);
851 }
852 op = m->RoundInt64ToFloat64();
853 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100854 case wasm::kExprF64UConvertI64:
855 if (m->Is32()) {
856 return BuildF64UConvertI64(input);
857 }
858 op = m->RoundUint64ToFloat64();
859 break;
Ben Murdochc5610432016-08-08 18:44:38 +0100860 case wasm::kExprI64SConvertF32:
861 return BuildI64SConvertF32(input, position);
862 case wasm::kExprI64SConvertF64:
863 return BuildI64SConvertF64(input, position);
864 case wasm::kExprI64UConvertF32:
865 return BuildI64UConvertF32(input, position);
866 case wasm::kExprI64UConvertF64:
867 return BuildI64UConvertF64(input, position);
868 case wasm::kExprI32AsmjsLoadMem8S:
869 return BuildAsmjsLoadMem(MachineType::Int8(), input);
870 case wasm::kExprI32AsmjsLoadMem8U:
871 return BuildAsmjsLoadMem(MachineType::Uint8(), input);
872 case wasm::kExprI32AsmjsLoadMem16S:
873 return BuildAsmjsLoadMem(MachineType::Int16(), input);
874 case wasm::kExprI32AsmjsLoadMem16U:
875 return BuildAsmjsLoadMem(MachineType::Uint16(), input);
876 case wasm::kExprI32AsmjsLoadMem:
877 return BuildAsmjsLoadMem(MachineType::Int32(), input);
878 case wasm::kExprF32AsmjsLoadMem:
879 return BuildAsmjsLoadMem(MachineType::Float32(), input);
880 case wasm::kExprF64AsmjsLoadMem:
881 return BuildAsmjsLoadMem(MachineType::Float64(), input);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000882 default:
883 op = UnsupportedOpcode(opcode);
884 }
885 return graph()->NewNode(op, input);
886}
887
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000888Node* WasmGraphBuilder::Float32Constant(float value) {
889 return jsgraph()->Float32Constant(value);
890}
891
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000892Node* WasmGraphBuilder::Float64Constant(double value) {
893 return jsgraph()->Float64Constant(value);
894}
895
Ben Murdochc5610432016-08-08 18:44:38 +0100896Node* WasmGraphBuilder::HeapConstant(Handle<HeapObject> value) {
897 return jsgraph()->HeapConstant(value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000898}
899
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000900Node* WasmGraphBuilder::Branch(Node* cond, Node** true_node,
901 Node** false_node) {
902 DCHECK_NOT_NULL(cond);
903 DCHECK_NOT_NULL(*control_);
904 Node* branch =
905 graph()->NewNode(jsgraph()->common()->Branch(), cond, *control_);
906 *true_node = graph()->NewNode(jsgraph()->common()->IfTrue(), branch);
907 *false_node = graph()->NewNode(jsgraph()->common()->IfFalse(), branch);
908 return branch;
909}
910
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000911Node* WasmGraphBuilder::Switch(unsigned count, Node* key) {
912 return graph()->NewNode(jsgraph()->common()->Switch(count), key, *control_);
913}
914
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000915Node* WasmGraphBuilder::IfValue(int32_t value, Node* sw) {
916 DCHECK_EQ(IrOpcode::kSwitch, sw->opcode());
917 return graph()->NewNode(jsgraph()->common()->IfValue(value), sw);
918}
919
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000920Node* WasmGraphBuilder::IfDefault(Node* sw) {
921 DCHECK_EQ(IrOpcode::kSwitch, sw->opcode());
922 return graph()->NewNode(jsgraph()->common()->IfDefault(), sw);
923}
924
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000925Node* WasmGraphBuilder::Return(unsigned count, Node** vals) {
926 DCHECK_NOT_NULL(*control_);
927 DCHECK_NOT_NULL(*effect_);
928
929 if (count == 0) {
930 // Handle a return of void.
931 vals[0] = jsgraph()->Int32Constant(0);
932 count = 1;
933 }
934
Ben Murdochda12d292016-06-02 14:46:10 +0100935 Node** buf = Realloc(vals, count, count + 2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000936 buf[count] = *effect_;
937 buf[count + 1] = *control_;
938 Node* ret = graph()->NewNode(jsgraph()->common()->Return(), count + 2, vals);
939
940 MergeControlToEnd(jsgraph(), ret);
941 return ret;
942}
943
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000944Node* WasmGraphBuilder::ReturnVoid() { return Return(0, Buffer(0)); }
945
Ben Murdochc5610432016-08-08 18:44:38 +0100946Node* WasmGraphBuilder::Unreachable(wasm::WasmCodePosition position) {
947 trap_->Unreachable(position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000948 return nullptr;
949}
950
Ben Murdochda12d292016-06-02 14:46:10 +0100951Node* WasmGraphBuilder::MaskShiftCount32(Node* node) {
952 static const int32_t kMask32 = 0x1f;
953 if (!jsgraph()->machine()->Word32ShiftIsSafe()) {
954 // Shifts by constants are so common we pattern-match them here.
955 Int32Matcher match(node);
956 if (match.HasValue()) {
957 int32_t masked = (match.Value() & kMask32);
958 if (match.Value() != masked) node = jsgraph()->Int32Constant(masked);
959 } else {
960 node = graph()->NewNode(jsgraph()->machine()->Word32And(), node,
961 jsgraph()->Int32Constant(kMask32));
962 }
963 }
964 return node;
965}
966
967Node* WasmGraphBuilder::MaskShiftCount64(Node* node) {
968 static const int64_t kMask64 = 0x3f;
969 if (!jsgraph()->machine()->Word32ShiftIsSafe()) {
970 // Shifts by constants are so common we pattern-match them here.
971 Int64Matcher match(node);
972 if (match.HasValue()) {
973 int64_t masked = (match.Value() & kMask64);
974 if (match.Value() != masked) node = jsgraph()->Int64Constant(masked);
975 } else {
976 node = graph()->NewNode(jsgraph()->machine()->Word64And(), node,
977 jsgraph()->Int64Constant(kMask64));
978 }
979 }
980 return node;
981}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000982
983Node* WasmGraphBuilder::BuildF32Neg(Node* input) {
984 Node* result =
985 Unop(wasm::kExprF32ReinterpretI32,
986 Binop(wasm::kExprI32Xor, Unop(wasm::kExprI32ReinterpretF32, input),
987 jsgraph()->Int32Constant(0x80000000)));
988
989 return result;
990}
991
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000992Node* WasmGraphBuilder::BuildF64Neg(Node* input) {
993#if WASM_64
994 Node* result =
995 Unop(wasm::kExprF64ReinterpretI64,
996 Binop(wasm::kExprI64Xor, Unop(wasm::kExprI64ReinterpretF64, input),
997 jsgraph()->Int64Constant(0x8000000000000000)));
998
999 return result;
1000#else
1001 MachineOperatorBuilder* m = jsgraph()->machine();
1002
1003 Node* old_high_word = graph()->NewNode(m->Float64ExtractHighWord32(), input);
1004 Node* new_high_word = Binop(wasm::kExprI32Xor, old_high_word,
1005 jsgraph()->Int32Constant(0x80000000));
1006
1007 return graph()->NewNode(m->Float64InsertHighWord32(), input, new_high_word);
1008#endif
1009}
1010
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001011Node* 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001023Node* WasmGraphBuilder::BuildF64CopySign(Node* left, Node* right) {
1024#if WASM_64
1025 Node* result = Unop(
1026 wasm::kExprF64ReinterpretI64,
1027 Binop(wasm::kExprI64Ior,
1028 Binop(wasm::kExprI64And, Unop(wasm::kExprI64ReinterpretF64, left),
1029 jsgraph()->Int64Constant(0x7fffffffffffffff)),
1030 Binop(wasm::kExprI64And, Unop(wasm::kExprI64ReinterpretF64, right),
1031 jsgraph()->Int64Constant(0x8000000000000000))));
1032
1033 return result;
1034#else
1035 MachineOperatorBuilder* m = jsgraph()->machine();
1036
1037 Node* high_word_left = graph()->NewNode(m->Float64ExtractHighWord32(), left);
1038 Node* high_word_right =
1039 graph()->NewNode(m->Float64ExtractHighWord32(), right);
1040
1041 Node* new_high_word =
1042 Binop(wasm::kExprI32Ior, Binop(wasm::kExprI32And, high_word_left,
1043 jsgraph()->Int32Constant(0x7fffffff)),
1044 Binop(wasm::kExprI32And, high_word_right,
1045 jsgraph()->Int32Constant(0x80000000)));
1046
1047 return graph()->NewNode(m->Float64InsertHighWord32(), left, new_high_word);
1048#endif
1049}
1050
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001051Node* WasmGraphBuilder::BuildF32Min(Node* left, Node* right) {
1052 Diamond left_le_right(graph(), jsgraph()->common(),
1053 Binop(wasm::kExprF32Le, left, right));
1054
1055 Diamond right_lt_left(graph(), jsgraph()->common(),
1056 Binop(wasm::kExprF32Lt, right, left));
1057
1058 Diamond left_is_not_nan(graph(), jsgraph()->common(),
1059 Binop(wasm::kExprF32Eq, left, left));
1060
1061 return left_le_right.Phi(
1062 wasm::kAstF32, left,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001063 right_lt_left.Phi(
1064 wasm::kAstF32, right,
1065 left_is_not_nan.Phi(
1066 wasm::kAstF32,
1067 Binop(wasm::kExprF32Mul, right, Float32Constant(1.0)),
1068 Binop(wasm::kExprF32Mul, left, Float32Constant(1.0)))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001069}
1070
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001071Node* WasmGraphBuilder::BuildF32Max(Node* left, Node* right) {
1072 Diamond left_ge_right(graph(), jsgraph()->common(),
1073 Binop(wasm::kExprF32Ge, left, right));
1074
1075 Diamond right_gt_left(graph(), jsgraph()->common(),
1076 Binop(wasm::kExprF32Gt, right, left));
1077
1078 Diamond left_is_not_nan(graph(), jsgraph()->common(),
1079 Binop(wasm::kExprF32Eq, left, left));
1080
1081 return left_ge_right.Phi(
1082 wasm::kAstF32, left,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001083 right_gt_left.Phi(
1084 wasm::kAstF32, right,
1085 left_is_not_nan.Phi(
1086 wasm::kAstF32,
1087 Binop(wasm::kExprF32Mul, right, Float32Constant(1.0)),
1088 Binop(wasm::kExprF32Mul, left, Float32Constant(1.0)))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001089}
1090
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001091Node* WasmGraphBuilder::BuildF64Min(Node* left, Node* right) {
1092 Diamond left_le_right(graph(), jsgraph()->common(),
1093 Binop(wasm::kExprF64Le, left, right));
1094
1095 Diamond right_lt_left(graph(), jsgraph()->common(),
1096 Binop(wasm::kExprF64Lt, right, left));
1097
1098 Diamond left_is_not_nan(graph(), jsgraph()->common(),
1099 Binop(wasm::kExprF64Eq, left, left));
1100
1101 return left_le_right.Phi(
1102 wasm::kAstF64, left,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001103 right_lt_left.Phi(
1104 wasm::kAstF64, right,
1105 left_is_not_nan.Phi(
1106 wasm::kAstF64,
1107 Binop(wasm::kExprF64Mul, right, Float64Constant(1.0)),
1108 Binop(wasm::kExprF64Mul, left, Float64Constant(1.0)))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001109}
1110
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001111Node* WasmGraphBuilder::BuildF64Max(Node* left, Node* right) {
1112 Diamond left_ge_right(graph(), jsgraph()->common(),
1113 Binop(wasm::kExprF64Ge, left, right));
1114
1115 Diamond right_gt_left(graph(), jsgraph()->common(),
1116 Binop(wasm::kExprF64Lt, right, left));
1117
1118 Diamond left_is_not_nan(graph(), jsgraph()->common(),
1119 Binop(wasm::kExprF64Eq, left, left));
1120
1121 return left_ge_right.Phi(
1122 wasm::kAstF64, left,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001123 right_gt_left.Phi(
1124 wasm::kAstF64, right,
1125 left_is_not_nan.Phi(
1126 wasm::kAstF64,
1127 Binop(wasm::kExprF64Mul, right, Float64Constant(1.0)),
1128 Binop(wasm::kExprF64Mul, left, Float64Constant(1.0)))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001129}
1130
Ben Murdochc5610432016-08-08 18:44:38 +01001131Node* WasmGraphBuilder::BuildI32SConvertF32(Node* input,
1132 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001133 MachineOperatorBuilder* m = jsgraph()->machine();
1134 // Truncation of the input value is needed for the overflow check later.
1135 Node* trunc = Unop(wasm::kExprF32Trunc, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001136 Node* result = graph()->NewNode(m->TruncateFloat32ToInt32(), trunc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001137
1138 // Convert the result back to f64. If we end up at a different value than the
1139 // truncated input value, then there has been an overflow and we trap.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001140 Node* check = Unop(wasm::kExprF32SConvertI32, result);
1141 Node* overflow = Binop(wasm::kExprF32Ne, trunc, check);
Ben Murdochc5610432016-08-08 18:44:38 +01001142 trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001143
1144 return result;
1145}
1146
Ben Murdochc5610432016-08-08 18:44:38 +01001147Node* WasmGraphBuilder::BuildI32SConvertF64(Node* input,
1148 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001149 MachineOperatorBuilder* m = jsgraph()->machine();
1150 // Truncation of the input value is needed for the overflow check later.
1151 Node* trunc = Unop(wasm::kExprF64Trunc, input);
1152 Node* result = graph()->NewNode(m->ChangeFloat64ToInt32(), trunc);
1153
1154 // Convert the result back to f64. If we end up at a different value than the
1155 // truncated input value, then there has been an overflow and we trap.
1156 Node* check = Unop(wasm::kExprF64SConvertI32, result);
1157 Node* overflow = Binop(wasm::kExprF64Ne, trunc, check);
Ben Murdochc5610432016-08-08 18:44:38 +01001158 trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001159
1160 return result;
1161}
1162
Ben Murdochc5610432016-08-08 18:44:38 +01001163Node* WasmGraphBuilder::BuildI32UConvertF32(Node* input,
1164 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001165 MachineOperatorBuilder* m = jsgraph()->machine();
1166 // Truncation of the input value is needed for the overflow check later.
1167 Node* trunc = Unop(wasm::kExprF32Trunc, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001168 Node* result = graph()->NewNode(m->TruncateFloat32ToUint32(), trunc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001169
Ben Murdoch097c5b22016-05-18 11:27:45 +01001170 // Convert the result back to f32. If we end up at a different value than the
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001171 // truncated input value, then there has been an overflow and we trap.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001172 Node* check = Unop(wasm::kExprF32UConvertI32, result);
1173 Node* overflow = Binop(wasm::kExprF32Ne, trunc, check);
Ben Murdochc5610432016-08-08 18:44:38 +01001174 trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001175
1176 return result;
1177}
1178
Ben Murdochc5610432016-08-08 18:44:38 +01001179Node* WasmGraphBuilder::BuildI32UConvertF64(Node* input,
1180 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001181 MachineOperatorBuilder* m = jsgraph()->machine();
1182 // Truncation of the input value is needed for the overflow check later.
1183 Node* trunc = Unop(wasm::kExprF64Trunc, input);
Ben Murdochda12d292016-06-02 14:46:10 +01001184 Node* result = graph()->NewNode(m->TruncateFloat64ToUint32(), trunc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001185
1186 // Convert the result back to f64. If we end up at a different value than the
1187 // truncated input value, then there has been an overflow and we trap.
1188 Node* check = Unop(wasm::kExprF64UConvertI32, result);
1189 Node* overflow = Binop(wasm::kExprF64Ne, trunc, check);
Ben Murdochc5610432016-08-08 18:44:38 +01001190 trap_->AddTrapIfTrue(wasm::kTrapFloatUnrepresentable, overflow, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001191
1192 return result;
1193}
1194
Ben Murdochc5610432016-08-08 18:44:38 +01001195Node* WasmGraphBuilder::BuildI32AsmjsSConvertF32(Node* input) {
1196 MachineOperatorBuilder* m = jsgraph()->machine();
1197 // asm.js must use the wacky JS semantics.
1198 input = graph()->NewNode(m->ChangeFloat32ToFloat64(), input);
1199 return graph()->NewNode(m->TruncateFloat64ToWord32(), input);
1200}
1201
1202Node* WasmGraphBuilder::BuildI32AsmjsSConvertF64(Node* input) {
1203 MachineOperatorBuilder* m = jsgraph()->machine();
1204 // asm.js must use the wacky JS semantics.
1205 return graph()->NewNode(m->TruncateFloat64ToWord32(), input);
1206}
1207
1208Node* WasmGraphBuilder::BuildI32AsmjsUConvertF32(Node* input) {
1209 MachineOperatorBuilder* m = jsgraph()->machine();
1210 // asm.js must use the wacky JS semantics.
1211 input = graph()->NewNode(m->ChangeFloat32ToFloat64(), input);
1212 return graph()->NewNode(m->TruncateFloat64ToWord32(), input);
1213}
1214
1215Node* WasmGraphBuilder::BuildI32AsmjsUConvertF64(Node* input) {
1216 MachineOperatorBuilder* m = jsgraph()->machine();
1217 // asm.js must use the wacky JS semantics.
1218 return graph()->NewNode(m->TruncateFloat64ToWord32(), input);
1219}
1220
1221Node* WasmGraphBuilder::BuildBitCountingCall(Node* input, ExternalReference ref,
1222 MachineRepresentation input_type) {
1223 Node* stack_slot_param =
1224 graph()->NewNode(jsgraph()->machine()->StackSlot(input_type));
1225
1226 const Operator* store_op = jsgraph()->machine()->Store(
1227 StoreRepresentation(input_type, kNoWriteBarrier));
1228 *effect_ =
1229 graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0),
1230 input, *effect_, *control_);
1231
1232 MachineSignature::Builder sig_builder(jsgraph()->zone(), 1, 1);
1233 sig_builder.AddReturn(MachineType::Int32());
1234 sig_builder.AddParam(MachineType::Pointer());
1235
1236 Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
1237 Node* args[] = {function, stack_slot_param};
1238
1239 return BuildCCall(sig_builder.Build(), args);
1240}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001241
1242Node* WasmGraphBuilder::BuildI32Ctz(Node* input) {
Ben Murdochc5610432016-08-08 18:44:38 +01001243 return BuildBitCountingCall(
1244 input, ExternalReference::wasm_word32_ctz(jsgraph()->isolate()),
1245 MachineRepresentation::kWord32);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001246}
1247
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001248Node* WasmGraphBuilder::BuildI64Ctz(Node* input) {
Ben Murdochc5610432016-08-08 18:44:38 +01001249 return Unop(wasm::kExprI64UConvertI32,
1250 BuildBitCountingCall(input, ExternalReference::wasm_word64_ctz(
1251 jsgraph()->isolate()),
1252 MachineRepresentation::kWord64));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001253}
1254
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001255Node* WasmGraphBuilder::BuildI32Popcnt(Node* input) {
Ben Murdochc5610432016-08-08 18:44:38 +01001256 return BuildBitCountingCall(
1257 input, ExternalReference::wasm_word32_popcnt(jsgraph()->isolate()),
1258 MachineRepresentation::kWord32);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001259}
1260
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001261Node* WasmGraphBuilder::BuildI64Popcnt(Node* input) {
Ben Murdochc5610432016-08-08 18:44:38 +01001262 return Unop(wasm::kExprI64UConvertI32,
1263 BuildBitCountingCall(input, ExternalReference::wasm_word64_popcnt(
1264 jsgraph()->isolate()),
1265 MachineRepresentation::kWord64));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001266}
1267
Ben Murdoch097c5b22016-05-18 11:27:45 +01001268Node* WasmGraphBuilder::BuildF32Trunc(Node* input) {
1269 MachineType type = MachineType::Float32();
1270 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001271 ExternalReference::wasm_f32_trunc(jsgraph()->isolate());
1272
1273 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001274}
1275
1276Node* WasmGraphBuilder::BuildF32Floor(Node* input) {
1277 MachineType type = MachineType::Float32();
1278 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001279 ExternalReference::wasm_f32_floor(jsgraph()->isolate());
1280 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001281}
1282
1283Node* WasmGraphBuilder::BuildF32Ceil(Node* input) {
1284 MachineType type = MachineType::Float32();
1285 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001286 ExternalReference::wasm_f32_ceil(jsgraph()->isolate());
1287 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001288}
1289
1290Node* WasmGraphBuilder::BuildF32NearestInt(Node* input) {
1291 MachineType type = MachineType::Float32();
1292 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001293 ExternalReference::wasm_f32_nearest_int(jsgraph()->isolate());
1294 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001295}
1296
1297Node* WasmGraphBuilder::BuildF64Trunc(Node* input) {
1298 MachineType type = MachineType::Float64();
1299 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001300 ExternalReference::wasm_f64_trunc(jsgraph()->isolate());
1301 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001302}
1303
1304Node* WasmGraphBuilder::BuildF64Floor(Node* input) {
1305 MachineType type = MachineType::Float64();
1306 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001307 ExternalReference::wasm_f64_floor(jsgraph()->isolate());
1308 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001309}
1310
1311Node* WasmGraphBuilder::BuildF64Ceil(Node* input) {
1312 MachineType type = MachineType::Float64();
1313 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001314 ExternalReference::wasm_f64_ceil(jsgraph()->isolate());
1315 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001316}
1317
1318Node* WasmGraphBuilder::BuildF64NearestInt(Node* input) {
1319 MachineType type = MachineType::Float64();
1320 ExternalReference ref =
Ben Murdochda12d292016-06-02 14:46:10 +01001321 ExternalReference::wasm_f64_nearest_int(jsgraph()->isolate());
1322 return BuildCFuncInstruction(ref, type, input);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001323}
1324
Ben Murdochda12d292016-06-02 14:46:10 +01001325Node* WasmGraphBuilder::BuildF64Acos(Node* input) {
1326 MachineType type = MachineType::Float64();
1327 ExternalReference ref =
1328 ExternalReference::f64_acos_wrapper_function(jsgraph()->isolate());
1329 return BuildCFuncInstruction(ref, type, input);
1330}
Ben Murdoch097c5b22016-05-18 11:27:45 +01001331
Ben Murdochda12d292016-06-02 14:46:10 +01001332Node* WasmGraphBuilder::BuildF64Asin(Node* input) {
1333 MachineType type = MachineType::Float64();
1334 ExternalReference ref =
1335 ExternalReference::f64_asin_wrapper_function(jsgraph()->isolate());
1336 return BuildCFuncInstruction(ref, type, input);
1337}
1338
1339Node* WasmGraphBuilder::BuildF64Atan(Node* input) {
1340 MachineType type = MachineType::Float64();
1341 ExternalReference ref =
1342 ExternalReference::f64_atan_wrapper_function(jsgraph()->isolate());
1343 return BuildCFuncInstruction(ref, type, input);
1344}
1345
1346Node* WasmGraphBuilder::BuildF64Cos(Node* input) {
1347 MachineType type = MachineType::Float64();
1348 ExternalReference ref =
1349 ExternalReference::f64_cos_wrapper_function(jsgraph()->isolate());
1350 return BuildCFuncInstruction(ref, type, input);
1351}
1352
1353Node* WasmGraphBuilder::BuildF64Sin(Node* input) {
1354 MachineType type = MachineType::Float64();
1355 ExternalReference ref =
1356 ExternalReference::f64_sin_wrapper_function(jsgraph()->isolate());
1357 return BuildCFuncInstruction(ref, type, input);
1358}
1359
1360Node* WasmGraphBuilder::BuildF64Tan(Node* input) {
1361 MachineType type = MachineType::Float64();
1362 ExternalReference ref =
1363 ExternalReference::f64_tan_wrapper_function(jsgraph()->isolate());
1364 return BuildCFuncInstruction(ref, type, input);
1365}
1366
1367Node* WasmGraphBuilder::BuildF64Exp(Node* input) {
1368 MachineType type = MachineType::Float64();
1369 ExternalReference ref =
1370 ExternalReference::f64_exp_wrapper_function(jsgraph()->isolate());
1371 return BuildCFuncInstruction(ref, type, input);
1372}
1373
1374Node* WasmGraphBuilder::BuildF64Log(Node* input) {
1375 MachineType type = MachineType::Float64();
1376 ExternalReference ref =
1377 ExternalReference::f64_log_wrapper_function(jsgraph()->isolate());
1378 return BuildCFuncInstruction(ref, type, input);
1379}
1380
1381Node* WasmGraphBuilder::BuildF64Atan2(Node* left, Node* right) {
1382 MachineType type = MachineType::Float64();
1383 ExternalReference ref =
1384 ExternalReference::f64_atan2_wrapper_function(jsgraph()->isolate());
1385 return BuildCFuncInstruction(ref, type, left, right);
1386}
1387
1388Node* WasmGraphBuilder::BuildF64Pow(Node* left, Node* right) {
1389 MachineType type = MachineType::Float64();
1390 ExternalReference ref =
1391 ExternalReference::f64_pow_wrapper_function(jsgraph()->isolate());
1392 return BuildCFuncInstruction(ref, type, left, right);
1393}
1394
1395Node* WasmGraphBuilder::BuildF64Mod(Node* left, Node* right) {
1396 MachineType type = MachineType::Float64();
1397 ExternalReference ref =
1398 ExternalReference::f64_mod_wrapper_function(jsgraph()->isolate());
1399 return BuildCFuncInstruction(ref, type, left, right);
1400}
1401
1402Node* WasmGraphBuilder::BuildCFuncInstruction(ExternalReference ref,
1403 MachineType type, Node* input0,
1404 Node* input1) {
1405 // We do truncation by calling a C function which calculates the result.
1406 // The input is passed to the C function as a double*'s to avoid double
1407 // parameters. For this we reserve slots on the stack, store the parameters
1408 // in those slots, pass pointers to the slot to the C function,
1409 // and after calling the C function we collect the return value from
1410 // the stack slot.
1411
1412 Node* stack_slot_param0 =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001413 graph()->NewNode(jsgraph()->machine()->StackSlot(type.representation()));
1414
Ben Murdochda12d292016-06-02 14:46:10 +01001415 const Operator* store_op0 = jsgraph()->machine()->Store(
Ben Murdoch097c5b22016-05-18 11:27:45 +01001416 StoreRepresentation(type.representation(), kNoWriteBarrier));
Ben Murdochda12d292016-06-02 14:46:10 +01001417 *effect_ = graph()->NewNode(store_op0, stack_slot_param0,
1418 jsgraph()->Int32Constant(0), input0, *effect_,
1419 *control_);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001420
Ben Murdoch097c5b22016-05-18 11:27:45 +01001421 Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
Ben Murdochda12d292016-06-02 14:46:10 +01001422 Node** args = Buffer(5);
1423 args[0] = function;
1424 args[1] = stack_slot_param0;
1425 int input_count = 1;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001426
Ben Murdochda12d292016-06-02 14:46:10 +01001427 if (input1 != nullptr) {
1428 Node* stack_slot_param1 = graph()->NewNode(
1429 jsgraph()->machine()->StackSlot(type.representation()));
1430 const Operator* store_op1 = jsgraph()->machine()->Store(
1431 StoreRepresentation(type.representation(), kNoWriteBarrier));
1432 *effect_ = graph()->NewNode(store_op1, stack_slot_param1,
1433 jsgraph()->Int32Constant(0), input1, *effect_,
1434 *control_);
1435 args[2] = stack_slot_param1;
1436 ++input_count;
1437 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001438
Ben Murdochda12d292016-06-02 14:46:10 +01001439 Signature<MachineType>::Builder sig_builder(jsgraph()->zone(), 0,
1440 input_count);
1441 sig_builder.AddParam(MachineType::Pointer());
1442 if (input1 != nullptr) {
1443 sig_builder.AddParam(MachineType::Pointer());
1444 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001445 BuildCCall(sig_builder.Build(), args);
1446
1447 const Operator* load_op = jsgraph()->machine()->Load(type);
1448
1449 Node* load =
Ben Murdochda12d292016-06-02 14:46:10 +01001450 graph()->NewNode(load_op, stack_slot_param0, jsgraph()->Int32Constant(0),
1451 *effect_, *control_);
1452 *effect_ = load;
1453 return load;
1454}
1455
1456Node* WasmGraphBuilder::BuildF32SConvertI64(Node* input) {
1457 // TODO(titzer/bradnelson): Check handlng of asm.js case.
1458 return BuildIntToFloatConversionInstruction(
1459 input, ExternalReference::wasm_int64_to_float32(jsgraph()->isolate()),
1460 MachineRepresentation::kWord64, MachineType::Float32());
1461}
1462Node* WasmGraphBuilder::BuildF32UConvertI64(Node* input) {
1463 // TODO(titzer/bradnelson): Check handlng of asm.js case.
1464 return BuildIntToFloatConversionInstruction(
1465 input, ExternalReference::wasm_uint64_to_float32(jsgraph()->isolate()),
1466 MachineRepresentation::kWord64, MachineType::Float32());
1467}
1468Node* WasmGraphBuilder::BuildF64SConvertI64(Node* input) {
1469 return BuildIntToFloatConversionInstruction(
1470 input, ExternalReference::wasm_int64_to_float64(jsgraph()->isolate()),
1471 MachineRepresentation::kWord64, MachineType::Float64());
1472}
1473Node* WasmGraphBuilder::BuildF64UConvertI64(Node* input) {
1474 return BuildIntToFloatConversionInstruction(
1475 input, ExternalReference::wasm_uint64_to_float64(jsgraph()->isolate()),
1476 MachineRepresentation::kWord64, MachineType::Float64());
1477}
1478
1479Node* WasmGraphBuilder::BuildIntToFloatConversionInstruction(
1480 Node* input, ExternalReference ref,
1481 MachineRepresentation parameter_representation,
1482 const MachineType result_type) {
1483 Node* stack_slot_param = graph()->NewNode(
1484 jsgraph()->machine()->StackSlot(parameter_representation));
1485 Node* stack_slot_result = graph()->NewNode(
1486 jsgraph()->machine()->StackSlot(result_type.representation()));
1487 const Operator* store_op = jsgraph()->machine()->Store(
1488 StoreRepresentation(parameter_representation, kNoWriteBarrier));
1489 *effect_ =
1490 graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0),
1491 input, *effect_, *control_);
1492 MachineSignature::Builder sig_builder(jsgraph()->zone(), 0, 2);
1493 sig_builder.AddParam(MachineType::Pointer());
1494 sig_builder.AddParam(MachineType::Pointer());
1495 Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
1496 Node* args[] = {function, stack_slot_param, stack_slot_result};
1497 BuildCCall(sig_builder.Build(), args);
1498 const Operator* load_op = jsgraph()->machine()->Load(result_type);
1499 Node* load =
1500 graph()->NewNode(load_op, stack_slot_result, jsgraph()->Int32Constant(0),
1501 *effect_, *control_);
1502 *effect_ = load;
1503 return load;
1504}
1505
Ben Murdochc5610432016-08-08 18:44:38 +01001506Node* WasmGraphBuilder::BuildI64SConvertF32(Node* input,
1507 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001508 if (jsgraph()->machine()->Is32()) {
1509 return BuildFloatToIntConversionInstruction(
1510 input, ExternalReference::wasm_float32_to_int64(jsgraph()->isolate()),
Ben Murdochc5610432016-08-08 18:44:38 +01001511 MachineRepresentation::kFloat32, MachineType::Int64(), position);
Ben Murdochda12d292016-06-02 14:46:10 +01001512 } else {
1513 Node* trunc = graph()->NewNode(
1514 jsgraph()->machine()->TryTruncateFloat32ToInt64(), input);
1515 Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc);
1516 Node* overflow =
1517 graph()->NewNode(jsgraph()->common()->Projection(1), trunc);
Ben Murdochc5610432016-08-08 18:44:38 +01001518 trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001519 return result;
1520 }
1521}
1522
Ben Murdochc5610432016-08-08 18:44:38 +01001523Node* WasmGraphBuilder::BuildI64UConvertF32(Node* input,
1524 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001525 if (jsgraph()->machine()->Is32()) {
1526 return BuildFloatToIntConversionInstruction(
1527 input, ExternalReference::wasm_float32_to_uint64(jsgraph()->isolate()),
Ben Murdochc5610432016-08-08 18:44:38 +01001528 MachineRepresentation::kFloat32, MachineType::Int64(), position);
Ben Murdochda12d292016-06-02 14:46:10 +01001529 } else {
1530 Node* trunc = graph()->NewNode(
1531 jsgraph()->machine()->TryTruncateFloat32ToUint64(), input);
1532 Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc);
1533 Node* overflow =
1534 graph()->NewNode(jsgraph()->common()->Projection(1), trunc);
Ben Murdochc5610432016-08-08 18:44:38 +01001535 trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001536 return result;
1537 }
1538}
1539
Ben Murdochc5610432016-08-08 18:44:38 +01001540Node* WasmGraphBuilder::BuildI64SConvertF64(Node* input,
1541 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001542 if (jsgraph()->machine()->Is32()) {
1543 return BuildFloatToIntConversionInstruction(
1544 input, ExternalReference::wasm_float64_to_int64(jsgraph()->isolate()),
Ben Murdochc5610432016-08-08 18:44:38 +01001545 MachineRepresentation::kFloat64, MachineType::Int64(), position);
Ben Murdochda12d292016-06-02 14:46:10 +01001546 } else {
1547 Node* trunc = graph()->NewNode(
1548 jsgraph()->machine()->TryTruncateFloat64ToInt64(), input);
1549 Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc);
1550 Node* overflow =
1551 graph()->NewNode(jsgraph()->common()->Projection(1), trunc);
Ben Murdochc5610432016-08-08 18:44:38 +01001552 trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001553 return result;
1554 }
1555}
1556
Ben Murdochc5610432016-08-08 18:44:38 +01001557Node* WasmGraphBuilder::BuildI64UConvertF64(Node* input,
1558 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001559 if (jsgraph()->machine()->Is32()) {
1560 return BuildFloatToIntConversionInstruction(
1561 input, ExternalReference::wasm_float64_to_uint64(jsgraph()->isolate()),
Ben Murdochc5610432016-08-08 18:44:38 +01001562 MachineRepresentation::kFloat64, MachineType::Int64(), position);
Ben Murdochda12d292016-06-02 14:46:10 +01001563 } else {
1564 Node* trunc = graph()->NewNode(
1565 jsgraph()->machine()->TryTruncateFloat64ToUint64(), input);
1566 Node* result = graph()->NewNode(jsgraph()->common()->Projection(0), trunc);
1567 Node* overflow =
1568 graph()->NewNode(jsgraph()->common()->Projection(1), trunc);
Ben Murdochc5610432016-08-08 18:44:38 +01001569 trap_->ZeroCheck64(wasm::kTrapFloatUnrepresentable, overflow, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001570 return result;
1571 }
1572}
1573
1574Node* WasmGraphBuilder::BuildFloatToIntConversionInstruction(
1575 Node* input, ExternalReference ref,
1576 MachineRepresentation parameter_representation,
Ben Murdochc5610432016-08-08 18:44:38 +01001577 const MachineType result_type, wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001578 Node* stack_slot_param = graph()->NewNode(
1579 jsgraph()->machine()->StackSlot(parameter_representation));
1580 Node* stack_slot_result = graph()->NewNode(
1581 jsgraph()->machine()->StackSlot(result_type.representation()));
1582 const Operator* store_op = jsgraph()->machine()->Store(
1583 StoreRepresentation(parameter_representation, kNoWriteBarrier));
1584 *effect_ =
1585 graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0),
1586 input, *effect_, *control_);
1587 MachineSignature::Builder sig_builder(jsgraph()->zone(), 1, 2);
1588 sig_builder.AddReturn(MachineType::Int32());
1589 sig_builder.AddParam(MachineType::Pointer());
1590 sig_builder.AddParam(MachineType::Pointer());
1591 Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
1592 Node* args[] = {function, stack_slot_param, stack_slot_result};
1593 trap_->ZeroCheck32(wasm::kTrapFloatUnrepresentable,
Ben Murdochc5610432016-08-08 18:44:38 +01001594 BuildCCall(sig_builder.Build(), args), position);
Ben Murdochda12d292016-06-02 14:46:10 +01001595 const Operator* load_op = jsgraph()->machine()->Load(result_type);
1596 Node* load =
1597 graph()->NewNode(load_op, stack_slot_result, jsgraph()->Int32Constant(0),
1598 *effect_, *control_);
1599 *effect_ = load;
1600 return load;
1601}
1602
Ben Murdochc5610432016-08-08 18:44:38 +01001603Node* WasmGraphBuilder::BuildI32DivS(Node* left, Node* right,
1604 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001605 MachineOperatorBuilder* m = jsgraph()->machine();
Ben Murdochc5610432016-08-08 18:44:38 +01001606 trap_->ZeroCheck32(wasm::kTrapDivByZero, right, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001607 Node* before = *control_;
1608 Node* denom_is_m1;
1609 Node* denom_is_not_m1;
1610 Branch(
1611 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
1612 &denom_is_m1, &denom_is_not_m1);
1613 *control_ = denom_is_m1;
Ben Murdochc5610432016-08-08 18:44:38 +01001614 trap_->TrapIfEq32(wasm::kTrapDivUnrepresentable, left, kMinInt, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001615 if (*control_ != denom_is_m1) {
1616 *control_ = graph()->NewNode(jsgraph()->common()->Merge(2), denom_is_not_m1,
1617 *control_);
1618 } else {
1619 *control_ = before;
1620 }
1621 return graph()->NewNode(m->Int32Div(), left, right, *control_);
1622}
1623
Ben Murdochc5610432016-08-08 18:44:38 +01001624Node* WasmGraphBuilder::BuildI32RemS(Node* left, Node* right,
1625 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001626 MachineOperatorBuilder* m = jsgraph()->machine();
Ben Murdochda12d292016-06-02 14:46:10 +01001627
Ben Murdochc5610432016-08-08 18:44:38 +01001628 trap_->ZeroCheck32(wasm::kTrapRemByZero, right, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001629
1630 Diamond d(
1631 graph(), jsgraph()->common(),
1632 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
1633 BranchHint::kFalse);
1634 d.Chain(*control_);
1635
1636 return d.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
1637 graph()->NewNode(m->Int32Mod(), left, right, d.if_false));
1638}
1639
Ben Murdochc5610432016-08-08 18:44:38 +01001640Node* WasmGraphBuilder::BuildI32DivU(Node* left, Node* right,
1641 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001642 MachineOperatorBuilder* m = jsgraph()->machine();
Ben Murdochc5610432016-08-08 18:44:38 +01001643 return graph()->NewNode(
1644 m->Uint32Div(), left, right,
1645 trap_->ZeroCheck32(wasm::kTrapDivByZero, right, position));
Ben Murdochda12d292016-06-02 14:46:10 +01001646}
1647
Ben Murdochc5610432016-08-08 18:44:38 +01001648Node* WasmGraphBuilder::BuildI32RemU(Node* left, Node* right,
1649 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001650 MachineOperatorBuilder* m = jsgraph()->machine();
Ben Murdochc5610432016-08-08 18:44:38 +01001651 return graph()->NewNode(
1652 m->Uint32Mod(), left, right,
1653 trap_->ZeroCheck32(wasm::kTrapRemByZero, right, position));
Ben Murdochda12d292016-06-02 14:46:10 +01001654}
1655
Ben Murdochc5610432016-08-08 18:44:38 +01001656Node* WasmGraphBuilder::BuildI32AsmjsDivS(Node* left, Node* right) {
1657 MachineOperatorBuilder* m = jsgraph()->machine();
1658 // asm.js semantics return 0 on divide or mod by zero.
1659 if (m->Int32DivIsSafe()) {
1660 // The hardware instruction does the right thing (e.g. arm).
1661 return graph()->NewNode(m->Int32Div(), left, right, graph()->start());
1662 }
1663
1664 // Check denominator for zero.
1665 Diamond z(
1666 graph(), jsgraph()->common(),
1667 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
1668 BranchHint::kFalse);
1669
1670 // Check numerator for -1. (avoid minint / -1 case).
1671 Diamond n(
1672 graph(), jsgraph()->common(),
1673 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
1674 BranchHint::kFalse);
1675
1676 Node* div = graph()->NewNode(m->Int32Div(), left, right, z.if_false);
1677 Node* neg =
1678 graph()->NewNode(m->Int32Sub(), jsgraph()->Int32Constant(0), left);
1679
1680 return n.Phi(
1681 MachineRepresentation::kWord32, neg,
1682 z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0), div));
1683}
1684
1685Node* WasmGraphBuilder::BuildI32AsmjsRemS(Node* left, Node* right) {
1686 MachineOperatorBuilder* m = jsgraph()->machine();
1687 // asm.js semantics return 0 on divide or mod by zero.
1688 // Explicit check for x % 0.
1689 Diamond z(
1690 graph(), jsgraph()->common(),
1691 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
1692 BranchHint::kFalse);
1693
1694 // Explicit check for x % -1.
1695 Diamond d(
1696 graph(), jsgraph()->common(),
1697 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
1698 BranchHint::kFalse);
1699 d.Chain(z.if_false);
1700
1701 return z.Phi(
1702 MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
1703 d.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
1704 graph()->NewNode(m->Int32Mod(), left, right, d.if_false)));
1705}
1706
1707Node* WasmGraphBuilder::BuildI32AsmjsDivU(Node* left, Node* right) {
1708 MachineOperatorBuilder* m = jsgraph()->machine();
1709 // asm.js semantics return 0 on divide or mod by zero.
1710 if (m->Uint32DivIsSafe()) {
1711 // The hardware instruction does the right thing (e.g. arm).
1712 return graph()->NewNode(m->Uint32Div(), left, right, graph()->start());
1713 }
1714
1715 // Explicit check for x % 0.
1716 Diamond z(
1717 graph(), jsgraph()->common(),
1718 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
1719 BranchHint::kFalse);
1720
1721 return z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
1722 graph()->NewNode(jsgraph()->machine()->Uint32Div(), left, right,
1723 z.if_false));
1724}
1725
1726Node* WasmGraphBuilder::BuildI32AsmjsRemU(Node* left, Node* right) {
1727 MachineOperatorBuilder* m = jsgraph()->machine();
1728 // asm.js semantics return 0 on divide or mod by zero.
1729 // Explicit check for x % 0.
1730 Diamond z(
1731 graph(), jsgraph()->common(),
1732 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
1733 BranchHint::kFalse);
1734
1735 Node* rem = graph()->NewNode(jsgraph()->machine()->Uint32Mod(), left, right,
1736 z.if_false);
1737 return z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
1738 rem);
1739}
1740
1741Node* WasmGraphBuilder::BuildI64DivS(Node* left, Node* right,
1742 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001743 if (jsgraph()->machine()->Is32()) {
1744 return BuildDiv64Call(
1745 left, right, ExternalReference::wasm_int64_div(jsgraph()->isolate()),
Ben Murdochc5610432016-08-08 18:44:38 +01001746 MachineType::Int64(), wasm::kTrapDivByZero, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001747 }
Ben Murdochc5610432016-08-08 18:44:38 +01001748 trap_->ZeroCheck64(wasm::kTrapDivByZero, right, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001749 Node* before = *control_;
1750 Node* denom_is_m1;
1751 Node* denom_is_not_m1;
1752 Branch(graph()->NewNode(jsgraph()->machine()->Word64Equal(), right,
1753 jsgraph()->Int64Constant(-1)),
1754 &denom_is_m1, &denom_is_not_m1);
1755 *control_ = denom_is_m1;
1756 trap_->TrapIfEq64(wasm::kTrapDivUnrepresentable, left,
Ben Murdochc5610432016-08-08 18:44:38 +01001757 std::numeric_limits<int64_t>::min(), position);
Ben Murdochda12d292016-06-02 14:46:10 +01001758 if (*control_ != denom_is_m1) {
1759 *control_ = graph()->NewNode(jsgraph()->common()->Merge(2), denom_is_not_m1,
1760 *control_);
1761 } else {
1762 *control_ = before;
1763 }
1764 return graph()->NewNode(jsgraph()->machine()->Int64Div(), left, right,
1765 *control_);
1766}
1767
Ben Murdochc5610432016-08-08 18:44:38 +01001768Node* WasmGraphBuilder::BuildI64RemS(Node* left, Node* right,
1769 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001770 if (jsgraph()->machine()->Is32()) {
1771 return BuildDiv64Call(
1772 left, right, ExternalReference::wasm_int64_mod(jsgraph()->isolate()),
Ben Murdochc5610432016-08-08 18:44:38 +01001773 MachineType::Int64(), wasm::kTrapRemByZero, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001774 }
Ben Murdochc5610432016-08-08 18:44:38 +01001775 trap_->ZeroCheck64(wasm::kTrapRemByZero, right, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001776 Diamond d(jsgraph()->graph(), jsgraph()->common(),
1777 graph()->NewNode(jsgraph()->machine()->Word64Equal(), right,
1778 jsgraph()->Int64Constant(-1)));
1779
1780 Node* rem = graph()->NewNode(jsgraph()->machine()->Int64Mod(), left, right,
1781 d.if_false);
1782
1783 return d.Phi(MachineRepresentation::kWord64, jsgraph()->Int64Constant(0),
1784 rem);
1785}
1786
Ben Murdochc5610432016-08-08 18:44:38 +01001787Node* WasmGraphBuilder::BuildI64DivU(Node* left, Node* right,
1788 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001789 if (jsgraph()->machine()->Is32()) {
1790 return BuildDiv64Call(
1791 left, right, ExternalReference::wasm_uint64_div(jsgraph()->isolate()),
Ben Murdochc5610432016-08-08 18:44:38 +01001792 MachineType::Int64(), wasm::kTrapDivByZero, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001793 }
Ben Murdochc5610432016-08-08 18:44:38 +01001794 return graph()->NewNode(
1795 jsgraph()->machine()->Uint64Div(), left, right,
1796 trap_->ZeroCheck64(wasm::kTrapDivByZero, right, position));
Ben Murdochda12d292016-06-02 14:46:10 +01001797}
Ben Murdochc5610432016-08-08 18:44:38 +01001798Node* WasmGraphBuilder::BuildI64RemU(Node* left, Node* right,
1799 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001800 if (jsgraph()->machine()->Is32()) {
1801 return BuildDiv64Call(
1802 left, right, ExternalReference::wasm_uint64_mod(jsgraph()->isolate()),
Ben Murdochc5610432016-08-08 18:44:38 +01001803 MachineType::Int64(), wasm::kTrapRemByZero, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001804 }
Ben Murdochc5610432016-08-08 18:44:38 +01001805 return graph()->NewNode(
1806 jsgraph()->machine()->Uint64Mod(), left, right,
1807 trap_->ZeroCheck64(wasm::kTrapRemByZero, right, position));
Ben Murdochda12d292016-06-02 14:46:10 +01001808}
1809
1810Node* WasmGraphBuilder::BuildDiv64Call(Node* left, Node* right,
1811 ExternalReference ref,
Ben Murdochc5610432016-08-08 18:44:38 +01001812 MachineType result_type, int trap_zero,
1813 wasm::WasmCodePosition position) {
Ben Murdochda12d292016-06-02 14:46:10 +01001814 Node* stack_slot_dst = graph()->NewNode(
1815 jsgraph()->machine()->StackSlot(MachineRepresentation::kWord64));
1816 Node* stack_slot_src = graph()->NewNode(
1817 jsgraph()->machine()->StackSlot(MachineRepresentation::kWord64));
1818
1819 const Operator* store_op = jsgraph()->machine()->Store(
1820 StoreRepresentation(MachineRepresentation::kWord64, kNoWriteBarrier));
1821 *effect_ =
1822 graph()->NewNode(store_op, stack_slot_dst, jsgraph()->Int32Constant(0),
1823 left, *effect_, *control_);
1824 *effect_ =
1825 graph()->NewNode(store_op, stack_slot_src, jsgraph()->Int32Constant(0),
1826 right, *effect_, *control_);
1827
1828 MachineSignature::Builder sig_builder(jsgraph()->zone(), 1, 2);
1829 sig_builder.AddReturn(MachineType::Int32());
1830 sig_builder.AddParam(MachineType::Pointer());
1831 sig_builder.AddParam(MachineType::Pointer());
1832
1833 Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
1834 Node* args[] = {function, stack_slot_dst, stack_slot_src};
1835
1836 Node* call = BuildCCall(sig_builder.Build(), args);
1837
1838 // TODO(wasm): This can get simpler if we have a specialized runtime call to
1839 // throw WASM exceptions by trap code instead of by string.
Ben Murdochc5610432016-08-08 18:44:38 +01001840 trap_->ZeroCheck32(static_cast<wasm::TrapReason>(trap_zero), call, position);
1841 trap_->TrapIfEq32(wasm::kTrapDivUnrepresentable, call, -1, position);
Ben Murdochda12d292016-06-02 14:46:10 +01001842 const Operator* load_op = jsgraph()->machine()->Load(result_type);
1843 Node* load =
1844 graph()->NewNode(load_op, stack_slot_dst, jsgraph()->Int32Constant(0),
Ben Murdoch097c5b22016-05-18 11:27:45 +01001845 *effect_, *control_);
1846 *effect_ = load;
1847 return load;
1848}
1849
1850Node* WasmGraphBuilder::BuildCCall(MachineSignature* sig, Node** args) {
1851 const size_t params = sig->parameter_count();
1852 const size_t extra = 2; // effect and control inputs.
1853 const size_t count = 1 + params + extra;
1854
1855 // Reallocate the buffer to make space for extra inputs.
Ben Murdochda12d292016-06-02 14:46:10 +01001856 args = Realloc(args, 1 + params, count);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001857
1858 // Add effect and control inputs.
1859 args[params + 1] = *effect_;
1860 args[params + 2] = *control_;
1861
1862 CallDescriptor* desc =
1863 Linkage::GetSimplifiedCDescriptor(jsgraph()->zone(), sig);
1864
1865 const Operator* op = jsgraph()->common()->Call(desc);
1866 Node* call = graph()->NewNode(op, static_cast<int>(count), args);
1867 *effect_ = call;
1868 return call;
1869}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001870
Ben Murdochc5610432016-08-08 18:44:38 +01001871Node* WasmGraphBuilder::BuildWasmCall(wasm::FunctionSig* sig, Node** args,
1872 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001873 const size_t params = sig->parameter_count();
1874 const size_t extra = 2; // effect and control inputs.
1875 const size_t count = 1 + params + extra;
1876
1877 // Reallocate the buffer to make space for extra inputs.
Ben Murdochda12d292016-06-02 14:46:10 +01001878 args = Realloc(args, 1 + params, count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001879
1880 // Add effect and control inputs.
1881 args[params + 1] = *effect_;
1882 args[params + 2] = *control_;
1883
Ben Murdoch097c5b22016-05-18 11:27:45 +01001884 CallDescriptor* descriptor =
1885 wasm::ModuleEnv::GetWasmCallDescriptor(jsgraph()->zone(), sig);
1886 const Operator* op = jsgraph()->common()->Call(descriptor);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001887 Node* call = graph()->NewNode(op, static_cast<int>(count), args);
Ben Murdochc5610432016-08-08 18:44:38 +01001888 SetSourcePosition(call, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001889
1890 *effect_ = call;
1891 return call;
1892}
1893
Ben Murdochc5610432016-08-08 18:44:38 +01001894Node* WasmGraphBuilder::CallDirect(uint32_t index, Node** args,
1895 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001896 DCHECK_NULL(args[0]);
1897
1898 // Add code object as constant.
Ben Murdochc5610432016-08-08 18:44:38 +01001899 args[0] = HeapConstant(module_->GetFunctionCode(index));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001900 wasm::FunctionSig* sig = module_->GetFunctionSignature(index);
1901
Ben Murdochc5610432016-08-08 18:44:38 +01001902 return BuildWasmCall(sig, args, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001903}
1904
Ben Murdochc5610432016-08-08 18:44:38 +01001905Node* WasmGraphBuilder::CallImport(uint32_t index, Node** args,
1906 wasm::WasmCodePosition position) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001907 DCHECK_NULL(args[0]);
1908
1909 // Add code object as constant.
Ben Murdochc5610432016-08-08 18:44:38 +01001910 args[0] = HeapConstant(module_->GetImportCode(index));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001911 wasm::FunctionSig* sig = module_->GetImportSignature(index);
1912
Ben Murdochc5610432016-08-08 18:44:38 +01001913 return BuildWasmCall(sig, args, position);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001914}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001915
Ben Murdochc5610432016-08-08 18:44:38 +01001916Node* WasmGraphBuilder::CallIndirect(uint32_t index, Node** args,
1917 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001918 DCHECK_NOT_NULL(args[0]);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001919 DCHECK(module_ && module_->instance);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001920
1921 MachineOperatorBuilder* machine = jsgraph()->machine();
1922
1923 // Compute the code object by loading it from the function table.
1924 Node* key = args[0];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001925
1926 // Bounds check the index.
1927 int table_size = static_cast<int>(module_->FunctionTableSize());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001928 if (table_size > 0) {
1929 // Bounds check against the table size.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001930 Node* size = Int32Constant(static_cast<int>(table_size));
1931 Node* in_bounds = graph()->NewNode(machine->Uint32LessThan(), key, size);
Ben Murdochc5610432016-08-08 18:44:38 +01001932 trap_->AddTrapIfFalse(wasm::kTrapFuncInvalid, in_bounds, position);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001933 } else {
1934 // No function table. Generate a trap and return a constant.
Ben Murdochc5610432016-08-08 18:44:38 +01001935 trap_->AddTrapIfFalse(wasm::kTrapFuncInvalid, Int32Constant(0), position);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001936 return trap_->GetTrapValue(module_->GetSignature(index));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001937 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001938 Node* table = FunctionTable();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001939
1940 // Load signature from the table and check.
1941 // The table is a FixedArray; signatures are encoded as SMIs.
1942 // [sig1, sig2, sig3, ...., code1, code2, code3 ...]
1943 ElementAccess access = AccessBuilder::ForFixedArrayElement();
1944 const int fixed_offset = access.header_size - access.tag();
1945 {
1946 Node* load_sig = graph()->NewNode(
1947 machine->Load(MachineType::AnyTagged()), table,
1948 graph()->NewNode(machine->Int32Add(),
1949 graph()->NewNode(machine->Word32Shl(), key,
1950 Int32Constant(kPointerSizeLog2)),
1951 Int32Constant(fixed_offset)),
1952 *effect_, *control_);
1953 Node* sig_match = graph()->NewNode(machine->WordEqual(), load_sig,
1954 jsgraph()->SmiConstant(index));
Ben Murdochc5610432016-08-08 18:44:38 +01001955 trap_->AddTrapIfFalse(wasm::kTrapFuncSigMismatch, sig_match, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001956 }
1957
1958 // Load code object from the table.
1959 int offset = fixed_offset + kPointerSize * table_size;
1960 Node* load_code = graph()->NewNode(
1961 machine->Load(MachineType::AnyTagged()), table,
1962 graph()->NewNode(machine->Int32Add(),
1963 graph()->NewNode(machine->Word32Shl(), key,
1964 Int32Constant(kPointerSizeLog2)),
1965 Int32Constant(offset)),
1966 *effect_, *control_);
1967
1968 args[0] = load_code;
1969 wasm::FunctionSig* sig = module_->GetSignature(index);
Ben Murdochc5610432016-08-08 18:44:38 +01001970 return BuildWasmCall(sig, args, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001971}
1972
Ben Murdochda12d292016-06-02 14:46:10 +01001973Node* WasmGraphBuilder::BuildI32Rol(Node* left, Node* right) {
1974 // Implement Rol by Ror since TurboFan does not have Rol opcode.
1975 // TODO(weiliang): support Word32Rol opcode in TurboFan.
1976 Int32Matcher m(right);
1977 if (m.HasValue()) {
1978 return Binop(wasm::kExprI32Ror, left,
1979 jsgraph()->Int32Constant(32 - m.Value()));
1980 } else {
1981 return Binop(wasm::kExprI32Ror, left,
1982 Binop(wasm::kExprI32Sub, jsgraph()->Int32Constant(32), right));
1983 }
1984}
1985
1986Node* WasmGraphBuilder::BuildI64Rol(Node* left, Node* right) {
1987 // Implement Rol by Ror since TurboFan does not have Rol opcode.
1988 // TODO(weiliang): support Word64Rol opcode in TurboFan.
1989 Int64Matcher m(right);
1990 if (m.HasValue()) {
1991 return Binop(wasm::kExprI64Ror, left,
1992 jsgraph()->Int64Constant(64 - m.Value()));
1993 } else {
1994 return Binop(wasm::kExprI64Ror, left,
1995 Binop(wasm::kExprI64Sub, jsgraph()->Int64Constant(64), right));
1996 }
1997}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001998
1999Node* WasmGraphBuilder::Invert(Node* node) {
Ben Murdochda12d292016-06-02 14:46:10 +01002000 return Unop(wasm::kExprI32Eqz, node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002001}
2002
Ben Murdochc5610432016-08-08 18:44:38 +01002003Node* WasmGraphBuilder::BuildChangeInt32ToTagged(Node* value) {
2004 MachineOperatorBuilder* machine = jsgraph()->machine();
2005 CommonOperatorBuilder* common = jsgraph()->common();
2006
2007 if (machine->Is64()) {
2008 return BuildChangeInt32ToSmi(value);
2009 }
2010
2011 Node* add = graph()->NewNode(machine->Int32AddWithOverflow(), value, value);
2012
2013 Node* ovf = graph()->NewNode(common->Projection(1), add);
2014 Node* branch = graph()->NewNode(common->Branch(BranchHint::kFalse), ovf,
2015 graph()->start());
2016
2017 Node* if_true = graph()->NewNode(common->IfTrue(), branch);
2018 Node* vtrue = BuildAllocateHeapNumberWithValue(
2019 graph()->NewNode(machine->ChangeInt32ToFloat64(), value), if_true);
2020
2021 Node* if_false = graph()->NewNode(common->IfFalse(), branch);
2022 Node* vfalse = graph()->NewNode(common->Projection(0), add);
2023
2024 Node* merge = graph()->NewNode(common->Merge(2), if_true, if_false);
2025 Node* phi = graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2),
2026 vtrue, vfalse, merge);
2027 return phi;
2028}
2029
2030Node* WasmGraphBuilder::BuildChangeFloat64ToTagged(Node* value) {
2031 MachineOperatorBuilder* machine = jsgraph()->machine();
2032 CommonOperatorBuilder* common = jsgraph()->common();
2033
2034 Node* value32 = graph()->NewNode(machine->RoundFloat64ToInt32(), value);
2035 Node* check_same = graph()->NewNode(
2036 machine->Float64Equal(), value,
2037 graph()->NewNode(machine->ChangeInt32ToFloat64(), value32));
2038 Node* branch_same =
2039 graph()->NewNode(common->Branch(), check_same, graph()->start());
2040
2041 Node* if_smi = graph()->NewNode(common->IfTrue(), branch_same);
2042 Node* vsmi;
2043 Node* if_box = graph()->NewNode(common->IfFalse(), branch_same);
2044 Node* vbox;
2045
2046 // We only need to check for -0 if the {value} can potentially contain -0.
2047 Node* check_zero = graph()->NewNode(machine->Word32Equal(), value32,
2048 jsgraph()->Int32Constant(0));
2049 Node* branch_zero =
2050 graph()->NewNode(common->Branch(BranchHint::kFalse), check_zero, if_smi);
2051
2052 Node* if_zero = graph()->NewNode(common->IfTrue(), branch_zero);
2053 Node* if_notzero = graph()->NewNode(common->IfFalse(), branch_zero);
2054
2055 // In case of 0, we need to check the high bits for the IEEE -0 pattern.
2056 Node* check_negative = graph()->NewNode(
2057 machine->Int32LessThan(),
2058 graph()->NewNode(machine->Float64ExtractHighWord32(), value),
2059 jsgraph()->Int32Constant(0));
2060 Node* branch_negative = graph()->NewNode(common->Branch(BranchHint::kFalse),
2061 check_negative, if_zero);
2062
2063 Node* if_negative = graph()->NewNode(common->IfTrue(), branch_negative);
2064 Node* if_notnegative = graph()->NewNode(common->IfFalse(), branch_negative);
2065
2066 // We need to create a box for negative 0.
2067 if_smi = graph()->NewNode(common->Merge(2), if_notzero, if_notnegative);
2068 if_box = graph()->NewNode(common->Merge(2), if_box, if_negative);
2069
2070 // On 64-bit machines we can just wrap the 32-bit integer in a smi, for 32-bit
2071 // machines we need to deal with potential overflow and fallback to boxing.
2072 if (machine->Is64()) {
2073 vsmi = BuildChangeInt32ToSmi(value32);
2074 } else {
2075 Node* smi_tag =
2076 graph()->NewNode(machine->Int32AddWithOverflow(), value32, value32);
2077
2078 Node* check_ovf = graph()->NewNode(common->Projection(1), smi_tag);
2079 Node* branch_ovf =
2080 graph()->NewNode(common->Branch(BranchHint::kFalse), check_ovf, if_smi);
2081
2082 Node* if_ovf = graph()->NewNode(common->IfTrue(), branch_ovf);
2083 if_box = graph()->NewNode(common->Merge(2), if_ovf, if_box);
2084
2085 if_smi = graph()->NewNode(common->IfFalse(), branch_ovf);
2086 vsmi = graph()->NewNode(common->Projection(0), smi_tag);
2087 }
2088
2089 // Allocate the box for the {value}.
2090 vbox = BuildAllocateHeapNumberWithValue(value, if_box);
2091
2092 Node* control = graph()->NewNode(common->Merge(2), if_smi, if_box);
2093 value = graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2), vsmi,
2094 vbox, control);
2095 return value;
2096}
2097
2098Node* WasmGraphBuilder::ToJS(Node* node, Node* context, wasm::LocalType type) {
2099 switch (type) {
2100 case wasm::kAstI32:
2101 return BuildChangeInt32ToTagged(node);
2102 case wasm::kAstI64:
2103 // TODO(titzer): i64->JS has no good solution right now. Using lower 32
2104 // bits.
2105 if (jsgraph()->machine()->Is64()) {
2106 // On 32 bit platforms we do not have to do the truncation because the
2107 // node we get in as a parameter only contains the low word anyways.
2108 node = graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(),
2109 node);
2110 }
2111 return BuildChangeInt32ToTagged(node);
2112 case wasm::kAstF32:
2113 node = graph()->NewNode(jsgraph()->machine()->ChangeFloat32ToFloat64(),
2114 node);
2115 return BuildChangeFloat64ToTagged(node);
2116 case wasm::kAstF64:
2117 return BuildChangeFloat64ToTagged(node);
2118 case wasm::kAstStmt:
2119 return jsgraph()->UndefinedConstant();
2120 default:
2121 UNREACHABLE();
2122 return nullptr;
2123 }
2124}
2125
2126Node* WasmGraphBuilder::BuildJavaScriptToNumber(Node* node, Node* context,
2127 Node* effect, Node* control) {
2128 Callable callable = CodeFactory::ToNumber(jsgraph()->isolate());
2129 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
2130 jsgraph()->isolate(), jsgraph()->zone(), callable.descriptor(), 0,
2131 CallDescriptor::kNoFlags, Operator::kNoProperties);
2132 Node* stub_code = jsgraph()->HeapConstant(callable.code());
2133
2134 Node* result = graph()->NewNode(jsgraph()->common()->Call(desc), stub_code,
2135 node, context, effect, control);
2136
2137 *control_ = result;
2138 *effect_ = result;
2139
2140 return result;
2141}
2142
2143bool CanCover(Node* value, IrOpcode::Value opcode) {
2144 if (value->opcode() != opcode) return false;
2145 bool first = true;
2146 for (Edge const edge : value->use_edges()) {
2147 if (NodeProperties::IsControlEdge(edge)) continue;
2148 if (NodeProperties::IsEffectEdge(edge)) continue;
2149 DCHECK(NodeProperties::IsValueEdge(edge));
2150 if (!first) return false;
2151 first = false;
2152 }
2153 return true;
2154}
2155
2156Node* WasmGraphBuilder::BuildChangeTaggedToFloat64(Node* value) {
2157 MachineOperatorBuilder* machine = jsgraph()->machine();
2158 CommonOperatorBuilder* common = jsgraph()->common();
2159
2160 if (CanCover(value, IrOpcode::kJSToNumber)) {
2161 // ChangeTaggedToFloat64(JSToNumber(x)) =>
2162 // if IsSmi(x) then ChangeSmiToFloat64(x)
2163 // else let y = JSToNumber(x) in
2164 // if IsSmi(y) then ChangeSmiToFloat64(y)
2165 // else BuildLoadHeapNumberValue(y)
2166 Node* object = NodeProperties::GetValueInput(value, 0);
2167 Node* context = NodeProperties::GetContextInput(value);
2168 Node* frame_state = NodeProperties::GetFrameStateInput(value, 0);
2169 Node* effect = NodeProperties::GetEffectInput(value);
2170 Node* control = NodeProperties::GetControlInput(value);
2171
2172 const Operator* merge_op = common->Merge(2);
2173 const Operator* ephi_op = common->EffectPhi(2);
2174 const Operator* phi_op = common->Phi(MachineRepresentation::kFloat64, 2);
2175
2176 Node* check1 = BuildTestNotSmi(object);
2177 Node* branch1 =
2178 graph()->NewNode(common->Branch(BranchHint::kFalse), check1, control);
2179
2180 Node* if_true1 = graph()->NewNode(common->IfTrue(), branch1);
2181 Node* vtrue1 = graph()->NewNode(value->op(), object, context, frame_state,
2182 effect, if_true1);
2183 Node* etrue1 = vtrue1;
2184
2185 Node* check2 = BuildTestNotSmi(vtrue1);
2186 Node* branch2 = graph()->NewNode(common->Branch(), check2, if_true1);
2187
2188 Node* if_true2 = graph()->NewNode(common->IfTrue(), branch2);
2189 Node* vtrue2 = BuildLoadHeapNumberValue(vtrue1, if_true2);
2190
2191 Node* if_false2 = graph()->NewNode(common->IfFalse(), branch2);
2192 Node* vfalse2 = BuildChangeSmiToFloat64(vtrue1);
2193
2194 if_true1 = graph()->NewNode(merge_op, if_true2, if_false2);
2195 vtrue1 = graph()->NewNode(phi_op, vtrue2, vfalse2, if_true1);
2196
2197 Node* if_false1 = graph()->NewNode(common->IfFalse(), branch1);
2198 Node* vfalse1 = BuildChangeSmiToFloat64(object);
2199 Node* efalse1 = effect;
2200
2201 Node* merge1 = graph()->NewNode(merge_op, if_true1, if_false1);
2202 Node* ephi1 = graph()->NewNode(ephi_op, etrue1, efalse1, merge1);
2203 Node* phi1 = graph()->NewNode(phi_op, vtrue1, vfalse1, merge1);
2204
2205 // Wire the new diamond into the graph, {JSToNumber} can still throw.
2206 NodeProperties::ReplaceUses(value, phi1, ephi1, etrue1, etrue1);
2207
2208 // TODO(mstarzinger): This iteration cuts out the IfSuccess projection from
2209 // the node and places it inside the diamond. Come up with a helper method!
2210 for (Node* use : etrue1->uses()) {
2211 if (use->opcode() == IrOpcode::kIfSuccess) {
2212 use->ReplaceUses(merge1);
2213 NodeProperties::ReplaceControlInput(branch2, use);
2214 }
2215 }
2216 return phi1;
2217 }
2218
2219 Node* check = BuildTestNotSmi(value);
2220 Node* branch = graph()->NewNode(common->Branch(BranchHint::kFalse), check,
2221 graph()->start());
2222
2223 Node* if_not_smi = graph()->NewNode(common->IfTrue(), branch);
2224
2225 Node* vnot_smi;
2226 Node* check_undefined = graph()->NewNode(machine->WordEqual(), value,
2227 jsgraph()->UndefinedConstant());
2228 Node* branch_undefined = graph()->NewNode(common->Branch(BranchHint::kFalse),
2229 check_undefined, if_not_smi);
2230
2231 Node* if_undefined = graph()->NewNode(common->IfTrue(), branch_undefined);
2232 Node* vundefined =
2233 jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN());
2234
2235 Node* if_not_undefined =
2236 graph()->NewNode(common->IfFalse(), branch_undefined);
2237 Node* vheap_number = BuildLoadHeapNumberValue(value, if_not_undefined);
2238
2239 if_not_smi =
2240 graph()->NewNode(common->Merge(2), if_undefined, if_not_undefined);
2241 vnot_smi = graph()->NewNode(common->Phi(MachineRepresentation::kFloat64, 2),
2242 vundefined, vheap_number, if_not_smi);
2243
2244 Node* if_smi = graph()->NewNode(common->IfFalse(), branch);
2245 Node* vfrom_smi = BuildChangeSmiToFloat64(value);
2246
2247 Node* merge = graph()->NewNode(common->Merge(2), if_not_smi, if_smi);
2248 Node* phi = graph()->NewNode(common->Phi(MachineRepresentation::kFloat64, 2),
2249 vnot_smi, vfrom_smi, merge);
2250
2251 return phi;
2252}
2253
2254Node* WasmGraphBuilder::FromJS(Node* node, Node* context,
2255 wasm::LocalType type) {
2256 // Do a JavaScript ToNumber.
2257 Node* num = BuildJavaScriptToNumber(node, context, *effect_, *control_);
2258
2259 // Change representation.
2260 SimplifiedOperatorBuilder simplified(jsgraph()->zone());
2261 num = BuildChangeTaggedToFloat64(num);
2262
2263 switch (type) {
2264 case wasm::kAstI32: {
2265 num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToWord32(),
2266 num);
2267 break;
2268 }
2269 case wasm::kAstI64:
2270 // TODO(titzer): JS->i64 has no good solution right now. Using 32 bits.
2271 num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToWord32(),
2272 num);
2273 if (jsgraph()->machine()->Is64()) {
2274 // We cannot change an int32 to an int64 on a 32 bit platform. Instead
2275 // we will split the parameter node later.
2276 num = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), num);
2277 }
2278 break;
2279 case wasm::kAstF32:
2280 num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToFloat32(),
2281 num);
2282 break;
2283 case wasm::kAstF64:
2284 break;
2285 case wasm::kAstStmt:
2286 num = jsgraph()->Int32Constant(0);
2287 break;
2288 default:
2289 UNREACHABLE();
2290 return nullptr;
2291 }
2292 return num;
2293}
2294
2295Node* WasmGraphBuilder::BuildChangeInt32ToSmi(Node* value) {
2296 if (jsgraph()->machine()->Is64()) {
2297 value = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), value);
2298 }
2299 return graph()->NewNode(jsgraph()->machine()->WordShl(), value,
2300 BuildSmiShiftBitsConstant());
2301}
2302
2303Node* WasmGraphBuilder::BuildChangeSmiToInt32(Node* value) {
2304 value = graph()->NewNode(jsgraph()->machine()->WordSar(), value,
2305 BuildSmiShiftBitsConstant());
2306 if (jsgraph()->machine()->Is64()) {
2307 value =
2308 graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(), value);
2309 }
2310 return value;
2311}
2312
2313Node* WasmGraphBuilder::BuildChangeSmiToFloat64(Node* value) {
2314 return graph()->NewNode(jsgraph()->machine()->ChangeInt32ToFloat64(),
2315 BuildChangeSmiToInt32(value));
2316}
2317
2318Node* WasmGraphBuilder::BuildTestNotSmi(Node* value) {
2319 STATIC_ASSERT(kSmiTag == 0);
2320 STATIC_ASSERT(kSmiTagMask == 1);
2321 return graph()->NewNode(jsgraph()->machine()->WordAnd(), value,
2322 jsgraph()->IntPtrConstant(kSmiTagMask));
2323}
2324
2325Node* WasmGraphBuilder::BuildSmiShiftBitsConstant() {
2326 return jsgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize);
2327}
2328
2329Node* WasmGraphBuilder::BuildAllocateHeapNumberWithValue(Node* value,
2330 Node* control) {
2331 MachineOperatorBuilder* machine = jsgraph()->machine();
2332 CommonOperatorBuilder* common = jsgraph()->common();
2333 // The AllocateHeapNumberStub does not use the context, so we can safely pass
2334 // in Smi zero here.
2335 Callable callable = CodeFactory::AllocateHeapNumber(jsgraph()->isolate());
2336 Node* target = jsgraph()->HeapConstant(callable.code());
2337 Node* context = jsgraph()->NoContextConstant();
2338 Node* effect = graph()->NewNode(common->BeginRegion(), graph()->start());
2339 if (!allocate_heap_number_operator_.is_set()) {
2340 CallDescriptor* descriptor = Linkage::GetStubCallDescriptor(
2341 jsgraph()->isolate(), jsgraph()->zone(), callable.descriptor(), 0,
2342 CallDescriptor::kNoFlags, Operator::kNoThrow);
2343 allocate_heap_number_operator_.set(common->Call(descriptor));
2344 }
2345 Node* heap_number = graph()->NewNode(allocate_heap_number_operator_.get(),
2346 target, context, effect, control);
2347 Node* store =
2348 graph()->NewNode(machine->Store(StoreRepresentation(
2349 MachineRepresentation::kFloat64, kNoWriteBarrier)),
2350 heap_number, BuildHeapNumberValueIndexConstant(), value,
2351 heap_number, control);
2352 return graph()->NewNode(common->FinishRegion(), heap_number, store);
2353}
2354
2355Node* WasmGraphBuilder::BuildLoadHeapNumberValue(Node* value, Node* control) {
2356 return graph()->NewNode(jsgraph()->machine()->Load(MachineType::Float64()),
2357 value, BuildHeapNumberValueIndexConstant(),
2358 graph()->start(), control);
2359}
2360
2361Node* WasmGraphBuilder::BuildHeapNumberValueIndexConstant() {
2362 return jsgraph()->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag);
2363}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002364
2365void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code,
2366 wasm::FunctionSig* sig) {
Ben Murdochc5610432016-08-08 18:44:38 +01002367 int wasm_count = static_cast<int>(sig->parameter_count());
2368 int param_count;
2369 if (jsgraph()->machine()->Is64()) {
2370 param_count = static_cast<int>(sig->parameter_count());
2371 } else {
2372 param_count = Int64Lowering::GetParameterCountAfterLowering(sig);
2373 }
2374 int count = param_count + 3;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002375 Node** args = Buffer(count);
2376
2377 // Build the start and the JS parameter nodes.
Ben Murdochc5610432016-08-08 18:44:38 +01002378 Node* start = Start(param_count + 5);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002379 *control_ = start;
2380 *effect_ = start;
Ben Murdochda12d292016-06-02 14:46:10 +01002381 // Create the context parameter
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002382 Node* context = graph()->NewNode(
Ben Murdochda12d292016-06-02 14:46:10 +01002383 jsgraph()->common()->Parameter(
Ben Murdochc5610432016-08-08 18:44:38 +01002384 Linkage::GetJSCallContextParamIndex(wasm_count + 1), "%context"),
Ben Murdochda12d292016-06-02 14:46:10 +01002385 graph()->start());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002386
2387 int pos = 0;
Ben Murdochc5610432016-08-08 18:44:38 +01002388 args[pos++] = HeapConstant(wasm_code);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002389
2390 // Convert JS parameters to WASM numbers.
Ben Murdochc5610432016-08-08 18:44:38 +01002391 for (int i = 0; i < wasm_count; i++) {
Ben Murdochda12d292016-06-02 14:46:10 +01002392 Node* param =
2393 graph()->NewNode(jsgraph()->common()->Parameter(i + 1), start);
Ben Murdochc5610432016-08-08 18:44:38 +01002394 Node* wasm_param = FromJS(param, context, sig->GetParam(i));
2395 args[pos++] = wasm_param;
2396 if (jsgraph()->machine()->Is32() && sig->GetParam(i) == wasm::kAstI64) {
2397 // We make up the high word with SAR to get the proper sign extension.
2398 args[pos++] = graph()->NewNode(jsgraph()->machine()->Word32Sar(),
2399 wasm_param, jsgraph()->Int32Constant(31));
2400 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002401 }
2402
2403 args[pos++] = *effect_;
2404 args[pos++] = *control_;
2405
2406 // Call the WASM code.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002407 CallDescriptor* desc =
2408 wasm::ModuleEnv::GetWasmCallDescriptor(jsgraph()->zone(), sig);
Ben Murdochc5610432016-08-08 18:44:38 +01002409 if (jsgraph()->machine()->Is32()) {
2410 desc = wasm::ModuleEnv::GetI32WasmCallDescriptor(jsgraph()->zone(), desc);
2411 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002412 Node* call = graph()->NewNode(jsgraph()->common()->Call(desc), count, args);
Ben Murdochc5610432016-08-08 18:44:38 +01002413 Node* retval = call;
2414 if (jsgraph()->machine()->Is32() && sig->return_count() > 0 &&
2415 sig->GetReturn(0) == wasm::kAstI64) {
2416 // The return values comes as two values, we pick the low word.
2417 retval = graph()->NewNode(jsgraph()->common()->Projection(0), retval);
2418 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002419 Node* jsval =
Ben Murdochc5610432016-08-08 18:44:38 +01002420 ToJS(retval, context,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002421 sig->return_count() == 0 ? wasm::kAstStmt : sig->GetReturn());
2422 Node* ret =
2423 graph()->NewNode(jsgraph()->common()->Return(), jsval, call, start);
2424
2425 MergeControlToEnd(jsgraph(), ret);
2426}
2427
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002428void WasmGraphBuilder::BuildWasmToJSWrapper(Handle<JSFunction> function,
2429 wasm::FunctionSig* sig) {
2430 int js_count = function->shared()->internal_formal_parameter_count();
2431 int wasm_count = static_cast<int>(sig->parameter_count());
Ben Murdochc5610432016-08-08 18:44:38 +01002432 int param_count;
2433 if (jsgraph()->machine()->Is64()) {
2434 param_count = wasm_count;
2435 } else {
2436 param_count = Int64Lowering::GetParameterCountAfterLowering(sig);
2437 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002438
2439 // Build the start and the parameter nodes.
2440 Isolate* isolate = jsgraph()->isolate();
2441 CallDescriptor* desc;
Ben Murdochc5610432016-08-08 18:44:38 +01002442 Node* start = Start(param_count + 3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002443 *effect_ = start;
2444 *control_ = start;
2445 // JS context is the last parameter.
Ben Murdochc5610432016-08-08 18:44:38 +01002446 Node* context = HeapConstant(Handle<Context>(function->context(), isolate));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002447 Node** args = Buffer(wasm_count + 7);
2448
2449 bool arg_count_before_args = false;
2450 bool add_new_target_undefined = false;
2451
2452 int pos = 0;
2453 if (js_count == wasm_count) {
2454 // exact arity match, just call the function directly.
2455 desc = Linkage::GetJSCallDescriptor(graph()->zone(), false, wasm_count + 1,
2456 CallDescriptor::kNoFlags);
2457 arg_count_before_args = false;
2458 add_new_target_undefined = true;
2459 } else {
2460 // Use the Call builtin.
2461 Callable callable = CodeFactory::Call(isolate);
2462 args[pos++] = jsgraph()->HeapConstant(callable.code());
2463 desc = Linkage::GetStubCallDescriptor(isolate, graph()->zone(),
2464 callable.descriptor(), wasm_count + 1,
2465 CallDescriptor::kNoFlags);
2466 arg_count_before_args = true;
2467 }
2468
2469 args[pos++] = jsgraph()->Constant(function); // JS function.
2470 if (arg_count_before_args) {
2471 args[pos++] = jsgraph()->Int32Constant(wasm_count); // argument count
2472 }
2473 // JS receiver.
2474 Handle<Object> global(function->context()->global_object(), isolate);
2475 args[pos++] = jsgraph()->Constant(global);
2476
2477 // Convert WASM numbers to JS values.
Ben Murdochc5610432016-08-08 18:44:38 +01002478 int param_index = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002479 for (int i = 0; i < wasm_count; i++) {
Ben Murdochc5610432016-08-08 18:44:38 +01002480 Node* param =
2481 graph()->NewNode(jsgraph()->common()->Parameter(param_index++), start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002482 args[pos++] = ToJS(param, context, sig->GetParam(i));
Ben Murdochc5610432016-08-08 18:44:38 +01002483 if (jsgraph()->machine()->Is32() && sig->GetParam(i) == wasm::kAstI64) {
2484 // On 32 bit platforms we have to skip the high word of int64 parameters.
2485 param_index++;
2486 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002487 }
2488
2489 if (add_new_target_undefined) {
2490 args[pos++] = jsgraph()->UndefinedConstant(); // new target
2491 }
2492
2493 if (!arg_count_before_args) {
2494 args[pos++] = jsgraph()->Int32Constant(wasm_count); // argument count
2495 }
2496 args[pos++] = context;
2497 args[pos++] = *effect_;
2498 args[pos++] = *control_;
2499
2500 Node* call = graph()->NewNode(jsgraph()->common()->Call(desc), pos, args);
2501
2502 // Convert the return value back.
Ben Murdochc5610432016-08-08 18:44:38 +01002503 Node* ret;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002504 Node* val =
2505 FromJS(call, context,
2506 sig->return_count() == 0 ? wasm::kAstStmt : sig->GetReturn());
Ben Murdochc5610432016-08-08 18:44:38 +01002507 if (jsgraph()->machine()->Is32() && sig->return_count() > 0 &&
2508 sig->GetReturn() == wasm::kAstI64) {
2509 ret = graph()->NewNode(jsgraph()->common()->Return(), val,
2510 graph()->NewNode(jsgraph()->machine()->Word32Sar(),
2511 val, jsgraph()->Int32Constant(31)),
2512 call, start);
2513 } else {
2514 ret = graph()->NewNode(jsgraph()->common()->Return(), val, call, start);
2515 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002516
2517 MergeControlToEnd(jsgraph(), ret);
2518}
2519
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002520Node* WasmGraphBuilder::MemBuffer(uint32_t offset) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002521 DCHECK(module_ && module_->instance);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002522 if (offset == 0) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002523 if (!mem_buffer_) {
Ben Murdochc5610432016-08-08 18:44:38 +01002524 mem_buffer_ = jsgraph()->RelocatableIntPtrConstant(
2525 reinterpret_cast<uintptr_t>(module_->instance->mem_start),
2526 RelocInfo::WASM_MEMORY_REFERENCE);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002527 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002528 return mem_buffer_;
2529 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01002530 return jsgraph()->RelocatableIntPtrConstant(
2531 reinterpret_cast<uintptr_t>(module_->instance->mem_start + offset),
2532 RelocInfo::WASM_MEMORY_REFERENCE);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002533 }
2534}
2535
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002536Node* WasmGraphBuilder::MemSize(uint32_t offset) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002537 DCHECK(module_ && module_->instance);
2538 uint32_t size = static_cast<uint32_t>(module_->instance->mem_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002539 if (offset == 0) {
2540 if (!mem_size_) mem_size_ = jsgraph()->Int32Constant(size);
2541 return mem_size_;
2542 } else {
2543 return jsgraph()->Int32Constant(size + offset);
2544 }
2545}
2546
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002547Node* WasmGraphBuilder::FunctionTable() {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002548 DCHECK(module_ && module_->instance &&
2549 !module_->instance->function_table.is_null());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002550 if (!function_table_) {
Ben Murdochc5610432016-08-08 18:44:38 +01002551 function_table_ = HeapConstant(module_->instance->function_table);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002552 }
2553 return function_table_;
2554}
2555
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002556Node* WasmGraphBuilder::LoadGlobal(uint32_t index) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002557 DCHECK(module_ && module_->instance && module_->instance->globals_start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002558 MachineType mem_type = module_->GetGlobalType(index);
2559 Node* addr = jsgraph()->IntPtrConstant(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002560 reinterpret_cast<uintptr_t>(module_->instance->globals_start +
Ben Murdochda12d292016-06-02 14:46:10 +01002561 module_->module->globals[index].offset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002562 const Operator* op = jsgraph()->machine()->Load(mem_type);
2563 Node* node = graph()->NewNode(op, addr, jsgraph()->Int32Constant(0), *effect_,
2564 *control_);
2565 *effect_ = node;
2566 return node;
2567}
2568
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002569Node* WasmGraphBuilder::StoreGlobal(uint32_t index, Node* val) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002570 DCHECK(module_ && module_->instance && module_->instance->globals_start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002571 MachineType mem_type = module_->GetGlobalType(index);
2572 Node* addr = jsgraph()->IntPtrConstant(
Ben Murdoch097c5b22016-05-18 11:27:45 +01002573 reinterpret_cast<uintptr_t>(module_->instance->globals_start +
Ben Murdochda12d292016-06-02 14:46:10 +01002574 module_->module->globals[index].offset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002575 const Operator* op = jsgraph()->machine()->Store(
2576 StoreRepresentation(mem_type.representation(), kNoWriteBarrier));
2577 Node* node = graph()->NewNode(op, addr, jsgraph()->Int32Constant(0), val,
2578 *effect_, *control_);
2579 *effect_ = node;
2580 return node;
2581}
2582
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002583void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index,
Ben Murdochc5610432016-08-08 18:44:38 +01002584 uint32_t offset,
2585 wasm::WasmCodePosition position) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002586 DCHECK(module_ && module_->instance);
2587 size_t size = module_->instance->mem_size;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002588 byte memsize = wasm::WasmOpcodes::MemSize(memtype);
Ben Murdochc5610432016-08-08 18:44:38 +01002589
Ben Murdoch097c5b22016-05-18 11:27:45 +01002590 if (offset >= size || (static_cast<uint64_t>(offset) + memsize) > size) {
Ben Murdochc5610432016-08-08 18:44:38 +01002591 // The access will always throw (unless memory is grown).
2592 Node* cond = jsgraph()->Int32Constant(0);
2593 trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position);
2594 return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002595 }
2596
Ben Murdochc5610432016-08-08 18:44:38 +01002597 // Check against the effective size.
2598 size_t effective_size = size - offset - memsize;
2599 CHECK(effective_size <= kMaxUInt32);
2600
2601 Uint32Matcher m(index);
2602 if (m.HasValue()) {
2603 uint32_t value = m.Value();
2604 if (value <= effective_size) {
2605 // The bounds check will always succeed.
2606 return;
2607 }
2608 }
2609
2610 Node* cond = graph()->NewNode(
2611 jsgraph()->machine()->Uint32LessThanOrEqual(), index,
2612 jsgraph()->Int32Constant(static_cast<uint32_t>(effective_size)));
2613
2614 trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002615}
2616
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002617Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype,
Ben Murdochc5610432016-08-08 18:44:38 +01002618 Node* index, uint32_t offset,
2619 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002620 Node* load;
Ben Murdochc5610432016-08-08 18:44:38 +01002621 // WASM semantics throw on OOB. Introduce explicit bounds check.
2622 BoundsCheckMem(memtype, index, offset, position);
2623 load = graph()->NewNode(jsgraph()->machine()->Load(memtype),
2624 MemBuffer(offset), index, *effect_, *control_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002625
2626 *effect_ = load;
2627
2628 if (type == wasm::kAstI64 &&
2629 ElementSizeLog2Of(memtype.representation()) < 3) {
2630 // TODO(titzer): TF zeroes the upper bits of 64-bit loads for subword sizes.
2631 if (memtype.IsSigned()) {
2632 // sign extend
2633 load = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load);
2634 } else {
2635 // zero extend
2636 load =
2637 graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), load);
2638 }
2639 }
2640
2641 return load;
2642}
2643
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002644Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index,
Ben Murdochc5610432016-08-08 18:44:38 +01002645 uint32_t offset, Node* val,
2646 wasm::WasmCodePosition position) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002647 Node* store;
Ben Murdochc5610432016-08-08 18:44:38 +01002648 // WASM semantics throw on OOB. Introduce explicit bounds check.
2649 BoundsCheckMem(memtype, index, offset, position);
2650 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier);
2651 store = graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset),
2652 index, val, *effect_, *control_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002653 *effect_ = store;
2654 return store;
2655}
2656
Ben Murdochc5610432016-08-08 18:44:38 +01002657Node* WasmGraphBuilder::BuildAsmjsLoadMem(MachineType type, Node* index) {
2658 // TODO(turbofan): fold bounds checks for constant asm.js loads.
2659 // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish).
2660 const Operator* op = jsgraph()->machine()->CheckedLoad(type);
2661 Node* load = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), *effect_,
2662 *control_);
2663 *effect_ = load;
2664 return load;
2665}
2666
2667Node* WasmGraphBuilder::BuildAsmjsStoreMem(MachineType type, Node* index,
2668 Node* val) {
2669 // TODO(turbofan): fold bounds checks for constant asm.js stores.
2670 // asm.js semantics use CheckedStore (i.e. ignore OOB writes).
2671 const Operator* op =
2672 jsgraph()->machine()->CheckedStore(type.representation());
2673 Node* store = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), val,
2674 *effect_, *control_);
2675 *effect_ = store;
2676 return val;
2677}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002678
2679void WasmGraphBuilder::PrintDebugName(Node* node) {
2680 PrintF("#%d:%s", node->id(), node->op()->mnemonic());
2681}
2682
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002683Node* WasmGraphBuilder::String(const char* string) {
2684 return jsgraph()->Constant(
2685 jsgraph()->isolate()->factory()->NewStringFromAsciiChecked(string));
2686}
2687
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002688Graph* WasmGraphBuilder::graph() { return jsgraph()->graph(); }
2689
Ben Murdoch097c5b22016-05-18 11:27:45 +01002690void WasmGraphBuilder::Int64LoweringForTesting() {
Ben Murdochda12d292016-06-02 14:46:10 +01002691 if (jsgraph()->machine()->Is32()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002692 Int64Lowering r(jsgraph()->graph(), jsgraph()->machine(),
2693 jsgraph()->common(), jsgraph()->zone(),
2694 function_signature_);
2695 r.LowerGraph();
2696 }
2697}
2698
Ben Murdochc5610432016-08-08 18:44:38 +01002699void WasmGraphBuilder::SetSourcePosition(Node* node,
2700 wasm::WasmCodePosition position) {
2701 DCHECK_NE(position, wasm::kNoCodePosition);
2702 compiler::SourcePosition pos(position);
2703 if (source_position_table_)
2704 source_position_table_->SetSourcePosition(node, pos);
2705}
2706
Ben Murdoch097c5b22016-05-18 11:27:45 +01002707static void RecordFunctionCompilation(Logger::LogEventsAndTags tag,
2708 CompilationInfo* info,
2709 const char* message, uint32_t index,
Ben Murdochda12d292016-06-02 14:46:10 +01002710 wasm::WasmName func_name) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002711 Isolate* isolate = info->isolate();
2712 if (isolate->logger()->is_logging_code_events() ||
2713 isolate->cpu_profiler()->is_profiling()) {
2714 ScopedVector<char> buffer(128);
Ben Murdochc5610432016-08-08 18:44:38 +01002715 SNPrintF(buffer, "%s#%d:%.*s", message, index, func_name.length(),
2716 func_name.start());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002717 Handle<String> name_str =
2718 isolate->factory()->NewStringFromAsciiChecked(buffer.start());
2719 Handle<String> script_str =
2720 isolate->factory()->NewStringFromAsciiChecked("(WASM)");
2721 Handle<Code> code = info->code();
2722 Handle<SharedFunctionInfo> shared =
2723 isolate->factory()->NewSharedFunctionInfo(name_str, code, false);
Ben Murdochda12d292016-06-02 14:46:10 +01002724 PROFILE(isolate, CodeCreateEvent(tag, AbstractCode::cast(*code), *shared,
Ben Murdochc5610432016-08-08 18:44:38 +01002725 *script_str, 0, 0));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002726 }
2727}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002728
2729Handle<JSFunction> CompileJSToWasmWrapper(
2730 Isolate* isolate, wasm::ModuleEnv* module, Handle<String> name,
2731 Handle<Code> wasm_code, Handle<JSObject> module_object, uint32_t index) {
Ben Murdochda12d292016-06-02 14:46:10 +01002732 wasm::WasmFunction* func = &module->module->functions[index];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002733
2734 //----------------------------------------------------------------------------
2735 // Create the JSFunction object.
2736 //----------------------------------------------------------------------------
2737 Handle<SharedFunctionInfo> shared =
2738 isolate->factory()->NewSharedFunctionInfo(name, wasm_code, false);
2739 int params = static_cast<int>(func->sig->parameter_count());
2740 shared->set_length(params);
Ben Murdochda12d292016-06-02 14:46:10 +01002741 shared->set_internal_formal_parameter_count(params);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002742 Handle<JSFunction> function = isolate->factory()->NewFunction(
2743 isolate->wasm_function_map(), name, MaybeHandle<Code>());
2744 function->SetInternalField(0, *module_object);
2745 function->set_shared(*shared);
2746
2747 //----------------------------------------------------------------------------
2748 // Create the Graph
2749 //----------------------------------------------------------------------------
Ben Murdochda12d292016-06-02 14:46:10 +01002750 Zone zone(isolate->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002751 Graph graph(&zone);
2752 CommonOperatorBuilder common(&zone);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002753 MachineOperatorBuilder machine(&zone);
Ben Murdochc5610432016-08-08 18:44:38 +01002754 JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002755
2756 Node* control = nullptr;
2757 Node* effect = nullptr;
2758
2759 WasmGraphBuilder builder(&zone, &jsgraph, func->sig);
2760 builder.set_control_ptr(&control);
2761 builder.set_effect_ptr(&effect);
2762 builder.set_module(module);
2763 builder.BuildJSToWasmWrapper(wasm_code, func->sig);
2764
2765 //----------------------------------------------------------------------------
2766 // Run the compilation pipeline.
2767 //----------------------------------------------------------------------------
2768 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002769 if (FLAG_trace_turbo_graph) { // Simple textual RPO.
2770 OFStream os(stdout);
2771 os << "-- Graph after change lowering -- " << std::endl;
2772 os << AsRPO(graph);
2773 }
2774
2775 // Schedule and compile to machine code.
2776 int params = static_cast<int>(
2777 module->GetFunctionSignature(index)->parameter_count());
2778 CallDescriptor* incoming = Linkage::GetJSCallDescriptor(
2779 &zone, false, params + 1, CallDescriptor::kNoFlags);
Ben Murdochda12d292016-06-02 14:46:10 +01002780 Code::Flags flags = Code::ComputeFlags(Code::JS_TO_WASM_FUNCTION);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002781 bool debugging =
2782#if DEBUG
2783 true;
2784#else
2785 FLAG_print_opt_code || FLAG_trace_turbo || FLAG_trace_turbo_graph;
2786#endif
Ben Murdochc5610432016-08-08 18:44:38 +01002787 Vector<const char> func_name = ArrayVector("js-to-wasm");
Ben Murdoch097c5b22016-05-18 11:27:45 +01002788
2789 static unsigned id = 0;
2790 Vector<char> buffer;
2791 if (debugging) {
2792 buffer = Vector<char>::New(128);
Ben Murdochc5610432016-08-08 18:44:38 +01002793 int chars = SNPrintF(buffer, "js-to-wasm#%d", id);
2794 func_name = Vector<const char>::cast(buffer.SubVector(0, chars));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002795 }
2796
2797 CompilationInfo info(func_name, isolate, &zone, flags);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002798 Handle<Code> code =
Ben Murdochc5610432016-08-08 18:44:38 +01002799 Pipeline::GenerateCodeForTesting(&info, incoming, &graph);
Ben Murdochda12d292016-06-02 14:46:10 +01002800#ifdef ENABLE_DISASSEMBLER
2801 if (FLAG_print_opt_code && !code.is_null()) {
2802 OFStream os(stdout);
2803 code->Disassemble(buffer.start(), os);
2804 }
2805#endif
Ben Murdoch097c5b22016-05-18 11:27:45 +01002806 if (debugging) {
2807 buffer.Dispose();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002808 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002809
Ben Murdochda12d292016-06-02 14:46:10 +01002810 RecordFunctionCompilation(
2811 Logger::FUNCTION_TAG, &info, "js-to-wasm", index,
2812 module->module->GetName(func->name_offset, func->name_length));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002813 // Set the JSFunction's machine code.
2814 function->set_code(*code);
2815 }
2816 return function;
2817}
2818
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002819Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, wasm::ModuleEnv* module,
2820 Handle<JSFunction> function,
Ben Murdochda12d292016-06-02 14:46:10 +01002821 wasm::FunctionSig* sig,
2822 wasm::WasmName module_name,
2823 wasm::WasmName function_name) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002824 //----------------------------------------------------------------------------
2825 // Create the Graph
2826 //----------------------------------------------------------------------------
Ben Murdochda12d292016-06-02 14:46:10 +01002827 Zone zone(isolate->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002828 Graph graph(&zone);
2829 CommonOperatorBuilder common(&zone);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002830 MachineOperatorBuilder machine(&zone);
Ben Murdochc5610432016-08-08 18:44:38 +01002831 JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002832
2833 Node* control = nullptr;
2834 Node* effect = nullptr;
2835
Ben Murdoch097c5b22016-05-18 11:27:45 +01002836 WasmGraphBuilder builder(&zone, &jsgraph, sig);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002837 builder.set_control_ptr(&control);
2838 builder.set_effect_ptr(&effect);
2839 builder.set_module(module);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002840 builder.BuildWasmToJSWrapper(function, sig);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002841
2842 Handle<Code> code = Handle<Code>::null();
2843 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002844 if (FLAG_trace_turbo_graph) { // Simple textual RPO.
2845 OFStream os(stdout);
2846 os << "-- Graph after change lowering -- " << std::endl;
2847 os << AsRPO(graph);
2848 }
2849
2850 // Schedule and compile to machine code.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002851 CallDescriptor* incoming =
2852 wasm::ModuleEnv::GetWasmCallDescriptor(&zone, sig);
Ben Murdochc5610432016-08-08 18:44:38 +01002853 if (machine.Is32()) {
2854 incoming = wasm::ModuleEnv::GetI32WasmCallDescriptor(&zone, incoming);
2855 }
Ben Murdochda12d292016-06-02 14:46:10 +01002856 Code::Flags flags = Code::ComputeFlags(Code::WASM_TO_JS_FUNCTION);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002857 bool debugging =
2858#if DEBUG
2859 true;
2860#else
2861 FLAG_print_opt_code || FLAG_trace_turbo || FLAG_trace_turbo_graph;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002862#endif
Ben Murdochc5610432016-08-08 18:44:38 +01002863 Vector<const char> func_name = ArrayVector("wasm-to-js");
Ben Murdoch097c5b22016-05-18 11:27:45 +01002864 static unsigned id = 0;
2865 Vector<char> buffer;
2866 if (debugging) {
2867 buffer = Vector<char>::New(128);
Ben Murdochc5610432016-08-08 18:44:38 +01002868 int chars = SNPrintF(buffer, "wasm-to-js#%d", id);
2869 func_name = Vector<const char>::cast(buffer.SubVector(0, chars));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002870 }
2871
2872 CompilationInfo info(func_name, isolate, &zone, flags);
2873 code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr);
Ben Murdochda12d292016-06-02 14:46:10 +01002874#ifdef ENABLE_DISASSEMBLER
2875 if (FLAG_print_opt_code && !code.is_null()) {
2876 OFStream os(stdout);
2877 code->Disassemble(buffer.start(), os);
2878 }
2879#endif
Ben Murdoch097c5b22016-05-18 11:27:45 +01002880 if (debugging) {
2881 buffer.Dispose();
2882 }
2883
2884 RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, "wasm-to-js", 0,
Ben Murdochda12d292016-06-02 14:46:10 +01002885 module_name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002886 }
2887 return code;
2888}
2889
Ben Murdochc5610432016-08-08 18:44:38 +01002890std::pair<JSGraph*, SourcePositionTable*> BuildGraphForWasmFunction(
2891 JSGraph* jsgraph, wasm::ErrorThrower* thrower, Isolate* isolate,
2892 wasm::ModuleEnv*& module_env, const wasm::WasmFunction* function,
2893 double* decode_ms) {
Ben Murdochda12d292016-06-02 14:46:10 +01002894 base::ElapsedTimer decode_timer;
2895 if (FLAG_trace_wasm_decode_time) {
2896 decode_timer.Start();
2897 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002898 // Create a TF graph during decoding.
Ben Murdochc5610432016-08-08 18:44:38 +01002899 Graph* graph = jsgraph->graph();
2900 CommonOperatorBuilder* common = jsgraph->common();
2901 MachineOperatorBuilder* machine = jsgraph->machine();
2902 SourcePositionTable* source_position_table =
2903 new (jsgraph->zone()) SourcePositionTable(graph);
2904 WasmGraphBuilder builder(jsgraph->zone(), jsgraph, function->sig,
2905 source_position_table);
Ben Murdochda12d292016-06-02 14:46:10 +01002906 wasm::FunctionBody body = {
Ben Murdochc5610432016-08-08 18:44:38 +01002907 module_env, function->sig, module_env->module->module_start,
2908 module_env->module->module_start + function->code_start_offset,
2909 module_env->module->module_start + function->code_end_offset};
Ben Murdochda12d292016-06-02 14:46:10 +01002910 wasm::TreeResult result =
2911 wasm::BuildTFGraph(isolate->allocator(), &builder, body);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002912
Ben Murdochc5610432016-08-08 18:44:38 +01002913 if (machine->Is32()) {
2914 Int64Lowering r(graph, machine, common, jsgraph->zone(), function->sig);
2915 r.LowerGraph();
2916 }
2917
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002918 if (result.failed()) {
2919 if (FLAG_trace_wasm_compiler) {
2920 OFStream os(stdout);
2921 os << "Compilation failed: " << result << std::endl;
2922 }
2923 // Add the function as another context for the exception
Ben Murdoch097c5b22016-05-18 11:27:45 +01002924 ScopedVector<char> buffer(128);
Ben Murdochc5610432016-08-08 18:44:38 +01002925 wasm::WasmName name = module_env->module->GetName(function->name_offset,
2926 function->name_length);
Ben Murdochda12d292016-06-02 14:46:10 +01002927 SNPrintF(buffer, "Compiling WASM function #%d:%.*s failed:",
Ben Murdochc5610432016-08-08 18:44:38 +01002928 function->func_index, name.length(), name.start());
2929 thrower->Failed(buffer.start(), result);
2930 return std::make_pair(nullptr, nullptr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002931 }
Ben Murdochc5610432016-08-08 18:44:38 +01002932 int index = static_cast<int>(function->func_index);
Ben Murdochda12d292016-06-02 14:46:10 +01002933 if (index >= FLAG_trace_wasm_ast_start && index < FLAG_trace_wasm_ast_end) {
2934 PrintAst(isolate->allocator(), body);
2935 }
Ben Murdochda12d292016-06-02 14:46:10 +01002936 if (FLAG_trace_wasm_decode_time) {
Ben Murdochc5610432016-08-08 18:44:38 +01002937 *decode_ms = decode_timer.Elapsed().InMillisecondsF();
Ben Murdochda12d292016-06-02 14:46:10 +01002938 }
Ben Murdochc5610432016-08-08 18:44:38 +01002939 return std::make_pair(jsgraph, source_position_table);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002940}
2941
Ben Murdochc5610432016-08-08 18:44:38 +01002942class WasmCompilationUnit {
2943 public:
2944 WasmCompilationUnit(wasm::ErrorThrower* thrower, Isolate* isolate,
2945 wasm::ModuleEnv* module_env,
2946 const wasm::WasmFunction* function, uint32_t index)
2947 : thrower_(thrower),
2948 isolate_(isolate),
2949 module_env_(module_env),
2950 function_(function),
2951 graph_zone_(new Zone(isolate->allocator())),
2952 jsgraph_(new (graph_zone()) JSGraph(
2953 isolate, new (graph_zone()) Graph(graph_zone()),
2954 new (graph_zone()) CommonOperatorBuilder(graph_zone()), nullptr,
2955 nullptr,
2956 new (graph_zone()) MachineOperatorBuilder(
2957 graph_zone(), MachineType::PointerRepresentation(),
2958 InstructionSelector::SupportedMachineOperatorFlags()))),
2959 compilation_zone_(isolate->allocator()),
2960 info_(function->name_length != 0
2961 ? module_env->module->GetNameOrNull(function->name_offset,
2962 function->name_length)
2963 : ArrayVector("wasm"),
2964 isolate, &compilation_zone_,
2965 Code::ComputeFlags(Code::WASM_FUNCTION)),
2966 job_(),
2967 index_(index),
2968 ok_(true) {
2969 // Create and cache this node in the main thread.
2970 jsgraph_->CEntryStubConstant(1);
2971 }
2972
2973 Zone* graph_zone() { return graph_zone_.get(); }
2974
2975 void ExecuteCompilation() {
2976 // TODO(ahaas): The counters are not thread-safe at the moment.
2977 // HistogramTimerScope wasm_compile_function_time_scope(
2978 // isolate_->counters()->wasm_compile_function_time());
2979 if (FLAG_trace_wasm_compiler) {
2980 OFStream os(stdout);
2981 os << "Compiling WASM function "
2982 << wasm::WasmFunctionName(function_, module_env_) << std::endl;
2983 os << std::endl;
2984 }
2985
2986 double decode_ms = 0;
2987 size_t node_count = 0;
2988
2989 base::SmartPointer<Zone> graph_zone(graph_zone_.Detach());
2990 std::pair<JSGraph*, SourcePositionTable*> graph_result =
2991 BuildGraphForWasmFunction(jsgraph_, thrower_, isolate_, module_env_,
2992 function_, &decode_ms);
2993 JSGraph* jsgraph = graph_result.first;
2994 SourcePositionTable* source_positions = graph_result.second;
2995
2996 if (jsgraph == nullptr) {
2997 ok_ = false;
2998 return;
2999 }
3000
3001 base::ElapsedTimer pipeline_timer;
3002 if (FLAG_trace_wasm_decode_time) {
3003 node_count = jsgraph->graph()->NodeCount();
3004 pipeline_timer.Start();
3005 }
3006
3007 // Run the compiler pipeline to generate machine code.
3008 CallDescriptor* descriptor = wasm::ModuleEnv::GetWasmCallDescriptor(
3009 &compilation_zone_, function_->sig);
3010 if (jsgraph->machine()->Is32()) {
3011 descriptor =
3012 module_env_->GetI32WasmCallDescriptor(&compilation_zone_, descriptor);
3013 }
3014 job_.Reset(Pipeline::NewWasmCompilationJob(&info_, jsgraph->graph(),
3015 descriptor, source_positions));
3016 ok_ = job_->OptimizeGraph() == CompilationJob::SUCCEEDED;
3017 // TODO(bradnelson): Improve histogram handling of size_t.
3018 // TODO(ahaas): The counters are not thread-safe at the moment.
3019 // isolate_->counters()->wasm_compile_function_peak_memory_bytes()
3020 // ->AddSample(
3021 // static_cast<int>(jsgraph->graph()->zone()->allocation_size()));
3022
3023 if (FLAG_trace_wasm_decode_time) {
3024 double pipeline_ms = pipeline_timer.Elapsed().InMillisecondsF();
3025 PrintF(
3026 "wasm-compilation phase 1 ok: %d bytes, %0.3f ms decode, %zu nodes, "
3027 "%0.3f ms pipeline\n",
3028 static_cast<int>(function_->code_end_offset -
3029 function_->code_start_offset),
3030 decode_ms, node_count, pipeline_ms);
3031 }
3032 }
3033
3034 Handle<Code> FinishCompilation() {
3035 if (!ok_) {
3036 return Handle<Code>::null();
3037 }
3038 if (job_->GenerateCode() != CompilationJob::SUCCEEDED) {
3039 return Handle<Code>::null();
3040 }
3041 base::ElapsedTimer compile_timer;
3042 if (FLAG_trace_wasm_decode_time) {
3043 compile_timer.Start();
3044 }
3045 Handle<Code> code = info_.code();
3046 DCHECK(!code.is_null());
3047 DCHECK(code->deoptimization_data() == nullptr ||
3048 code->deoptimization_data()->length() == 0);
3049 Handle<FixedArray> deopt_data =
3050 isolate_->factory()->NewFixedArray(2, TENURED);
3051 if (!module_env_->instance->js_object.is_null()) {
3052 deopt_data->set(0, *module_env_->instance->js_object);
3053 }
3054 deopt_data->set(1, Smi::FromInt(function_->func_index));
3055 deopt_data->set_length(2);
3056 code->set_deoptimization_data(*deopt_data);
3057
3058 RecordFunctionCompilation(
3059 Logger::FUNCTION_TAG, &info_, "WASM_function", function_->func_index,
3060 module_env_->module->GetName(function_->name_offset,
3061 function_->name_length));
3062
3063 if (FLAG_trace_wasm_decode_time) {
3064 double compile_ms = compile_timer.Elapsed().InMillisecondsF();
3065 PrintF("wasm-code-generation ok: %d bytes, %0.3f ms code generation\n",
3066 static_cast<int>(function_->code_end_offset -
3067 function_->code_start_offset),
3068 compile_ms);
3069 }
3070
3071 return code;
3072 }
3073
3074 wasm::ErrorThrower* thrower_;
3075 Isolate* isolate_;
3076 wasm::ModuleEnv* module_env_;
3077 const wasm::WasmFunction* function_;
3078 // The graph zone is deallocated at the end of ExecuteCompilation.
3079 base::SmartPointer<Zone> graph_zone_;
3080 JSGraph* jsgraph_;
3081 Zone compilation_zone_;
3082 CompilationInfo info_;
3083 base::SmartPointer<CompilationJob> job_;
3084 uint32_t index_;
3085 bool ok_;
3086};
3087
3088WasmCompilationUnit* CreateWasmCompilationUnit(
3089 wasm::ErrorThrower* thrower, Isolate* isolate, wasm::ModuleEnv* module_env,
3090 const wasm::WasmFunction* function, uint32_t index) {
3091 return new WasmCompilationUnit(thrower, isolate, module_env, function, index);
3092}
3093
3094void ExecuteCompilation(WasmCompilationUnit* unit) {
3095 unit->ExecuteCompilation();
3096}
3097
3098uint32_t GetIndexOfWasmCompilationUnit(WasmCompilationUnit* unit) {
3099 return unit->index_;
3100}
3101
3102Handle<Code> FinishCompilation(WasmCompilationUnit* unit) {
3103 Handle<Code> result = unit->FinishCompilation();
3104 delete unit;
3105 return result;
3106}
3107
3108// Helper function to compile a single function.
3109Handle<Code> CompileWasmFunction(wasm::ErrorThrower* thrower, Isolate* isolate,
3110 wasm::ModuleEnv* module_env,
3111 const wasm::WasmFunction* function) {
3112 WasmCompilationUnit* unit =
3113 CreateWasmCompilationUnit(thrower, isolate, module_env, function, 0);
3114 ExecuteCompilation(unit);
3115 return FinishCompilation(unit);
3116}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003117
3118} // namespace compiler
3119} // namespace internal
3120} // namespace v8