Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : *
4 : * Copyright 2015 Mozilla Foundation
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : #include "wasm/WasmIonCompile.h"
20 :
21 : #include "mozilla/MathAlgorithms.h"
22 :
23 : #include "jit/CodeGenerator.h"
24 :
25 : #include "wasm/WasmBaselineCompile.h"
26 : #include "wasm/WasmBinaryIterator.h"
27 : #include "wasm/WasmGenerator.h"
28 : #include "wasm/WasmSignalHandlers.h"
29 : #include "wasm/WasmValidate.h"
30 :
31 : using namespace js;
32 : using namespace js::jit;
33 : using namespace js::wasm;
34 :
35 : using mozilla::DebugOnly;
36 : using mozilla::IsPowerOfTwo;
37 : using mozilla::Maybe;
38 : using mozilla::Nothing;
39 : using mozilla::Some;
40 :
41 : namespace {
42 :
43 : typedef Vector<MBasicBlock*, 8, SystemAllocPolicy> BlockVector;
44 :
45 0 : struct IonCompilePolicy
46 : {
47 : // We store SSA definitions in the value stack.
48 : typedef MDefinition* Value;
49 :
50 : // We store loop headers and then/else blocks in the control flow stack.
51 : typedef MBasicBlock* ControlItem;
52 : };
53 :
54 : typedef OpIter<IonCompilePolicy> IonOpIter;
55 :
56 : class FunctionCompiler;
57 :
58 : // CallCompileState describes a call that is being compiled. Due to expression
59 : // nesting, multiple calls can be in the middle of compilation at the same time
60 : // and these are tracked in a stack by FunctionCompiler.
61 :
62 0 : class CallCompileState
63 : {
64 : // The line or bytecode of the call.
65 : uint32_t lineOrBytecode_;
66 :
67 : // A generator object that is passed each argument as it is compiled.
68 : ABIArgGenerator abi_;
69 :
70 : // The maximum number of bytes used by "child" calls, i.e., calls that occur
71 : // while evaluating the arguments of the call represented by this
72 : // CallCompileState.
73 : uint32_t maxChildStackBytes_;
74 :
75 : // Set by FunctionCompiler::finishCall(), tells the MWasmCall by how
76 : // much to bump the stack pointer before making the call. See
77 : // FunctionCompiler::startCall() comment below.
78 : uint32_t spIncrement_;
79 :
80 : // Accumulates the register arguments while compiling arguments.
81 : MWasmCall::Args regArgs_;
82 :
83 : // Reserved argument for passing Instance* to builtin instance method calls.
84 : ABIArg instanceArg_;
85 :
86 : // Accumulates the stack arguments while compiling arguments. This is only
87 : // necessary to track when childClobbers_ is true so that the stack offsets
88 : // can be updated.
89 : Vector<MWasmStackArg*, 0, SystemAllocPolicy> stackArgs_;
90 :
91 : // Set by child calls (i.e., calls that execute while evaluating a parent's
92 : // operands) to indicate that the child and parent call cannot reuse the
93 : // same stack space -- the parent must store its stack arguments below the
94 : // child's and increment sp when performing its call.
95 : bool childClobbers_;
96 :
97 : // Only FunctionCompiler should be directly manipulating CallCompileState.
98 : friend class FunctionCompiler;
99 :
100 : public:
101 0 : CallCompileState(FunctionCompiler& f, uint32_t lineOrBytecode)
102 0 : : lineOrBytecode_(lineOrBytecode),
103 : maxChildStackBytes_(0),
104 : spIncrement_(0),
105 0 : childClobbers_(false)
106 0 : { }
107 : };
108 :
109 : // Encapsulates the compilation of a single function in an asm.js module. The
110 : // function compiler handles the creation and final backend compilation of the
111 : // MIR graph.
112 0 : class FunctionCompiler
113 : {
114 : struct ControlFlowPatch {
115 : MControlInstruction* ins;
116 : uint32_t index;
117 0 : ControlFlowPatch(MControlInstruction* ins, uint32_t index)
118 0 : : ins(ins),
119 0 : index(index)
120 0 : {}
121 : };
122 :
123 : typedef Vector<ControlFlowPatch, 0, SystemAllocPolicy> ControlFlowPatchVector;
124 : typedef Vector<ControlFlowPatchVector, 0, SystemAllocPolicy> ControlFlowPatchsVector;
125 : typedef Vector<CallCompileState*, 0, SystemAllocPolicy> CallCompileStateVector;
126 :
127 : const ModuleEnvironment& env_;
128 : IonOpIter iter_;
129 : const FuncBytes& func_;
130 : const ValTypeVector& locals_;
131 : size_t lastReadCallSite_;
132 :
133 : TempAllocator& alloc_;
134 : MIRGraph& graph_;
135 : const CompileInfo& info_;
136 : MIRGenerator& mirGen_;
137 :
138 : MBasicBlock* curBlock_;
139 : CallCompileStateVector callStack_;
140 : uint32_t maxStackArgBytes_;
141 :
142 : uint32_t loopDepth_;
143 : uint32_t blockDepth_;
144 : ControlFlowPatchsVector blockPatches_;
145 :
146 : // TLS pointer argument to the current function.
147 : MWasmParameter* tlsPointer_;
148 :
149 : public:
150 0 : FunctionCompiler(const ModuleEnvironment& env,
151 : Decoder& decoder,
152 : const FuncBytes& func,
153 : const ValTypeVector& locals,
154 : MIRGenerator& mirGen)
155 0 : : env_(env),
156 : iter_(env, decoder),
157 : func_(func),
158 : locals_(locals),
159 : lastReadCallSite_(0),
160 0 : alloc_(mirGen.alloc()),
161 0 : graph_(mirGen.graph()),
162 0 : info_(mirGen.info()),
163 : mirGen_(mirGen),
164 : curBlock_(nullptr),
165 : maxStackArgBytes_(0),
166 : loopDepth_(0),
167 : blockDepth_(0),
168 0 : tlsPointer_(nullptr)
169 0 : {}
170 :
171 0 : const ModuleEnvironment& env() const { return env_; }
172 0 : IonOpIter& iter() { return iter_; }
173 0 : TempAllocator& alloc() const { return alloc_; }
174 0 : const Sig& sig() const { return func_.sig(); }
175 :
176 0 : BytecodeOffset bytecodeOffset() const {
177 0 : return iter_.bytecodeOffset();
178 : }
179 0 : Maybe<BytecodeOffset> bytecodeIfNotAsmJS() const {
180 0 : return env_.isAsmJS() ? Nothing() : Some(iter_.bytecodeOffset());
181 : }
182 :
183 0 : bool init()
184 : {
185 : // Prepare the entry block for MIR generation:
186 :
187 0 : const ValTypeVector& args = func_.sig().args();
188 :
189 0 : if (!mirGen_.ensureBallast())
190 0 : return false;
191 0 : if (!newBlock(/* prev */ nullptr, &curBlock_))
192 0 : return false;
193 :
194 0 : for (ABIArgValTypeIter i(args); !i.done(); i++) {
195 0 : MWasmParameter* ins = MWasmParameter::New(alloc(), *i, i.mirType());
196 0 : curBlock_->add(ins);
197 0 : curBlock_->initSlot(info().localSlot(i.index()), ins);
198 0 : if (!mirGen_.ensureBallast())
199 0 : return false;
200 : }
201 :
202 : // Set up a parameter that receives the hidden TLS pointer argument.
203 0 : tlsPointer_ = MWasmParameter::New(alloc(), ABIArg(WasmTlsReg), MIRType::Pointer);
204 0 : curBlock_->add(tlsPointer_);
205 0 : if (!mirGen_.ensureBallast())
206 0 : return false;
207 :
208 0 : for (size_t i = args.length(); i < locals_.length(); i++) {
209 0 : MInstruction* ins = nullptr;
210 0 : switch (locals_[i]) {
211 : case ValType::I32:
212 0 : ins = MConstant::New(alloc(), Int32Value(0), MIRType::Int32);
213 0 : break;
214 : case ValType::I64:
215 0 : ins = MConstant::NewInt64(alloc(), 0);
216 0 : break;
217 : case ValType::F32:
218 0 : ins = MConstant::New(alloc(), Float32Value(0.f), MIRType::Float32);
219 0 : break;
220 : case ValType::F64:
221 0 : ins = MConstant::New(alloc(), DoubleValue(0.0), MIRType::Double);
222 0 : break;
223 : case ValType::I8x16:
224 0 : ins = MSimdConstant::New(alloc(), SimdConstant::SplatX16(0), MIRType::Int8x16);
225 0 : break;
226 : case ValType::I16x8:
227 0 : ins = MSimdConstant::New(alloc(), SimdConstant::SplatX8(0), MIRType::Int16x8);
228 0 : break;
229 : case ValType::I32x4:
230 0 : ins = MSimdConstant::New(alloc(), SimdConstant::SplatX4(0), MIRType::Int32x4);
231 0 : break;
232 : case ValType::F32x4:
233 0 : ins = MSimdConstant::New(alloc(), SimdConstant::SplatX4(0.f), MIRType::Float32x4);
234 0 : break;
235 : case ValType::B8x16:
236 : // Bool8x16 uses the same data layout as Int8x16.
237 0 : ins = MSimdConstant::New(alloc(), SimdConstant::SplatX16(0), MIRType::Bool8x16);
238 0 : break;
239 : case ValType::B16x8:
240 : // Bool16x8 uses the same data layout as Int16x8.
241 0 : ins = MSimdConstant::New(alloc(), SimdConstant::SplatX8(0), MIRType::Bool16x8);
242 0 : break;
243 : case ValType::B32x4:
244 : // Bool32x4 uses the same data layout as Int32x4.
245 0 : ins = MSimdConstant::New(alloc(), SimdConstant::SplatX4(0), MIRType::Bool32x4);
246 0 : break;
247 : }
248 :
249 0 : curBlock_->add(ins);
250 0 : curBlock_->initSlot(info().localSlot(i), ins);
251 0 : if (!mirGen_.ensureBallast())
252 0 : return false;
253 : }
254 :
255 0 : addInterruptCheck();
256 :
257 0 : return true;
258 : }
259 :
260 0 : void finish()
261 : {
262 0 : mirGen().initWasmMaxStackArgBytes(maxStackArgBytes_);
263 :
264 0 : MOZ_ASSERT(callStack_.empty());
265 0 : MOZ_ASSERT(loopDepth_ == 0);
266 0 : MOZ_ASSERT(blockDepth_ == 0);
267 : #ifdef DEBUG
268 0 : for (ControlFlowPatchVector& patches : blockPatches_)
269 0 : MOZ_ASSERT(patches.empty());
270 : #endif
271 0 : MOZ_ASSERT(inDeadCode());
272 0 : MOZ_ASSERT(done(), "all bytes must be consumed");
273 0 : MOZ_ASSERT(func_.callSiteLineNums().length() == lastReadCallSite_);
274 0 : }
275 :
276 : /************************* Read-only interface (after local scope setup) */
277 :
278 0 : MIRGenerator& mirGen() const { return mirGen_; }
279 0 : MIRGraph& mirGraph() const { return graph_; }
280 0 : const CompileInfo& info() const { return info_; }
281 :
282 0 : MDefinition* getLocalDef(unsigned slot)
283 : {
284 0 : if (inDeadCode())
285 0 : return nullptr;
286 0 : return curBlock_->getSlot(info().localSlot(slot));
287 : }
288 :
289 0 : const ValTypeVector& locals() const { return locals_; }
290 :
291 : /***************************** Code generation (after local scope setup) */
292 :
293 0 : MDefinition* constant(const SimdConstant& v, MIRType type)
294 : {
295 0 : if (inDeadCode())
296 0 : return nullptr;
297 : MInstruction* constant;
298 0 : constant = MSimdConstant::New(alloc(), v, type);
299 0 : curBlock_->add(constant);
300 0 : return constant;
301 : }
302 :
303 0 : MDefinition* constant(const Value& v, MIRType type)
304 : {
305 0 : if (inDeadCode())
306 0 : return nullptr;
307 0 : MConstant* constant = MConstant::New(alloc(), v, type);
308 0 : curBlock_->add(constant);
309 0 : return constant;
310 : }
311 :
312 0 : MDefinition* constant(float f)
313 : {
314 0 : if (inDeadCode())
315 0 : return nullptr;
316 0 : auto* cst = MWasmFloatConstant::NewFloat32(alloc(), f);
317 0 : curBlock_->add(cst);
318 0 : return cst;
319 : }
320 :
321 0 : MDefinition* constant(double d)
322 : {
323 0 : if (inDeadCode())
324 0 : return nullptr;
325 0 : auto* cst = MWasmFloatConstant::NewDouble(alloc(), d);
326 0 : curBlock_->add(cst);
327 0 : return cst;
328 : }
329 :
330 0 : MDefinition* constant(int64_t i)
331 : {
332 0 : if (inDeadCode())
333 0 : return nullptr;
334 0 : MConstant* constant = MConstant::NewInt64(alloc(), i);
335 0 : curBlock_->add(constant);
336 0 : return constant;
337 : }
338 :
339 : template <class T>
340 0 : MDefinition* unary(MDefinition* op)
341 : {
342 0 : if (inDeadCode())
343 0 : return nullptr;
344 0 : T* ins = T::New(alloc(), op);
345 0 : curBlock_->add(ins);
346 0 : return ins;
347 : }
348 :
349 : template <class T>
350 0 : MDefinition* unary(MDefinition* op, MIRType type)
351 : {
352 0 : if (inDeadCode())
353 0 : return nullptr;
354 0 : T* ins = T::New(alloc(), op, type);
355 0 : curBlock_->add(ins);
356 0 : return ins;
357 : }
358 :
359 : template <class T>
360 : MDefinition* binary(MDefinition* lhs, MDefinition* rhs)
361 : {
362 : if (inDeadCode())
363 : return nullptr;
364 : T* ins = T::New(alloc(), lhs, rhs);
365 : curBlock_->add(ins);
366 : return ins;
367 : }
368 :
369 : template <class T>
370 0 : MDefinition* binary(MDefinition* lhs, MDefinition* rhs, MIRType type)
371 : {
372 0 : if (inDeadCode())
373 0 : return nullptr;
374 0 : T* ins = T::New(alloc(), lhs, rhs, type);
375 0 : curBlock_->add(ins);
376 0 : return ins;
377 : }
378 :
379 0 : bool mustPreserveNaN(MIRType type)
380 : {
381 0 : return IsFloatingPointType(type) && !env().isAsmJS();
382 : }
383 :
384 0 : MDefinition* sub(MDefinition* lhs, MDefinition* rhs, MIRType type)
385 : {
386 0 : if (inDeadCode())
387 0 : return nullptr;
388 :
389 : // wasm can't fold x - 0.0 because of NaN with custom payloads.
390 0 : MSub* ins = MSub::New(alloc(), lhs, rhs, type, mustPreserveNaN(type));
391 0 : curBlock_->add(ins);
392 0 : return ins;
393 : }
394 :
395 0 : MDefinition* nearbyInt(MDefinition* input, RoundingMode roundingMode)
396 : {
397 0 : if (inDeadCode())
398 0 : return nullptr;
399 :
400 0 : auto* ins = MNearbyInt::New(alloc(), input, input->type(), roundingMode);
401 0 : curBlock_->add(ins);
402 0 : return ins;
403 : }
404 :
405 0 : MDefinition* unarySimd(MDefinition* input, MSimdUnaryArith::Operation op, MIRType type)
406 : {
407 0 : if (inDeadCode())
408 0 : return nullptr;
409 :
410 0 : MOZ_ASSERT(IsSimdType(input->type()) && input->type() == type);
411 0 : MInstruction* ins = MSimdUnaryArith::New(alloc(), input, op);
412 0 : curBlock_->add(ins);
413 0 : return ins;
414 : }
415 :
416 0 : MDefinition* binarySimd(MDefinition* lhs, MDefinition* rhs, MSimdBinaryArith::Operation op,
417 : MIRType type)
418 : {
419 0 : if (inDeadCode())
420 0 : return nullptr;
421 :
422 0 : MOZ_ASSERT(IsSimdType(lhs->type()) && rhs->type() == lhs->type());
423 0 : MOZ_ASSERT(lhs->type() == type);
424 0 : return MSimdBinaryArith::AddLegalized(alloc(), curBlock_, lhs, rhs, op);
425 : }
426 :
427 0 : MDefinition* binarySimd(MDefinition* lhs, MDefinition* rhs, MSimdBinaryBitwise::Operation op,
428 : MIRType type)
429 : {
430 0 : if (inDeadCode())
431 0 : return nullptr;
432 :
433 0 : MOZ_ASSERT(IsSimdType(lhs->type()) && rhs->type() == lhs->type());
434 0 : MOZ_ASSERT(lhs->type() == type);
435 0 : auto* ins = MSimdBinaryBitwise::New(alloc(), lhs, rhs, op);
436 0 : curBlock_->add(ins);
437 0 : return ins;
438 : }
439 :
440 0 : MDefinition* binarySimdComp(MDefinition* lhs, MDefinition* rhs, MSimdBinaryComp::Operation op,
441 : SimdSign sign)
442 : {
443 0 : if (inDeadCode())
444 0 : return nullptr;
445 :
446 0 : return MSimdBinaryComp::AddLegalized(alloc(), curBlock_, lhs, rhs, op, sign);
447 : }
448 :
449 0 : MDefinition* binarySimdSaturating(MDefinition* lhs, MDefinition* rhs,
450 : MSimdBinarySaturating::Operation op, SimdSign sign)
451 : {
452 0 : if (inDeadCode())
453 0 : return nullptr;
454 :
455 0 : auto* ins = MSimdBinarySaturating::New(alloc(), lhs, rhs, op, sign);
456 0 : curBlock_->add(ins);
457 0 : return ins;
458 : }
459 :
460 0 : MDefinition* binarySimdShift(MDefinition* lhs, MDefinition* rhs, MSimdShift::Operation op)
461 : {
462 0 : if (inDeadCode())
463 0 : return nullptr;
464 :
465 0 : return MSimdShift::AddLegalized(alloc(), curBlock_, lhs, rhs, op);
466 : }
467 :
468 0 : MDefinition* swizzleSimd(MDefinition* vector, const uint8_t lanes[], MIRType type)
469 : {
470 0 : if (inDeadCode())
471 0 : return nullptr;
472 :
473 0 : MOZ_ASSERT(vector->type() == type);
474 0 : MSimdSwizzle* ins = MSimdSwizzle::New(alloc(), vector, lanes);
475 0 : curBlock_->add(ins);
476 0 : return ins;
477 : }
478 :
479 0 : MDefinition* shuffleSimd(MDefinition* lhs, MDefinition* rhs, const uint8_t lanes[],
480 : MIRType type)
481 : {
482 0 : if (inDeadCode())
483 0 : return nullptr;
484 :
485 0 : MOZ_ASSERT(lhs->type() == type);
486 0 : MInstruction* ins = MSimdShuffle::New(alloc(), lhs, rhs, lanes);
487 0 : curBlock_->add(ins);
488 0 : return ins;
489 : }
490 :
491 0 : MDefinition* insertElementSimd(MDefinition* vec, MDefinition* val, unsigned lane, MIRType type)
492 : {
493 0 : if (inDeadCode())
494 0 : return nullptr;
495 :
496 0 : MOZ_ASSERT(IsSimdType(vec->type()) && vec->type() == type);
497 0 : MOZ_ASSERT(SimdTypeToLaneArgumentType(vec->type()) == val->type());
498 0 : MSimdInsertElement* ins = MSimdInsertElement::New(alloc(), vec, val, lane);
499 0 : curBlock_->add(ins);
500 0 : return ins;
501 : }
502 :
503 0 : MDefinition* selectSimd(MDefinition* mask, MDefinition* lhs, MDefinition* rhs, MIRType type)
504 : {
505 0 : if (inDeadCode())
506 0 : return nullptr;
507 :
508 0 : MOZ_ASSERT(IsSimdType(mask->type()));
509 0 : MOZ_ASSERT(IsSimdType(lhs->type()) && rhs->type() == lhs->type());
510 0 : MOZ_ASSERT(lhs->type() == type);
511 0 : MSimdSelect* ins = MSimdSelect::New(alloc(), mask, lhs, rhs);
512 0 : curBlock_->add(ins);
513 0 : return ins;
514 : }
515 :
516 0 : MDefinition* simdAllTrue(MDefinition* boolVector)
517 : {
518 0 : if (inDeadCode())
519 0 : return nullptr;
520 :
521 0 : MSimdAllTrue* ins = MSimdAllTrue::New(alloc(), boolVector, MIRType::Int32);
522 0 : curBlock_->add(ins);
523 0 : return ins;
524 : }
525 :
526 0 : MDefinition* simdAnyTrue(MDefinition* boolVector)
527 : {
528 0 : if (inDeadCode())
529 0 : return nullptr;
530 :
531 0 : MSimdAnyTrue* ins = MSimdAnyTrue::New(alloc(), boolVector, MIRType::Int32);
532 0 : curBlock_->add(ins);
533 0 : return ins;
534 : }
535 :
536 : // fromXXXBits()
537 0 : MDefinition* bitcastSimd(MDefinition* vec, MIRType from, MIRType to)
538 : {
539 0 : if (inDeadCode())
540 0 : return nullptr;
541 :
542 0 : MOZ_ASSERT(vec->type() == from);
543 0 : MOZ_ASSERT(IsSimdType(from) && IsSimdType(to) && from != to);
544 0 : auto* ins = MSimdReinterpretCast::New(alloc(), vec, to);
545 0 : curBlock_->add(ins);
546 0 : return ins;
547 : }
548 :
549 : // Int <--> Float conversions.
550 0 : MDefinition* convertSimd(MDefinition* vec, MIRType from, MIRType to, SimdSign sign)
551 : {
552 0 : if (inDeadCode())
553 0 : return nullptr;
554 :
555 0 : MOZ_ASSERT(IsSimdType(from) && IsSimdType(to) && from != to);
556 0 : return MSimdConvert::AddLegalized(alloc(), curBlock_, vec, to, sign, bytecodeOffset());
557 : }
558 :
559 0 : MDefinition* splatSimd(MDefinition* v, MIRType type)
560 : {
561 0 : if (inDeadCode())
562 0 : return nullptr;
563 :
564 0 : MOZ_ASSERT(IsSimdType(type));
565 0 : MOZ_ASSERT(SimdTypeToLaneArgumentType(type) == v->type());
566 0 : MSimdSplat* ins = MSimdSplat::New(alloc(), v, type);
567 0 : curBlock_->add(ins);
568 0 : return ins;
569 : }
570 :
571 0 : MDefinition* minMax(MDefinition* lhs, MDefinition* rhs, MIRType type, bool isMax) {
572 0 : if (inDeadCode())
573 0 : return nullptr;
574 :
575 0 : if (mustPreserveNaN(type)) {
576 : // Convert signaling NaN to quiet NaNs.
577 0 : MDefinition* zero = constant(DoubleValue(0.0), type);
578 0 : lhs = sub(lhs, zero, type);
579 0 : rhs = sub(rhs, zero, type);
580 : }
581 :
582 0 : MMinMax* ins = MMinMax::NewWasm(alloc(), lhs, rhs, type, isMax);
583 0 : curBlock_->add(ins);
584 0 : return ins;
585 : }
586 :
587 0 : MDefinition* mul(MDefinition* lhs, MDefinition* rhs, MIRType type, MMul::Mode mode)
588 : {
589 0 : if (inDeadCode())
590 0 : return nullptr;
591 :
592 : // wasm can't fold x * 1.0 because of NaN with custom payloads.
593 0 : auto* ins = MMul::NewWasm(alloc(), lhs, rhs, type, mode, mustPreserveNaN(type));
594 0 : curBlock_->add(ins);
595 0 : return ins;
596 : }
597 :
598 0 : MDefinition* div(MDefinition* lhs, MDefinition* rhs, MIRType type, bool unsignd)
599 : {
600 0 : if (inDeadCode())
601 0 : return nullptr;
602 0 : bool trapOnError = !env().isAsmJS();
603 0 : if (!unsignd && type == MIRType::Int32) {
604 : // Enforce the signedness of the operation by coercing the operands
605 : // to signed. Otherwise, operands that "look" unsigned to Ion but
606 : // are not unsigned to Baldr (eg, unsigned right shifts) may lead to
607 : // the operation being executed unsigned. Applies to mod() as well.
608 : //
609 : // Do this for Int32 only since Int64 is not subject to the same
610 : // issues.
611 : //
612 : // Note the offsets passed to MTruncateToInt32 are wrong here, but
613 : // it doesn't matter: they're not codegen'd to calls since inputs
614 : // already are int32.
615 0 : auto* lhs2 = MTruncateToInt32::New(alloc(), lhs);
616 0 : curBlock_->add(lhs2);
617 0 : lhs = lhs2;
618 0 : auto* rhs2 = MTruncateToInt32::New(alloc(), rhs);
619 0 : curBlock_->add(rhs2);
620 0 : rhs = rhs2;
621 : }
622 0 : auto* ins = MDiv::New(alloc(), lhs, rhs, type, unsignd, trapOnError, bytecodeOffset(),
623 0 : mustPreserveNaN(type));
624 0 : curBlock_->add(ins);
625 0 : return ins;
626 : }
627 :
628 0 : MDefinition* mod(MDefinition* lhs, MDefinition* rhs, MIRType type, bool unsignd)
629 : {
630 0 : if (inDeadCode())
631 0 : return nullptr;
632 0 : bool trapOnError = !env().isAsmJS();
633 0 : if (!unsignd && type == MIRType::Int32) {
634 : // See block comment in div().
635 0 : auto* lhs2 = MTruncateToInt32::New(alloc(), lhs);
636 0 : curBlock_->add(lhs2);
637 0 : lhs = lhs2;
638 0 : auto* rhs2 = MTruncateToInt32::New(alloc(), rhs);
639 0 : curBlock_->add(rhs2);
640 0 : rhs = rhs2;
641 : }
642 0 : auto* ins = MMod::New(alloc(), lhs, rhs, type, unsignd, trapOnError, bytecodeOffset());
643 0 : curBlock_->add(ins);
644 0 : return ins;
645 : }
646 :
647 0 : MDefinition* bitnot(MDefinition* op)
648 : {
649 0 : if (inDeadCode())
650 0 : return nullptr;
651 0 : auto* ins = MBitNot::NewInt32(alloc(), op);
652 0 : curBlock_->add(ins);
653 0 : return ins;
654 : }
655 :
656 0 : MDefinition* select(MDefinition* trueExpr, MDefinition* falseExpr, MDefinition* condExpr)
657 : {
658 0 : if (inDeadCode())
659 0 : return nullptr;
660 0 : auto* ins = MWasmSelect::New(alloc(), trueExpr, falseExpr, condExpr);
661 0 : curBlock_->add(ins);
662 0 : return ins;
663 : }
664 :
665 0 : MDefinition* extendI32(MDefinition* op, bool isUnsigned)
666 : {
667 0 : if (inDeadCode())
668 0 : return nullptr;
669 0 : auto* ins = MExtendInt32ToInt64::New(alloc(), op, isUnsigned);
670 0 : curBlock_->add(ins);
671 0 : return ins;
672 : }
673 :
674 0 : MDefinition* convertI64ToFloatingPoint(MDefinition* op, MIRType type, bool isUnsigned)
675 : {
676 0 : if (inDeadCode())
677 0 : return nullptr;
678 0 : auto* ins = MInt64ToFloatingPoint::New(alloc(), op, type, bytecodeOffset(), isUnsigned);
679 0 : curBlock_->add(ins);
680 0 : return ins;
681 : }
682 :
683 0 : MDefinition* rotate(MDefinition* input, MDefinition* count, MIRType type, bool left)
684 : {
685 0 : if (inDeadCode())
686 0 : return nullptr;
687 0 : auto* ins = MRotate::New(alloc(), input, count, type, left);
688 0 : curBlock_->add(ins);
689 0 : return ins;
690 : }
691 :
692 : template <class T>
693 0 : MDefinition* truncate(MDefinition* op, bool isUnsigned)
694 : {
695 0 : if (inDeadCode())
696 0 : return nullptr;
697 0 : auto* ins = T::New(alloc(), op, isUnsigned, bytecodeOffset());
698 0 : curBlock_->add(ins);
699 0 : return ins;
700 : }
701 :
702 0 : MDefinition* compare(MDefinition* lhs, MDefinition* rhs, JSOp op, MCompare::CompareType type)
703 : {
704 0 : if (inDeadCode())
705 0 : return nullptr;
706 0 : auto* ins = MCompare::New(alloc(), lhs, rhs, op, type);
707 0 : curBlock_->add(ins);
708 0 : return ins;
709 : }
710 :
711 0 : void assign(unsigned slot, MDefinition* def)
712 : {
713 0 : if (inDeadCode())
714 0 : return;
715 0 : curBlock_->setSlot(info().localSlot(slot), def);
716 : }
717 :
718 : private:
719 0 : MWasmLoadTls* maybeLoadMemoryBase() {
720 0 : MWasmLoadTls* load = nullptr;
721 : #ifdef JS_CODEGEN_X86
722 : AliasSet aliases = env_.maxMemoryLength.isSome() ? AliasSet::None()
723 : : AliasSet::Load(AliasSet::WasmHeapMeta);
724 : load = MWasmLoadTls::New(alloc(), tlsPointer_, offsetof(wasm::TlsData, memoryBase),
725 : MIRType::Pointer, aliases);
726 : curBlock_->add(load);
727 : #endif
728 0 : return load;
729 : }
730 :
731 0 : MWasmLoadTls* maybeLoadBoundsCheckLimit() {
732 0 : MWasmLoadTls* load = nullptr;
733 : #ifndef WASM_HUGE_MEMORY
734 : AliasSet aliases = env_.maxMemoryLength.isSome() ? AliasSet::None()
735 : : AliasSet::Load(AliasSet::WasmHeapMeta);
736 : load = MWasmLoadTls::New(alloc(), tlsPointer_, offsetof(wasm::TlsData, boundsCheckLimit),
737 : MIRType::Int32, aliases);
738 : curBlock_->add(load);
739 : #endif
740 0 : return load;
741 : }
742 :
743 0 : void checkOffsetAndBounds(MemoryAccessDesc* access, MDefinition** base)
744 : {
745 : // If the offset is bigger than the guard region, a separate instruction
746 : // is necessary to add the offset to the base and check for overflow.
747 0 : if (access->offset() >= OffsetGuardLimit || !JitOptions.wasmFoldOffsets) {
748 0 : auto* ins = MWasmAddOffset::New(alloc(), *base, access->offset(), bytecodeOffset());
749 0 : curBlock_->add(ins);
750 :
751 0 : *base = ins;
752 0 : access->clearOffset();
753 : }
754 :
755 0 : MWasmLoadTls* boundsCheckLimit = maybeLoadBoundsCheckLimit();
756 0 : if (boundsCheckLimit)
757 0 : curBlock_->add(MWasmBoundsCheck::New(alloc(), *base, boundsCheckLimit, bytecodeOffset()));
758 0 : }
759 :
760 : public:
761 0 : MDefinition* load(MDefinition* base, MemoryAccessDesc* access, ValType result)
762 : {
763 0 : if (inDeadCode())
764 0 : return nullptr;
765 :
766 0 : MWasmLoadTls* memoryBase = maybeLoadMemoryBase();
767 0 : MInstruction* load = nullptr;
768 0 : if (access->isPlainAsmJS()) {
769 0 : MOZ_ASSERT(access->offset() == 0);
770 0 : MWasmLoadTls* boundsCheckLimit = maybeLoadBoundsCheckLimit();
771 0 : load = MAsmJSLoadHeap::New(alloc(), memoryBase, base, boundsCheckLimit, access->type());
772 : } else {
773 0 : checkOffsetAndBounds(access, &base);
774 0 : load = MWasmLoad::New(alloc(), memoryBase, base, *access, ToMIRType(result));
775 : }
776 :
777 0 : if (load)
778 0 : curBlock_->add(load);
779 :
780 0 : return load;
781 : }
782 :
783 0 : MOZ_MUST_USE bool store(MDefinition* base, MemoryAccessDesc* access, MDefinition* v)
784 : {
785 0 : if (inDeadCode())
786 0 : return true;
787 :
788 0 : MWasmLoadTls* memoryBase = maybeLoadMemoryBase();
789 0 : MInstruction* store = nullptr;
790 0 : if (access->isPlainAsmJS()) {
791 0 : MOZ_ASSERT(access->offset() == 0);
792 0 : MWasmLoadTls* boundsCheckLimit = maybeLoadBoundsCheckLimit();
793 0 : store = MAsmJSStoreHeap::New(alloc(), memoryBase, base, boundsCheckLimit,
794 0 : access->type(), v);
795 : } else {
796 0 : checkOffsetAndBounds(access, &base);
797 0 : store = MWasmStore::New(alloc(), memoryBase, base, *access, v);
798 : }
799 :
800 0 : if (store)
801 0 : curBlock_->add(store);
802 :
803 0 : return !!store;
804 : }
805 :
806 0 : MDefinition* atomicCompareExchangeHeap(MDefinition* base, MemoryAccessDesc* access,
807 : MDefinition* oldv, MDefinition* newv)
808 : {
809 0 : if (inDeadCode())
810 0 : return nullptr;
811 :
812 0 : checkOffsetAndBounds(access, &base);
813 0 : MWasmLoadTls* memoryBase = maybeLoadMemoryBase();
814 0 : auto* cas = MAsmJSCompareExchangeHeap::New(alloc(), bytecodeOffset(), memoryBase, base,
815 0 : *access, oldv, newv, tlsPointer_);
816 0 : if (cas)
817 0 : curBlock_->add(cas);
818 0 : return cas;
819 : }
820 :
821 0 : MDefinition* atomicExchangeHeap(MDefinition* base, MemoryAccessDesc* access,
822 : MDefinition* value)
823 : {
824 0 : if (inDeadCode())
825 0 : return nullptr;
826 :
827 0 : checkOffsetAndBounds(access, &base);
828 0 : MWasmLoadTls* memoryBase = maybeLoadMemoryBase();
829 0 : auto* cas = MAsmJSAtomicExchangeHeap::New(alloc(), bytecodeOffset(), memoryBase, base,
830 0 : *access, value, tlsPointer_);
831 0 : if (cas)
832 0 : curBlock_->add(cas);
833 0 : return cas;
834 : }
835 :
836 0 : MDefinition* atomicBinopHeap(js::jit::AtomicOp op,
837 : MDefinition* base, MemoryAccessDesc* access, MDefinition* v)
838 : {
839 0 : if (inDeadCode())
840 0 : return nullptr;
841 :
842 0 : checkOffsetAndBounds(access, &base);
843 0 : MWasmLoadTls* memoryBase = maybeLoadMemoryBase();
844 0 : auto* binop = MAsmJSAtomicBinopHeap::New(alloc(), bytecodeOffset(), op, memoryBase, base,
845 0 : *access, v, tlsPointer_);
846 0 : if (binop)
847 0 : curBlock_->add(binop);
848 0 : return binop;
849 : }
850 :
851 0 : MDefinition* loadGlobalVar(unsigned globalDataOffset, bool isConst, MIRType type)
852 : {
853 0 : if (inDeadCode())
854 0 : return nullptr;
855 :
856 0 : auto* load = MWasmLoadGlobalVar::New(alloc(), type, globalDataOffset, isConst, tlsPointer_);
857 0 : curBlock_->add(load);
858 0 : return load;
859 : }
860 :
861 0 : void storeGlobalVar(uint32_t globalDataOffset, MDefinition* v)
862 : {
863 0 : if (inDeadCode())
864 0 : return;
865 0 : curBlock_->add(MWasmStoreGlobalVar::New(alloc(), globalDataOffset, v, tlsPointer_));
866 : }
867 :
868 0 : void addInterruptCheck()
869 : {
870 : // We rely on signal handlers for interrupts on Asm.JS/Wasm
871 0 : MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
872 0 : }
873 :
874 0 : MDefinition* extractSimdElement(unsigned lane, MDefinition* base, MIRType type, SimdSign sign)
875 : {
876 0 : if (inDeadCode())
877 0 : return nullptr;
878 :
879 0 : MOZ_ASSERT(IsSimdType(base->type()));
880 0 : MOZ_ASSERT(!IsSimdType(type));
881 0 : auto* ins = MSimdExtractElement::New(alloc(), base, type, lane, sign);
882 0 : curBlock_->add(ins);
883 0 : return ins;
884 : }
885 :
886 : template<typename T>
887 0 : MDefinition* constructSimd(MDefinition* x, MDefinition* y, MDefinition* z, MDefinition* w,
888 : MIRType type)
889 : {
890 0 : if (inDeadCode())
891 0 : return nullptr;
892 :
893 0 : MOZ_ASSERT(IsSimdType(type));
894 0 : T* ins = T::New(alloc(), type, x, y, z, w);
895 0 : curBlock_->add(ins);
896 0 : return ins;
897 : }
898 :
899 : /***************************************************************** Calls */
900 :
901 : // The IonMonkey backend maintains a single stack offset (from the stack
902 : // pointer to the base of the frame) by adding the total amount of spill
903 : // space required plus the maximum stack required for argument passing.
904 : // Since we do not use IonMonkey's MPrepareCall/MPassArg/MCall, we must
905 : // manually accumulate, for the entire function, the maximum required stack
906 : // space for argument passing. (This is passed to the CodeGenerator via
907 : // MIRGenerator::maxWasmStackArgBytes.) Naively, this would just be the
908 : // maximum of the stack space required for each individual call (as
909 : // determined by the call ABI). However, as an optimization, arguments are
910 : // stored to the stack immediately after evaluation (to decrease live
911 : // ranges and reduce spilling). This introduces the complexity that,
912 : // between evaluating an argument and making the call, another argument
913 : // evaluation could perform a call that also needs to store to the stack.
914 : // When this occurs childClobbers_ = true and the parent expression's
915 : // arguments are stored above the maximum depth clobbered by a child
916 : // expression.
917 :
918 0 : bool startCall(CallCompileState* call)
919 : {
920 : // Always push calls to maintain the invariant that if we're inDeadCode
921 : // in finishCall, we have something to pop.
922 0 : return callStack_.append(call);
923 : }
924 :
925 0 : bool passInstance(CallCompileState* args)
926 : {
927 0 : if (inDeadCode())
928 0 : return true;
929 :
930 : // Should only pass an instance once.
931 0 : MOZ_ASSERT(args->instanceArg_ == ABIArg());
932 0 : args->instanceArg_ = args->abi_.next(MIRType::Pointer);
933 0 : return true;
934 : }
935 :
936 0 : bool passArg(MDefinition* argDef, ValType type, CallCompileState* call)
937 : {
938 0 : if (inDeadCode())
939 0 : return true;
940 :
941 0 : ABIArg arg = call->abi_.next(ToMIRType(type));
942 0 : switch (arg.kind()) {
943 : #ifdef JS_CODEGEN_REGISTER_PAIR
944 : case ABIArg::GPR_PAIR: {
945 : auto mirLow = MWrapInt64ToInt32::New(alloc(), argDef, /* bottomHalf = */ true);
946 : curBlock_->add(mirLow);
947 : auto mirHigh = MWrapInt64ToInt32::New(alloc(), argDef, /* bottomHalf = */ false);
948 : curBlock_->add(mirHigh);
949 : return call->regArgs_.append(MWasmCall::Arg(AnyRegister(arg.gpr64().low), mirLow)) &&
950 : call->regArgs_.append(MWasmCall::Arg(AnyRegister(arg.gpr64().high), mirHigh));
951 : }
952 : #endif
953 : case ABIArg::GPR:
954 : case ABIArg::FPU:
955 0 : return call->regArgs_.append(MWasmCall::Arg(arg.reg(), argDef));
956 : case ABIArg::Stack: {
957 0 : auto* mir = MWasmStackArg::New(alloc(), arg.offsetFromArgBase(), argDef);
958 0 : curBlock_->add(mir);
959 0 : return call->stackArgs_.append(mir);
960 : }
961 : default:
962 0 : MOZ_CRASH("Unknown ABIArg kind.");
963 : }
964 : }
965 :
966 0 : void propagateMaxStackArgBytes(uint32_t stackBytes)
967 : {
968 0 : if (callStack_.empty()) {
969 : // Outermost call
970 0 : maxStackArgBytes_ = Max(maxStackArgBytes_, stackBytes);
971 0 : return;
972 : }
973 :
974 : // Non-outermost call
975 0 : CallCompileState* outer = callStack_.back();
976 0 : outer->maxChildStackBytes_ = Max(outer->maxChildStackBytes_, stackBytes);
977 0 : if (stackBytes && !outer->stackArgs_.empty())
978 0 : outer->childClobbers_ = true;
979 : }
980 :
981 0 : bool finishCall(CallCompileState* call)
982 : {
983 0 : MOZ_ALWAYS_TRUE(callStack_.popCopy() == call);
984 :
985 0 : if (inDeadCode()) {
986 0 : propagateMaxStackArgBytes(call->maxChildStackBytes_);
987 0 : return true;
988 : }
989 :
990 0 : if (!call->regArgs_.append(MWasmCall::Arg(AnyRegister(WasmTlsReg), tlsPointer_)))
991 0 : return false;
992 :
993 0 : uint32_t stackBytes = call->abi_.stackBytesConsumedSoFar();
994 0 : if (call->childClobbers_) {
995 0 : call->spIncrement_ = AlignBytes(call->maxChildStackBytes_, WasmStackAlignment);
996 0 : for (MWasmStackArg* stackArg : call->stackArgs_)
997 0 : stackArg->incrementOffset(call->spIncrement_);
998 :
999 : // If instanceArg_ is not initialized then instanceArg_.kind() != ABIArg::Stack
1000 0 : if (call->instanceArg_.kind() == ABIArg::Stack) {
1001 0 : call->instanceArg_ = ABIArg(call->instanceArg_.offsetFromArgBase() +
1002 0 : call->spIncrement_);
1003 : }
1004 :
1005 0 : stackBytes += call->spIncrement_;
1006 : } else {
1007 0 : call->spIncrement_ = 0;
1008 0 : stackBytes = Max(stackBytes, call->maxChildStackBytes_);
1009 : }
1010 :
1011 0 : propagateMaxStackArgBytes(stackBytes);
1012 0 : return true;
1013 : }
1014 :
1015 0 : bool callDirect(const Sig& sig, uint32_t funcIndex, const CallCompileState& call,
1016 : MDefinition** def)
1017 : {
1018 0 : if (inDeadCode()) {
1019 0 : *def = nullptr;
1020 0 : return true;
1021 : }
1022 :
1023 0 : CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Func);
1024 0 : MIRType ret = ToMIRType(sig.ret());
1025 0 : auto callee = CalleeDesc::function(funcIndex);
1026 0 : auto* ins = MWasmCall::New(alloc(), desc, callee, call.regArgs_, ret, call.spIncrement_);
1027 0 : if (!ins)
1028 0 : return false;
1029 :
1030 0 : curBlock_->add(ins);
1031 0 : *def = ins;
1032 0 : return true;
1033 : }
1034 :
1035 0 : bool callIndirect(uint32_t sigIndex, MDefinition* index, const CallCompileState& call,
1036 : MDefinition** def)
1037 : {
1038 0 : if (inDeadCode()) {
1039 0 : *def = nullptr;
1040 0 : return true;
1041 : }
1042 :
1043 0 : const SigWithId& sig = env_.sigs[sigIndex];
1044 :
1045 0 : CalleeDesc callee;
1046 0 : if (env_.isAsmJS()) {
1047 0 : MOZ_ASSERT(sig.id.kind() == SigIdDesc::Kind::None);
1048 0 : const TableDesc& table = env_.tables[env_.asmJSSigToTableIndex[sigIndex]];
1049 0 : MOZ_ASSERT(IsPowerOfTwo(table.limits.initial));
1050 0 : MOZ_ASSERT(!table.external);
1051 :
1052 0 : MConstant* mask = MConstant::New(alloc(), Int32Value(table.limits.initial - 1));
1053 0 : curBlock_->add(mask);
1054 0 : MBitAnd* maskedIndex = MBitAnd::New(alloc(), index, mask, MIRType::Int32);
1055 0 : curBlock_->add(maskedIndex);
1056 :
1057 0 : index = maskedIndex;
1058 0 : callee = CalleeDesc::asmJSTable(table);
1059 : } else {
1060 0 : MOZ_ASSERT(sig.id.kind() != SigIdDesc::Kind::None);
1061 0 : MOZ_ASSERT(env_.tables.length() == 1);
1062 0 : const TableDesc& table = env_.tables[0];
1063 0 : callee = CalleeDesc::wasmTable(table, sig.id);
1064 : }
1065 :
1066 0 : CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Dynamic);
1067 0 : auto* ins = MWasmCall::New(alloc(), desc, callee, call.regArgs_, ToMIRType(sig.ret()),
1068 0 : call.spIncrement_, index);
1069 0 : if (!ins)
1070 0 : return false;
1071 :
1072 0 : curBlock_->add(ins);
1073 0 : *def = ins;
1074 0 : return true;
1075 : }
1076 :
1077 0 : bool callImport(unsigned globalDataOffset, const CallCompileState& call, ExprType ret,
1078 : MDefinition** def)
1079 : {
1080 0 : if (inDeadCode()) {
1081 0 : *def = nullptr;
1082 0 : return true;
1083 : }
1084 :
1085 0 : CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Dynamic);
1086 0 : auto callee = CalleeDesc::import(globalDataOffset);
1087 0 : auto* ins = MWasmCall::New(alloc(), desc, callee, call.regArgs_, ToMIRType(ret),
1088 0 : call.spIncrement_);
1089 0 : if (!ins)
1090 0 : return false;
1091 :
1092 0 : curBlock_->add(ins);
1093 0 : *def = ins;
1094 0 : return true;
1095 : }
1096 :
1097 0 : bool builtinCall(SymbolicAddress builtin, const CallCompileState& call, ValType ret,
1098 : MDefinition** def)
1099 : {
1100 0 : if (inDeadCode()) {
1101 0 : *def = nullptr;
1102 0 : return true;
1103 : }
1104 :
1105 0 : CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Symbolic);
1106 0 : auto callee = CalleeDesc::builtin(builtin);
1107 0 : auto* ins = MWasmCall::New(alloc(), desc, callee, call.regArgs_, ToMIRType(ret),
1108 0 : call.spIncrement_);
1109 0 : if (!ins)
1110 0 : return false;
1111 :
1112 0 : curBlock_->add(ins);
1113 0 : *def = ins;
1114 0 : return true;
1115 : }
1116 :
1117 0 : bool builtinInstanceMethodCall(SymbolicAddress builtin, const CallCompileState& call,
1118 : ValType ret, MDefinition** def)
1119 : {
1120 0 : if (inDeadCode()) {
1121 0 : *def = nullptr;
1122 0 : return true;
1123 : }
1124 :
1125 0 : CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Symbolic);
1126 0 : auto* ins = MWasmCall::NewBuiltinInstanceMethodCall(alloc(), desc, builtin,
1127 : call.instanceArg_, call.regArgs_,
1128 0 : ToMIRType(ret), call.spIncrement_);
1129 0 : if (!ins)
1130 0 : return false;
1131 :
1132 0 : curBlock_->add(ins);
1133 0 : *def = ins;
1134 0 : return true;
1135 : }
1136 :
1137 : /*********************************************** Control flow generation */
1138 :
1139 0 : inline bool inDeadCode() const {
1140 0 : return curBlock_ == nullptr;
1141 : }
1142 :
1143 0 : void returnExpr(MDefinition* operand)
1144 : {
1145 0 : if (inDeadCode())
1146 0 : return;
1147 :
1148 0 : MWasmReturn* ins = MWasmReturn::New(alloc(), operand);
1149 0 : curBlock_->end(ins);
1150 0 : curBlock_ = nullptr;
1151 : }
1152 :
1153 0 : void returnVoid()
1154 : {
1155 0 : if (inDeadCode())
1156 0 : return;
1157 :
1158 0 : MWasmReturnVoid* ins = MWasmReturnVoid::New(alloc());
1159 0 : curBlock_->end(ins);
1160 0 : curBlock_ = nullptr;
1161 : }
1162 :
1163 0 : void unreachableTrap()
1164 : {
1165 0 : if (inDeadCode())
1166 0 : return;
1167 :
1168 0 : auto* ins = MWasmTrap::New(alloc(), wasm::Trap::Unreachable, bytecodeOffset());
1169 0 : curBlock_->end(ins);
1170 0 : curBlock_ = nullptr;
1171 : }
1172 :
1173 : private:
1174 0 : static bool hasPushed(MBasicBlock* block)
1175 : {
1176 0 : uint32_t numPushed = block->stackDepth() - block->info().firstStackSlot();
1177 0 : MOZ_ASSERT(numPushed == 0 || numPushed == 1);
1178 0 : return numPushed;
1179 : }
1180 :
1181 : public:
1182 0 : void pushDef(MDefinition* def)
1183 : {
1184 0 : if (inDeadCode())
1185 0 : return;
1186 0 : MOZ_ASSERT(!hasPushed(curBlock_));
1187 0 : if (def && def->type() != MIRType::None)
1188 0 : curBlock_->push(def);
1189 : }
1190 :
1191 0 : MDefinition* popDefIfPushed()
1192 : {
1193 0 : if (!hasPushed(curBlock_))
1194 0 : return nullptr;
1195 0 : MDefinition* def = curBlock_->pop();
1196 0 : MOZ_ASSERT(def->type() != MIRType::Value);
1197 0 : return def;
1198 : }
1199 :
1200 : private:
1201 0 : void addJoinPredecessor(MDefinition* def, MBasicBlock** joinPred)
1202 : {
1203 0 : *joinPred = curBlock_;
1204 0 : if (inDeadCode())
1205 0 : return;
1206 0 : pushDef(def);
1207 : }
1208 :
1209 : public:
1210 0 : bool branchAndStartThen(MDefinition* cond, MBasicBlock** elseBlock)
1211 : {
1212 0 : if (inDeadCode()) {
1213 0 : *elseBlock = nullptr;
1214 : } else {
1215 : MBasicBlock* thenBlock;
1216 0 : if (!newBlock(curBlock_, &thenBlock))
1217 0 : return false;
1218 0 : if (!newBlock(curBlock_, elseBlock))
1219 0 : return false;
1220 :
1221 0 : curBlock_->end(MTest::New(alloc(), cond, thenBlock, *elseBlock));
1222 :
1223 0 : curBlock_ = thenBlock;
1224 0 : mirGraph().moveBlockToEnd(curBlock_);
1225 : }
1226 :
1227 0 : return startBlock();
1228 : }
1229 :
1230 0 : bool switchToElse(MBasicBlock* elseBlock, MBasicBlock** thenJoinPred)
1231 : {
1232 : MDefinition* ifDef;
1233 0 : if (!finishBlock(&ifDef))
1234 0 : return false;
1235 :
1236 0 : if (!elseBlock) {
1237 0 : *thenJoinPred = nullptr;
1238 : } else {
1239 0 : addJoinPredecessor(ifDef, thenJoinPred);
1240 :
1241 0 : curBlock_ = elseBlock;
1242 0 : mirGraph().moveBlockToEnd(curBlock_);
1243 : }
1244 :
1245 0 : return startBlock();
1246 : }
1247 :
1248 0 : bool joinIfElse(MBasicBlock* thenJoinPred, MDefinition** def)
1249 : {
1250 : MDefinition* elseDef;
1251 0 : if (!finishBlock(&elseDef))
1252 0 : return false;
1253 :
1254 0 : if (!thenJoinPred && inDeadCode()) {
1255 0 : *def = nullptr;
1256 : } else {
1257 : MBasicBlock* elseJoinPred;
1258 0 : addJoinPredecessor(elseDef, &elseJoinPred);
1259 :
1260 0 : mozilla::Array<MBasicBlock*, 2> blocks;
1261 0 : size_t numJoinPreds = 0;
1262 0 : if (thenJoinPred)
1263 0 : blocks[numJoinPreds++] = thenJoinPred;
1264 0 : if (elseJoinPred)
1265 0 : blocks[numJoinPreds++] = elseJoinPred;
1266 :
1267 0 : if (numJoinPreds == 0) {
1268 0 : *def = nullptr;
1269 0 : return true;
1270 : }
1271 :
1272 : MBasicBlock* join;
1273 0 : if (!goToNewBlock(blocks[0], &join))
1274 0 : return false;
1275 0 : for (size_t i = 1; i < numJoinPreds; ++i) {
1276 0 : if (!goToExistingBlock(blocks[i], join))
1277 0 : return false;
1278 : }
1279 :
1280 0 : curBlock_ = join;
1281 0 : *def = popDefIfPushed();
1282 : }
1283 :
1284 0 : return true;
1285 : }
1286 :
1287 0 : bool startBlock()
1288 : {
1289 0 : MOZ_ASSERT_IF(blockDepth_ < blockPatches_.length(), blockPatches_[blockDepth_].empty());
1290 0 : blockDepth_++;
1291 0 : return true;
1292 : }
1293 :
1294 0 : bool finishBlock(MDefinition** def)
1295 : {
1296 0 : MOZ_ASSERT(blockDepth_);
1297 0 : uint32_t topLabel = --blockDepth_;
1298 0 : return bindBranches(topLabel, def);
1299 : }
1300 :
1301 0 : bool startLoop(MBasicBlock** loopHeader)
1302 : {
1303 0 : *loopHeader = nullptr;
1304 :
1305 0 : blockDepth_++;
1306 0 : loopDepth_++;
1307 :
1308 0 : if (inDeadCode())
1309 0 : return true;
1310 :
1311 : // Create the loop header.
1312 0 : MOZ_ASSERT(curBlock_->loopDepth() == loopDepth_ - 1);
1313 0 : *loopHeader = MBasicBlock::New(mirGraph(), info(), curBlock_,
1314 : MBasicBlock::PENDING_LOOP_HEADER);
1315 0 : if (!*loopHeader)
1316 0 : return false;
1317 :
1318 0 : (*loopHeader)->setLoopDepth(loopDepth_);
1319 0 : mirGraph().addBlock(*loopHeader);
1320 0 : curBlock_->end(MGoto::New(alloc(), *loopHeader));
1321 :
1322 : MBasicBlock* body;
1323 0 : if (!goToNewBlock(*loopHeader, &body))
1324 0 : return false;
1325 0 : curBlock_ = body;
1326 0 : return true;
1327 : }
1328 :
1329 : private:
1330 0 : void fixupRedundantPhis(MBasicBlock* b)
1331 : {
1332 0 : for (size_t i = 0, depth = b->stackDepth(); i < depth; i++) {
1333 0 : MDefinition* def = b->getSlot(i);
1334 0 : if (def->isUnused())
1335 0 : b->setSlot(i, def->toPhi()->getOperand(0));
1336 : }
1337 0 : }
1338 :
1339 0 : bool setLoopBackedge(MBasicBlock* loopEntry, MBasicBlock* loopBody, MBasicBlock* backedge)
1340 : {
1341 0 : if (!loopEntry->setBackedgeWasm(backedge))
1342 0 : return false;
1343 :
1344 : // Flag all redundant phis as unused.
1345 0 : for (MPhiIterator phi = loopEntry->phisBegin(); phi != loopEntry->phisEnd(); phi++) {
1346 0 : MOZ_ASSERT(phi->numOperands() == 2);
1347 0 : if (phi->getOperand(0) == phi->getOperand(1))
1348 0 : phi->setUnused();
1349 : }
1350 :
1351 : // Fix up phis stored in the slots Vector of pending blocks.
1352 0 : for (ControlFlowPatchVector& patches : blockPatches_) {
1353 0 : for (ControlFlowPatch& p : patches) {
1354 0 : MBasicBlock* block = p.ins->block();
1355 0 : if (block->loopDepth() >= loopEntry->loopDepth())
1356 0 : fixupRedundantPhis(block);
1357 : }
1358 : }
1359 :
1360 : // The loop body, if any, might be referencing recycled phis too.
1361 0 : if (loopBody)
1362 0 : fixupRedundantPhis(loopBody);
1363 :
1364 : // Discard redundant phis and add to the free list.
1365 0 : for (MPhiIterator phi = loopEntry->phisBegin(); phi != loopEntry->phisEnd(); ) {
1366 0 : MPhi* entryDef = *phi++;
1367 0 : if (!entryDef->isUnused())
1368 0 : continue;
1369 :
1370 0 : entryDef->justReplaceAllUsesWith(entryDef->getOperand(0));
1371 0 : loopEntry->discardPhi(entryDef);
1372 0 : mirGraph().addPhiToFreeList(entryDef);
1373 : }
1374 :
1375 0 : return true;
1376 : }
1377 :
1378 : public:
1379 0 : bool closeLoop(MBasicBlock* loopHeader, MDefinition** loopResult)
1380 : {
1381 0 : MOZ_ASSERT(blockDepth_ >= 1);
1382 0 : MOZ_ASSERT(loopDepth_);
1383 :
1384 0 : uint32_t headerLabel = blockDepth_ - 1;
1385 :
1386 0 : if (!loopHeader) {
1387 0 : MOZ_ASSERT(inDeadCode());
1388 0 : MOZ_ASSERT(headerLabel >= blockPatches_.length() || blockPatches_[headerLabel].empty());
1389 0 : blockDepth_--;
1390 0 : loopDepth_--;
1391 0 : *loopResult = nullptr;
1392 0 : return true;
1393 : }
1394 :
1395 : // Op::Loop doesn't have an implicit backedge so temporarily set
1396 : // aside the end of the loop body to bind backedges.
1397 0 : MBasicBlock* loopBody = curBlock_;
1398 0 : curBlock_ = nullptr;
1399 :
1400 : // As explained in bug 1253544, Ion apparently has an invariant that
1401 : // there is only one backedge to loop headers. To handle wasm's ability
1402 : // to have multiple backedges to the same loop header, we bind all those
1403 : // branches as forward jumps to a single backward jump. This is
1404 : // unfortunate but the optimizer is able to fold these into single jumps
1405 : // to backedges.
1406 : MDefinition* _;
1407 0 : if (!bindBranches(headerLabel, &_))
1408 0 : return false;
1409 :
1410 0 : MOZ_ASSERT(loopHeader->loopDepth() == loopDepth_);
1411 :
1412 0 : if (curBlock_) {
1413 : // We're on the loop backedge block, created by bindBranches.
1414 0 : if (hasPushed(curBlock_))
1415 0 : curBlock_->pop();
1416 :
1417 0 : MOZ_ASSERT(curBlock_->loopDepth() == loopDepth_);
1418 0 : curBlock_->end(MGoto::New(alloc(), loopHeader));
1419 0 : if (!setLoopBackedge(loopHeader, loopBody, curBlock_))
1420 0 : return false;
1421 : }
1422 :
1423 0 : curBlock_ = loopBody;
1424 :
1425 0 : loopDepth_--;
1426 :
1427 : // If the loop depth still at the inner loop body, correct it.
1428 0 : if (curBlock_ && curBlock_->loopDepth() != loopDepth_) {
1429 : MBasicBlock* out;
1430 0 : if (!goToNewBlock(curBlock_, &out))
1431 0 : return false;
1432 0 : curBlock_ = out;
1433 : }
1434 :
1435 0 : blockDepth_ -= 1;
1436 0 : *loopResult = inDeadCode() ? nullptr : popDefIfPushed();
1437 0 : return true;
1438 : }
1439 :
1440 0 : bool addControlFlowPatch(MControlInstruction* ins, uint32_t relative, uint32_t index) {
1441 0 : MOZ_ASSERT(relative < blockDepth_);
1442 0 : uint32_t absolute = blockDepth_ - 1 - relative;
1443 :
1444 0 : if (absolute >= blockPatches_.length() && !blockPatches_.resize(absolute + 1))
1445 0 : return false;
1446 :
1447 0 : return blockPatches_[absolute].append(ControlFlowPatch(ins, index));
1448 : }
1449 :
1450 0 : bool br(uint32_t relativeDepth, MDefinition* maybeValue)
1451 : {
1452 0 : if (inDeadCode())
1453 0 : return true;
1454 :
1455 0 : MGoto* jump = MGoto::New(alloc());
1456 0 : if (!addControlFlowPatch(jump, relativeDepth, MGoto::TargetIndex))
1457 0 : return false;
1458 :
1459 0 : pushDef(maybeValue);
1460 :
1461 0 : curBlock_->end(jump);
1462 0 : curBlock_ = nullptr;
1463 0 : return true;
1464 : }
1465 :
1466 0 : bool brIf(uint32_t relativeDepth, MDefinition* maybeValue, MDefinition* condition)
1467 : {
1468 0 : if (inDeadCode())
1469 0 : return true;
1470 :
1471 0 : MBasicBlock* joinBlock = nullptr;
1472 0 : if (!newBlock(curBlock_, &joinBlock))
1473 0 : return false;
1474 :
1475 0 : MTest* test = MTest::New(alloc(), condition, joinBlock);
1476 0 : if (!addControlFlowPatch(test, relativeDepth, MTest::TrueBranchIndex))
1477 0 : return false;
1478 :
1479 0 : pushDef(maybeValue);
1480 :
1481 0 : curBlock_->end(test);
1482 0 : curBlock_ = joinBlock;
1483 0 : return true;
1484 : }
1485 :
1486 0 : bool brTable(MDefinition* operand, uint32_t defaultDepth, const Uint32Vector& depths,
1487 : MDefinition* maybeValue)
1488 : {
1489 0 : if (inDeadCode())
1490 0 : return true;
1491 :
1492 0 : size_t numCases = depths.length();
1493 0 : MOZ_ASSERT(numCases <= INT32_MAX);
1494 0 : MOZ_ASSERT(numCases);
1495 :
1496 0 : MTableSwitch* table = MTableSwitch::New(alloc(), operand, 0, int32_t(numCases - 1));
1497 :
1498 : size_t defaultIndex;
1499 0 : if (!table->addDefault(nullptr, &defaultIndex))
1500 0 : return false;
1501 0 : if (!addControlFlowPatch(table, defaultDepth, defaultIndex))
1502 0 : return false;
1503 :
1504 : typedef HashMap<uint32_t, uint32_t, DefaultHasher<uint32_t>, SystemAllocPolicy>
1505 : IndexToCaseMap;
1506 :
1507 0 : IndexToCaseMap indexToCase;
1508 0 : if (!indexToCase.init() || !indexToCase.put(defaultDepth, defaultIndex))
1509 0 : return false;
1510 :
1511 0 : for (size_t i = 0; i < numCases; i++) {
1512 0 : uint32_t depth = depths[i];
1513 :
1514 : size_t caseIndex;
1515 0 : IndexToCaseMap::AddPtr p = indexToCase.lookupForAdd(depth);
1516 0 : if (!p) {
1517 0 : if (!table->addSuccessor(nullptr, &caseIndex))
1518 0 : return false;
1519 0 : if (!addControlFlowPatch(table, depth, caseIndex))
1520 0 : return false;
1521 0 : if (!indexToCase.add(p, depth, caseIndex))
1522 0 : return false;
1523 : } else {
1524 0 : caseIndex = p->value();
1525 : }
1526 :
1527 0 : if (!table->addCase(caseIndex))
1528 0 : return false;
1529 : }
1530 :
1531 0 : pushDef(maybeValue);
1532 :
1533 0 : curBlock_->end(table);
1534 0 : curBlock_ = nullptr;
1535 :
1536 0 : return true;
1537 : }
1538 :
1539 : /************************************************************ DECODING ***/
1540 :
1541 0 : uint32_t readCallSiteLineOrBytecode() {
1542 0 : if (!func_.callSiteLineNums().empty())
1543 0 : return func_.callSiteLineNums()[lastReadCallSite_++];
1544 0 : return iter_.lastOpcodeOffset();
1545 : }
1546 :
1547 : #if DEBUG
1548 0 : bool done() const { return iter_.done(); }
1549 : #endif
1550 :
1551 : /*************************************************************************/
1552 : private:
1553 0 : bool newBlock(MBasicBlock* pred, MBasicBlock** block)
1554 : {
1555 0 : *block = MBasicBlock::New(mirGraph(), info(), pred, MBasicBlock::NORMAL);
1556 0 : if (!*block)
1557 0 : return false;
1558 0 : mirGraph().addBlock(*block);
1559 0 : (*block)->setLoopDepth(loopDepth_);
1560 0 : return true;
1561 : }
1562 :
1563 0 : bool goToNewBlock(MBasicBlock* pred, MBasicBlock** block)
1564 : {
1565 0 : if (!newBlock(pred, block))
1566 0 : return false;
1567 0 : pred->end(MGoto::New(alloc(), *block));
1568 0 : return true;
1569 : }
1570 :
1571 0 : bool goToExistingBlock(MBasicBlock* prev, MBasicBlock* next)
1572 : {
1573 0 : MOZ_ASSERT(prev);
1574 0 : MOZ_ASSERT(next);
1575 0 : prev->end(MGoto::New(alloc(), next));
1576 0 : return next->addPredecessor(alloc(), prev);
1577 : }
1578 :
1579 0 : bool bindBranches(uint32_t absolute, MDefinition** def)
1580 : {
1581 0 : if (absolute >= blockPatches_.length() || blockPatches_[absolute].empty()) {
1582 0 : *def = inDeadCode() ? nullptr : popDefIfPushed();
1583 0 : return true;
1584 : }
1585 :
1586 0 : ControlFlowPatchVector& patches = blockPatches_[absolute];
1587 0 : MControlInstruction* ins = patches[0].ins;
1588 0 : MBasicBlock* pred = ins->block();
1589 :
1590 0 : MBasicBlock* join = nullptr;
1591 0 : if (!newBlock(pred, &join))
1592 0 : return false;
1593 :
1594 0 : pred->mark();
1595 0 : ins->replaceSuccessor(patches[0].index, join);
1596 :
1597 0 : for (size_t i = 1; i < patches.length(); i++) {
1598 0 : ins = patches[i].ins;
1599 :
1600 0 : pred = ins->block();
1601 0 : if (!pred->isMarked()) {
1602 0 : if (!join->addPredecessor(alloc(), pred))
1603 0 : return false;
1604 0 : pred->mark();
1605 : }
1606 :
1607 0 : ins->replaceSuccessor(patches[i].index, join);
1608 : }
1609 :
1610 0 : MOZ_ASSERT_IF(curBlock_, !curBlock_->isMarked());
1611 0 : for (uint32_t i = 0; i < join->numPredecessors(); i++)
1612 0 : join->getPredecessor(i)->unmark();
1613 :
1614 0 : if (curBlock_ && !goToExistingBlock(curBlock_, join))
1615 0 : return false;
1616 :
1617 0 : curBlock_ = join;
1618 :
1619 0 : *def = popDefIfPushed();
1620 :
1621 0 : patches.clear();
1622 0 : return true;
1623 : }
1624 : };
1625 :
1626 : template <>
1627 0 : MDefinition* FunctionCompiler::unary<MToFloat32>(MDefinition* op)
1628 : {
1629 0 : if (inDeadCode())
1630 0 : return nullptr;
1631 0 : auto* ins = MToFloat32::New(alloc(), op, mustPreserveNaN(op->type()));
1632 0 : curBlock_->add(ins);
1633 0 : return ins;
1634 : }
1635 :
1636 : template <>
1637 0 : MDefinition* FunctionCompiler::unary<MTruncateToInt32>(MDefinition* op)
1638 : {
1639 0 : if (inDeadCode())
1640 0 : return nullptr;
1641 0 : auto* ins = MTruncateToInt32::New(alloc(), op, bytecodeOffset());
1642 0 : curBlock_->add(ins);
1643 0 : return ins;
1644 : }
1645 :
1646 : template <>
1647 0 : MDefinition* FunctionCompiler::unary<MNot>(MDefinition* op)
1648 : {
1649 0 : if (inDeadCode())
1650 0 : return nullptr;
1651 0 : auto* ins = MNot::NewInt32(alloc(), op);
1652 0 : curBlock_->add(ins);
1653 0 : return ins;
1654 : }
1655 :
1656 : template <>
1657 0 : MDefinition* FunctionCompiler::unary<MAbs>(MDefinition* op, MIRType type)
1658 : {
1659 0 : if (inDeadCode())
1660 0 : return nullptr;
1661 0 : auto* ins = MAbs::NewWasm(alloc(), op, type);
1662 0 : curBlock_->add(ins);
1663 0 : return ins;
1664 : }
1665 :
1666 : } // end anonymous namespace
1667 :
1668 : static bool
1669 0 : EmitI32Const(FunctionCompiler& f)
1670 : {
1671 : int32_t i32;
1672 0 : if (!f.iter().readI32Const(&i32))
1673 0 : return false;
1674 :
1675 0 : f.iter().setResult(f.constant(Int32Value(i32), MIRType::Int32));
1676 0 : return true;
1677 : }
1678 :
1679 : static bool
1680 0 : EmitI64Const(FunctionCompiler& f)
1681 : {
1682 : int64_t i64;
1683 0 : if (!f.iter().readI64Const(&i64))
1684 0 : return false;
1685 :
1686 0 : f.iter().setResult(f.constant(i64));
1687 0 : return true;
1688 : }
1689 :
1690 : static bool
1691 0 : EmitF32Const(FunctionCompiler& f)
1692 : {
1693 : float f32;
1694 0 : if (!f.iter().readF32Const(&f32))
1695 0 : return false;
1696 :
1697 0 : f.iter().setResult(f.constant(f32));
1698 0 : return true;
1699 : }
1700 :
1701 : static bool
1702 0 : EmitF64Const(FunctionCompiler& f)
1703 : {
1704 : double f64;
1705 0 : if (!f.iter().readF64Const(&f64))
1706 0 : return false;
1707 :
1708 0 : f.iter().setResult(f.constant(f64));
1709 0 : return true;
1710 : }
1711 :
1712 : static bool
1713 0 : EmitI8x16Const(FunctionCompiler& f)
1714 : {
1715 : I8x16 i8x16;
1716 0 : if (!f.iter().readI8x16Const(&i8x16))
1717 0 : return false;
1718 :
1719 0 : f.iter().setResult(f.constant(SimdConstant::CreateX16(i8x16), MIRType::Int8x16));
1720 0 : return true;
1721 : }
1722 :
1723 : static bool
1724 0 : EmitI16x8Const(FunctionCompiler& f)
1725 : {
1726 : I16x8 i16x8;
1727 0 : if (!f.iter().readI16x8Const(&i16x8))
1728 0 : return false;
1729 :
1730 0 : f.iter().setResult(f.constant(SimdConstant::CreateX8(i16x8), MIRType::Int16x8));
1731 0 : return true;
1732 : }
1733 :
1734 : static bool
1735 0 : EmitI32x4Const(FunctionCompiler& f)
1736 : {
1737 : I32x4 i32x4;
1738 0 : if (!f.iter().readI32x4Const(&i32x4))
1739 0 : return false;
1740 :
1741 0 : f.iter().setResult(f.constant(SimdConstant::CreateX4(i32x4), MIRType::Int32x4));
1742 0 : return true;
1743 : }
1744 :
1745 : static bool
1746 0 : EmitF32x4Const(FunctionCompiler& f)
1747 : {
1748 : F32x4 f32x4;
1749 0 : if (!f.iter().readF32x4Const(&f32x4))
1750 0 : return false;
1751 :
1752 0 : f.iter().setResult(f.constant(SimdConstant::CreateX4(f32x4), MIRType::Float32x4));
1753 0 : return true;
1754 : }
1755 :
1756 : static bool
1757 0 : EmitB8x16Const(FunctionCompiler& f)
1758 : {
1759 : I8x16 i8x16;
1760 0 : if (!f.iter().readB8x16Const(&i8x16))
1761 0 : return false;
1762 :
1763 0 : f.iter().setResult(f.constant(SimdConstant::CreateX16(i8x16), MIRType::Bool8x16));
1764 0 : return true;
1765 : }
1766 :
1767 : static bool
1768 0 : EmitB16x8Const(FunctionCompiler& f)
1769 : {
1770 : I16x8 i16x8;
1771 0 : if (!f.iter().readB16x8Const(&i16x8))
1772 0 : return false;
1773 :
1774 0 : f.iter().setResult(f.constant(SimdConstant::CreateX8(i16x8), MIRType::Bool16x8));
1775 0 : return true;
1776 : }
1777 :
1778 : static bool
1779 0 : EmitB32x4Const(FunctionCompiler& f)
1780 : {
1781 : I32x4 i32x4;
1782 0 : if (!f.iter().readB32x4Const(&i32x4))
1783 0 : return false;
1784 :
1785 0 : f.iter().setResult(f.constant(SimdConstant::CreateX4(i32x4), MIRType::Bool32x4));
1786 0 : return true;
1787 : }
1788 :
1789 : static bool
1790 0 : EmitBlock(FunctionCompiler& f)
1791 : {
1792 0 : return f.iter().readBlock() &&
1793 0 : f.startBlock();
1794 : }
1795 :
1796 : static bool
1797 0 : EmitLoop(FunctionCompiler& f)
1798 : {
1799 0 : if (!f.iter().readLoop())
1800 0 : return false;
1801 :
1802 : MBasicBlock* loopHeader;
1803 0 : if (!f.startLoop(&loopHeader))
1804 0 : return false;
1805 :
1806 0 : f.addInterruptCheck();
1807 :
1808 0 : f.iter().controlItem() = loopHeader;
1809 0 : return true;
1810 : }
1811 :
1812 : static bool
1813 0 : EmitIf(FunctionCompiler& f)
1814 : {
1815 0 : MDefinition* condition = nullptr;
1816 0 : if (!f.iter().readIf(&condition))
1817 0 : return false;
1818 :
1819 : MBasicBlock* elseBlock;
1820 0 : if (!f.branchAndStartThen(condition, &elseBlock))
1821 0 : return false;
1822 :
1823 0 : f.iter().controlItem() = elseBlock;
1824 0 : return true;
1825 : }
1826 :
1827 : static bool
1828 0 : EmitElse(FunctionCompiler& f)
1829 : {
1830 : ExprType thenType;
1831 : MDefinition* thenValue;
1832 0 : if (!f.iter().readElse(&thenType, &thenValue))
1833 0 : return false;
1834 :
1835 0 : if (!IsVoid(thenType))
1836 0 : f.pushDef(thenValue);
1837 :
1838 0 : if (!f.switchToElse(f.iter().controlItem(), &f.iter().controlItem()))
1839 0 : return false;
1840 :
1841 0 : return true;
1842 : }
1843 :
1844 : static bool
1845 0 : EmitEnd(FunctionCompiler& f)
1846 : {
1847 : LabelKind kind;
1848 : ExprType type;
1849 : MDefinition* value;
1850 0 : if (!f.iter().readEnd(&kind, &type, &value))
1851 0 : return false;
1852 :
1853 0 : MBasicBlock* block = f.iter().controlItem();
1854 :
1855 0 : f.iter().popEnd();
1856 :
1857 0 : if (!IsVoid(type))
1858 0 : f.pushDef(value);
1859 :
1860 0 : MDefinition* def = nullptr;
1861 0 : switch (kind) {
1862 : case LabelKind::Block:
1863 0 : if (!f.finishBlock(&def))
1864 0 : return false;
1865 0 : break;
1866 : case LabelKind::Loop:
1867 0 : if (!f.closeLoop(block, &def))
1868 0 : return false;
1869 0 : break;
1870 : case LabelKind::Then:
1871 : // If we didn't see an Else, create a trivial else block so that we create
1872 : // a diamond anyway, to preserve Ion invariants.
1873 0 : if (!f.switchToElse(block, &block))
1874 0 : return false;
1875 :
1876 0 : if (!f.joinIfElse(block, &def))
1877 0 : return false;
1878 0 : break;
1879 : case LabelKind::Else:
1880 0 : if (!f.joinIfElse(block, &def))
1881 0 : return false;
1882 0 : break;
1883 : }
1884 :
1885 0 : if (!IsVoid(type)) {
1886 0 : MOZ_ASSERT_IF(!f.inDeadCode(), def);
1887 0 : f.iter().setResult(def);
1888 : }
1889 :
1890 0 : return true;
1891 : }
1892 :
1893 : static bool
1894 0 : EmitBr(FunctionCompiler& f)
1895 : {
1896 : uint32_t relativeDepth;
1897 : ExprType type;
1898 : MDefinition* value;
1899 0 : if (!f.iter().readBr(&relativeDepth, &type, &value))
1900 0 : return false;
1901 :
1902 0 : if (IsVoid(type)) {
1903 0 : if (!f.br(relativeDepth, nullptr))
1904 0 : return false;
1905 : } else {
1906 0 : if (!f.br(relativeDepth, value))
1907 0 : return false;
1908 : }
1909 :
1910 0 : return true;
1911 : }
1912 :
1913 : static bool
1914 0 : EmitBrIf(FunctionCompiler& f)
1915 : {
1916 : uint32_t relativeDepth;
1917 : ExprType type;
1918 : MDefinition* value;
1919 : MDefinition* condition;
1920 0 : if (!f.iter().readBrIf(&relativeDepth, &type, &value, &condition))
1921 0 : return false;
1922 :
1923 0 : if (IsVoid(type)) {
1924 0 : if (!f.brIf(relativeDepth, nullptr, condition))
1925 0 : return false;
1926 : } else {
1927 0 : if (!f.brIf(relativeDepth, value, condition))
1928 0 : return false;
1929 : }
1930 :
1931 0 : return true;
1932 : }
1933 :
1934 : static bool
1935 0 : EmitBrTable(FunctionCompiler& f)
1936 : {
1937 0 : Uint32Vector depths;
1938 : uint32_t defaultDepth;
1939 : ExprType branchValueType;
1940 : MDefinition* branchValue;
1941 : MDefinition* index;
1942 0 : if (!f.iter().readBrTable(&depths, &defaultDepth, &branchValueType, &branchValue, &index))
1943 0 : return false;
1944 :
1945 : // If all the targets are the same, or there are no targets, we can just
1946 : // use a goto. This is not just an optimization: MaybeFoldConditionBlock
1947 : // assumes that tables have more than one successor.
1948 0 : bool allSameDepth = true;
1949 0 : for (uint32_t depth : depths) {
1950 0 : if (depth != defaultDepth) {
1951 0 : allSameDepth = false;
1952 0 : break;
1953 : }
1954 : }
1955 :
1956 0 : if (allSameDepth)
1957 0 : return f.br(defaultDepth, branchValue);
1958 :
1959 0 : return f.brTable(index, defaultDepth, depths, branchValue);
1960 : }
1961 :
1962 : static bool
1963 0 : EmitReturn(FunctionCompiler& f)
1964 : {
1965 : MDefinition* value;
1966 0 : if (!f.iter().readReturn(&value))
1967 0 : return false;
1968 :
1969 0 : if (IsVoid(f.sig().ret())) {
1970 0 : f.returnVoid();
1971 0 : return true;
1972 : }
1973 :
1974 0 : f.returnExpr(value);
1975 0 : return true;
1976 : }
1977 :
1978 : static bool
1979 0 : EmitUnreachable(FunctionCompiler& f)
1980 : {
1981 0 : if (!f.iter().readUnreachable())
1982 0 : return false;
1983 :
1984 0 : f.unreachableTrap();
1985 0 : return true;
1986 : }
1987 :
1988 : typedef IonOpIter::ValueVector DefVector;
1989 :
1990 : static bool
1991 0 : EmitCallArgs(FunctionCompiler& f, const Sig& sig, const DefVector& args, CallCompileState* call)
1992 : {
1993 0 : if (!f.startCall(call))
1994 0 : return false;
1995 :
1996 0 : for (size_t i = 0, n = sig.args().length(); i < n; ++i) {
1997 0 : if (!f.passArg(args[i], sig.args()[i], call))
1998 0 : return false;
1999 : }
2000 :
2001 0 : return f.finishCall(call);
2002 : }
2003 :
2004 : static bool
2005 0 : EmitCall(FunctionCompiler& f)
2006 : {
2007 0 : uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode();
2008 :
2009 : uint32_t funcIndex;
2010 0 : DefVector args;
2011 0 : if (!f.iter().readCall(&funcIndex, &args))
2012 0 : return false;
2013 :
2014 0 : if (f.inDeadCode())
2015 0 : return true;
2016 :
2017 0 : const Sig& sig = *f.env().funcSigs[funcIndex];
2018 :
2019 0 : CallCompileState call(f, lineOrBytecode);
2020 0 : if (!EmitCallArgs(f, sig, args, &call))
2021 0 : return false;
2022 :
2023 : MDefinition* def;
2024 0 : if (f.env().funcIsImport(funcIndex)) {
2025 0 : uint32_t globalDataOffset = f.env().funcImportGlobalDataOffsets[funcIndex];
2026 0 : if (!f.callImport(globalDataOffset, call, sig.ret(), &def))
2027 0 : return false;
2028 : } else {
2029 0 : if (!f.callDirect(sig, funcIndex, call, &def))
2030 0 : return false;
2031 : }
2032 :
2033 0 : if (IsVoid(sig.ret()))
2034 0 : return true;
2035 :
2036 0 : f.iter().setResult(def);
2037 0 : return true;
2038 : }
2039 :
2040 : static bool
2041 0 : EmitCallIndirect(FunctionCompiler& f, bool oldStyle)
2042 : {
2043 0 : uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode();
2044 :
2045 : uint32_t sigIndex;
2046 : MDefinition* callee;
2047 0 : DefVector args;
2048 0 : if (oldStyle) {
2049 0 : if (!f.iter().readOldCallIndirect(&sigIndex, &callee, &args))
2050 0 : return false;
2051 : } else {
2052 0 : if (!f.iter().readCallIndirect(&sigIndex, &callee, &args))
2053 0 : return false;
2054 : }
2055 :
2056 0 : if (f.inDeadCode())
2057 0 : return true;
2058 :
2059 0 : const Sig& sig = f.env().sigs[sigIndex];
2060 :
2061 0 : CallCompileState call(f, lineOrBytecode);
2062 0 : if (!EmitCallArgs(f, sig, args, &call))
2063 0 : return false;
2064 :
2065 : MDefinition* def;
2066 0 : if (!f.callIndirect(sigIndex, callee, call, &def))
2067 0 : return false;
2068 :
2069 0 : if (IsVoid(sig.ret()))
2070 0 : return true;
2071 :
2072 0 : f.iter().setResult(def);
2073 0 : return true;
2074 : }
2075 :
2076 : static bool
2077 0 : EmitGetLocal(FunctionCompiler& f)
2078 : {
2079 : uint32_t id;
2080 0 : if (!f.iter().readGetLocal(f.locals(), &id))
2081 0 : return false;
2082 :
2083 0 : f.iter().setResult(f.getLocalDef(id));
2084 0 : return true;
2085 : }
2086 :
2087 : static bool
2088 0 : EmitSetLocal(FunctionCompiler& f)
2089 : {
2090 : uint32_t id;
2091 : MDefinition* value;
2092 0 : if (!f.iter().readSetLocal(f.locals(), &id, &value))
2093 0 : return false;
2094 :
2095 0 : f.assign(id, value);
2096 0 : return true;
2097 : }
2098 :
2099 : static bool
2100 0 : EmitTeeLocal(FunctionCompiler& f)
2101 : {
2102 : uint32_t id;
2103 : MDefinition* value;
2104 0 : if (!f.iter().readTeeLocal(f.locals(), &id, &value))
2105 0 : return false;
2106 :
2107 0 : f.assign(id, value);
2108 0 : return true;
2109 : }
2110 :
2111 : static bool
2112 0 : EmitGetGlobal(FunctionCompiler& f)
2113 : {
2114 : uint32_t id;
2115 0 : if (!f.iter().readGetGlobal(&id))
2116 0 : return false;
2117 :
2118 0 : const GlobalDesc& global = f.env().globals[id];
2119 0 : if (!global.isConstant()) {
2120 0 : f.iter().setResult(f.loadGlobalVar(global.offset(), !global.isMutable(),
2121 0 : ToMIRType(global.type())));
2122 0 : return true;
2123 : }
2124 :
2125 0 : Val value = global.constantValue();
2126 0 : MIRType mirType = ToMIRType(value.type());
2127 :
2128 : MDefinition* result;
2129 0 : switch (value.type()) {
2130 : case ValType::I32:
2131 0 : result = f.constant(Int32Value(value.i32()), mirType);
2132 0 : break;
2133 : case ValType::I64:
2134 0 : result = f.constant(int64_t(value.i64()));
2135 0 : break;
2136 : case ValType::F32:
2137 0 : result = f.constant(value.f32());
2138 0 : break;
2139 : case ValType::F64:
2140 0 : result = f.constant(value.f64());
2141 0 : break;
2142 : case ValType::I8x16:
2143 0 : result = f.constant(SimdConstant::CreateX16(value.i8x16()), mirType);
2144 0 : break;
2145 : case ValType::I16x8:
2146 0 : result = f.constant(SimdConstant::CreateX8(value.i16x8()), mirType);
2147 0 : break;
2148 : case ValType::I32x4:
2149 0 : result = f.constant(SimdConstant::CreateX4(value.i32x4()), mirType);
2150 0 : break;
2151 : case ValType::F32x4:
2152 0 : result = f.constant(SimdConstant::CreateX4(value.f32x4()), mirType);
2153 0 : break;
2154 : default:
2155 0 : MOZ_CRASH("unexpected type in EmitGetGlobal");
2156 : }
2157 :
2158 0 : f.iter().setResult(result);
2159 0 : return true;
2160 : }
2161 :
2162 : static bool
2163 0 : EmitSetGlobal(FunctionCompiler& f)
2164 : {
2165 : uint32_t id;
2166 : MDefinition* value;
2167 0 : if (!f.iter().readSetGlobal(&id, &value))
2168 0 : return false;
2169 :
2170 0 : const GlobalDesc& global = f.env().globals[id];
2171 0 : MOZ_ASSERT(global.isMutable());
2172 :
2173 0 : f.storeGlobalVar(global.offset(), value);
2174 0 : return true;
2175 : }
2176 :
2177 : static bool
2178 0 : EmitTeeGlobal(FunctionCompiler& f)
2179 : {
2180 : uint32_t id;
2181 : MDefinition* value;
2182 0 : if (!f.iter().readTeeGlobal(&id, &value))
2183 0 : return false;
2184 :
2185 0 : const GlobalDesc& global = f.env().globals[id];
2186 0 : MOZ_ASSERT(global.isMutable());
2187 :
2188 0 : f.storeGlobalVar(global.offset(), value);
2189 0 : return true;
2190 : }
2191 :
2192 : template <typename MIRClass>
2193 : static bool
2194 : EmitUnary(FunctionCompiler& f, ValType operandType)
2195 : {
2196 : MDefinition* input;
2197 : if (!f.iter().readUnary(operandType, &input))
2198 : return false;
2199 :
2200 : f.iter().setResult(f.unary<MIRClass>(input));
2201 : return true;
2202 : }
2203 :
2204 : template <typename MIRClass>
2205 : static bool
2206 0 : EmitConversion(FunctionCompiler& f, ValType operandType, ValType resultType)
2207 : {
2208 : MDefinition* input;
2209 0 : if (!f.iter().readConversion(operandType, resultType, &input))
2210 0 : return false;
2211 :
2212 0 : f.iter().setResult(f.unary<MIRClass>(input));
2213 0 : return true;
2214 : }
2215 :
2216 : template <typename MIRClass>
2217 : static bool
2218 0 : EmitUnaryWithType(FunctionCompiler& f, ValType operandType, MIRType mirType)
2219 : {
2220 : MDefinition* input;
2221 0 : if (!f.iter().readUnary(operandType, &input))
2222 0 : return false;
2223 :
2224 0 : f.iter().setResult(f.unary<MIRClass>(input, mirType));
2225 0 : return true;
2226 : }
2227 :
2228 : template <typename MIRClass>
2229 : static bool
2230 : EmitConversionWithType(FunctionCompiler& f,
2231 : ValType operandType, ValType resultType, MIRType mirType)
2232 : {
2233 : MDefinition* input;
2234 : if (!f.iter().readConversion(operandType, resultType, &input))
2235 : return false;
2236 :
2237 : f.iter().setResult(f.unary<MIRClass>(input, mirType));
2238 : return true;
2239 : }
2240 :
2241 : static bool
2242 0 : EmitTruncate(FunctionCompiler& f, ValType operandType, ValType resultType,
2243 : bool isUnsigned)
2244 : {
2245 : MDefinition* input;
2246 0 : if (!f.iter().readConversion(operandType, resultType, &input))
2247 0 : return false;
2248 :
2249 0 : if (resultType == ValType::I32) {
2250 0 : if (f.env().isAsmJS())
2251 0 : f.iter().setResult(f.unary<MTruncateToInt32>(input));
2252 : else
2253 0 : f.iter().setResult(f.truncate<MWasmTruncateToInt32>(input, isUnsigned));
2254 : } else {
2255 0 : MOZ_ASSERT(resultType == ValType::I64);
2256 0 : MOZ_ASSERT(!f.env().isAsmJS());
2257 0 : f.iter().setResult(f.truncate<MWasmTruncateToInt64>(input, isUnsigned));
2258 : }
2259 0 : return true;
2260 : }
2261 :
2262 : static bool
2263 0 : EmitExtendI32(FunctionCompiler& f, bool isUnsigned)
2264 : {
2265 : MDefinition* input;
2266 0 : if (!f.iter().readConversion(ValType::I32, ValType::I64, &input))
2267 0 : return false;
2268 :
2269 0 : f.iter().setResult(f.extendI32(input, isUnsigned));
2270 0 : return true;
2271 : }
2272 :
2273 : static bool
2274 0 : EmitConvertI64ToFloatingPoint(FunctionCompiler& f,
2275 : ValType resultType, MIRType mirType, bool isUnsigned)
2276 : {
2277 : MDefinition* input;
2278 0 : if (!f.iter().readConversion(ValType::I64, resultType, &input))
2279 0 : return false;
2280 :
2281 0 : f.iter().setResult(f.convertI64ToFloatingPoint(input, mirType, isUnsigned));
2282 0 : return true;
2283 : }
2284 :
2285 : static bool
2286 0 : EmitReinterpret(FunctionCompiler& f, ValType resultType, ValType operandType, MIRType mirType)
2287 : {
2288 : MDefinition* input;
2289 0 : if (!f.iter().readConversion(operandType, resultType, &input))
2290 0 : return false;
2291 :
2292 0 : f.iter().setResult(f.unary<MWasmReinterpret>(input, mirType));
2293 0 : return true;
2294 : }
2295 :
2296 : static bool
2297 0 : EmitAdd(FunctionCompiler& f, ValType type, MIRType mirType)
2298 : {
2299 : MDefinition* lhs;
2300 : MDefinition* rhs;
2301 0 : if (!f.iter().readBinary(type, &lhs, &rhs))
2302 0 : return false;
2303 :
2304 0 : f.iter().setResult(f.binary<MAdd>(lhs, rhs, mirType));
2305 0 : return true;
2306 : }
2307 :
2308 : static bool
2309 0 : EmitSub(FunctionCompiler& f, ValType type, MIRType mirType)
2310 : {
2311 : MDefinition* lhs;
2312 : MDefinition* rhs;
2313 0 : if (!f.iter().readBinary(type, &lhs, &rhs))
2314 0 : return false;
2315 :
2316 0 : f.iter().setResult(f.sub(lhs, rhs, mirType));
2317 0 : return true;
2318 : }
2319 :
2320 : static bool
2321 0 : EmitRotate(FunctionCompiler& f, ValType type, bool isLeftRotation)
2322 : {
2323 : MDefinition* lhs;
2324 : MDefinition* rhs;
2325 0 : if (!f.iter().readBinary(type, &lhs, &rhs))
2326 0 : return false;
2327 :
2328 0 : MDefinition* result = f.rotate(lhs, rhs, ToMIRType(type), isLeftRotation);
2329 0 : f.iter().setResult(result);
2330 0 : return true;
2331 : }
2332 :
2333 : static bool
2334 0 : EmitBitNot(FunctionCompiler& f, ValType operandType)
2335 : {
2336 : MDefinition* input;
2337 0 : if (!f.iter().readUnary(operandType, &input))
2338 0 : return false;
2339 :
2340 0 : f.iter().setResult(f.bitnot(input));
2341 0 : return true;
2342 : }
2343 :
2344 : template <typename MIRClass>
2345 : static bool
2346 0 : EmitBitwise(FunctionCompiler& f, ValType operandType, MIRType mirType)
2347 : {
2348 : MDefinition* lhs;
2349 : MDefinition* rhs;
2350 0 : if (!f.iter().readBinary(operandType, &lhs, &rhs))
2351 0 : return false;
2352 :
2353 0 : f.iter().setResult(f.binary<MIRClass>(lhs, rhs, mirType));
2354 0 : return true;
2355 : }
2356 :
2357 : static bool
2358 0 : EmitMul(FunctionCompiler& f, ValType operandType, MIRType mirType)
2359 : {
2360 : MDefinition* lhs;
2361 : MDefinition* rhs;
2362 0 : if (!f.iter().readBinary(operandType, &lhs, &rhs))
2363 0 : return false;
2364 :
2365 0 : f.iter().setResult(f.mul(lhs, rhs, mirType,
2366 0 : mirType == MIRType::Int32 ? MMul::Integer : MMul::Normal));
2367 0 : return true;
2368 : }
2369 :
2370 : static bool
2371 0 : EmitDiv(FunctionCompiler& f, ValType operandType, MIRType mirType, bool isUnsigned)
2372 : {
2373 : MDefinition* lhs;
2374 : MDefinition* rhs;
2375 0 : if (!f.iter().readBinary(operandType, &lhs, &rhs))
2376 0 : return false;
2377 :
2378 0 : f.iter().setResult(f.div(lhs, rhs, mirType, isUnsigned));
2379 0 : return true;
2380 : }
2381 :
2382 : static bool
2383 0 : EmitRem(FunctionCompiler& f, ValType operandType, MIRType mirType, bool isUnsigned)
2384 : {
2385 : MDefinition* lhs;
2386 : MDefinition* rhs;
2387 0 : if (!f.iter().readBinary(operandType, &lhs, &rhs))
2388 0 : return false;
2389 :
2390 0 : f.iter().setResult(f.mod(lhs, rhs, mirType, isUnsigned));
2391 0 : return true;
2392 : }
2393 :
2394 : static bool
2395 0 : EmitMinMax(FunctionCompiler& f, ValType operandType, MIRType mirType, bool isMax)
2396 : {
2397 : MDefinition* lhs;
2398 : MDefinition* rhs;
2399 0 : if (!f.iter().readBinary(operandType, &lhs, &rhs))
2400 0 : return false;
2401 :
2402 0 : f.iter().setResult(f.minMax(lhs, rhs, mirType, isMax));
2403 0 : return true;
2404 : }
2405 :
2406 : static bool
2407 0 : EmitCopySign(FunctionCompiler& f, ValType operandType)
2408 : {
2409 : MDefinition* lhs;
2410 : MDefinition* rhs;
2411 0 : if (!f.iter().readBinary(operandType, &lhs, &rhs))
2412 0 : return false;
2413 :
2414 0 : f.iter().setResult(f.binary<MCopySign>(lhs, rhs, ToMIRType(operandType)));
2415 0 : return true;
2416 : }
2417 :
2418 : static bool
2419 0 : EmitComparison(FunctionCompiler& f,
2420 : ValType operandType, JSOp compareOp, MCompare::CompareType compareType)
2421 : {
2422 : MDefinition* lhs;
2423 : MDefinition* rhs;
2424 0 : if (!f.iter().readComparison(operandType, &lhs, &rhs))
2425 0 : return false;
2426 :
2427 0 : f.iter().setResult(f.compare(lhs, rhs, compareOp, compareType));
2428 0 : return true;
2429 : }
2430 :
2431 : static bool
2432 0 : EmitSelect(FunctionCompiler& f)
2433 : {
2434 : StackType type;
2435 : MDefinition* trueValue;
2436 : MDefinition* falseValue;
2437 : MDefinition* condition;
2438 0 : if (!f.iter().readSelect(&type, &trueValue, &falseValue, &condition))
2439 0 : return false;
2440 :
2441 0 : f.iter().setResult(f.select(trueValue, falseValue, condition));
2442 0 : return true;
2443 : }
2444 :
2445 : static bool
2446 0 : EmitLoad(FunctionCompiler& f, ValType type, Scalar::Type viewType)
2447 : {
2448 0 : LinearMemoryAddress<MDefinition*> addr;
2449 0 : if (!f.iter().readLoad(type, Scalar::byteSize(viewType), &addr))
2450 0 : return false;
2451 :
2452 0 : MemoryAccessDesc access(viewType, addr.align, addr.offset, f.bytecodeIfNotAsmJS());
2453 0 : auto* ins = f.load(addr.base, &access, type);
2454 0 : if (!f.inDeadCode() && !ins)
2455 0 : return false;
2456 :
2457 0 : f.iter().setResult(ins);
2458 0 : return true;
2459 : }
2460 :
2461 : static bool
2462 0 : EmitStore(FunctionCompiler& f, ValType resultType, Scalar::Type viewType)
2463 : {
2464 0 : LinearMemoryAddress<MDefinition*> addr;
2465 : MDefinition* value;
2466 0 : if (!f.iter().readStore(resultType, Scalar::byteSize(viewType), &addr, &value))
2467 0 : return false;
2468 :
2469 0 : MemoryAccessDesc access(viewType, addr.align, addr.offset, f.bytecodeIfNotAsmJS());
2470 :
2471 0 : return f.store(addr.base, &access, value);
2472 : }
2473 :
2474 : static bool
2475 0 : EmitTeeStore(FunctionCompiler& f, ValType resultType, Scalar::Type viewType)
2476 : {
2477 0 : LinearMemoryAddress<MDefinition*> addr;
2478 : MDefinition* value;
2479 0 : if (!f.iter().readTeeStore(resultType, Scalar::byteSize(viewType), &addr, &value))
2480 0 : return false;
2481 :
2482 0 : MemoryAccessDesc access(viewType, addr.align, addr.offset, f.bytecodeIfNotAsmJS());
2483 :
2484 0 : return f.store(addr.base, &access, value);
2485 : }
2486 :
2487 : static bool
2488 0 : EmitTeeStoreWithCoercion(FunctionCompiler& f, ValType resultType, Scalar::Type viewType)
2489 : {
2490 0 : LinearMemoryAddress<MDefinition*> addr;
2491 : MDefinition* value;
2492 0 : if (!f.iter().readTeeStore(resultType, Scalar::byteSize(viewType), &addr, &value))
2493 0 : return false;
2494 :
2495 0 : if (resultType == ValType::F32 && viewType == Scalar::Float64)
2496 0 : value = f.unary<MToDouble>(value);
2497 0 : else if (resultType == ValType::F64 && viewType == Scalar::Float32)
2498 0 : value = f.unary<MToFloat32>(value);
2499 : else
2500 0 : MOZ_CRASH("unexpected coerced store");
2501 :
2502 0 : MemoryAccessDesc access(viewType, addr.align, addr.offset, f.bytecodeIfNotAsmJS());
2503 :
2504 0 : return f.store(addr.base, &access, value);
2505 : }
2506 :
2507 : static bool
2508 0 : TryInlineUnaryBuiltin(FunctionCompiler& f, SymbolicAddress callee, MDefinition* input)
2509 : {
2510 0 : if (!input)
2511 0 : return false;
2512 :
2513 0 : MOZ_ASSERT(IsFloatingPointType(input->type()));
2514 :
2515 : RoundingMode mode;
2516 0 : if (!IsRoundingFunction(callee, &mode))
2517 0 : return false;
2518 :
2519 0 : if (!MNearbyInt::HasAssemblerSupport(mode))
2520 0 : return false;
2521 :
2522 0 : f.iter().setResult(f.nearbyInt(input, mode));
2523 0 : return true;
2524 : }
2525 :
2526 : static bool
2527 0 : EmitUnaryMathBuiltinCall(FunctionCompiler& f, SymbolicAddress callee, ValType operandType)
2528 : {
2529 0 : uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode();
2530 :
2531 : MDefinition* input;
2532 0 : if (!f.iter().readUnary(operandType, &input))
2533 0 : return false;
2534 :
2535 0 : if (TryInlineUnaryBuiltin(f, callee, input))
2536 0 : return true;
2537 :
2538 0 : CallCompileState call(f, lineOrBytecode);
2539 0 : if (!f.startCall(&call))
2540 0 : return false;
2541 :
2542 0 : if (!f.passArg(input, operandType, &call))
2543 0 : return false;
2544 :
2545 0 : if (!f.finishCall(&call))
2546 0 : return false;
2547 :
2548 : MDefinition* def;
2549 0 : if (!f.builtinCall(callee, call, operandType, &def))
2550 0 : return false;
2551 :
2552 0 : f.iter().setResult(def);
2553 0 : return true;
2554 : }
2555 :
2556 : static bool
2557 0 : EmitBinaryMathBuiltinCall(FunctionCompiler& f, SymbolicAddress callee, ValType operandType)
2558 : {
2559 0 : uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode();
2560 :
2561 0 : CallCompileState call(f, lineOrBytecode);
2562 0 : if (!f.startCall(&call))
2563 0 : return false;
2564 :
2565 : MDefinition* lhs;
2566 : MDefinition* rhs;
2567 0 : if (!f.iter().readBinary(operandType, &lhs, &rhs))
2568 0 : return false;
2569 :
2570 0 : if (!f.passArg(lhs, operandType, &call))
2571 0 : return false;
2572 :
2573 0 : if (!f.passArg(rhs, operandType, &call))
2574 0 : return false;
2575 :
2576 0 : if (!f.finishCall(&call))
2577 0 : return false;
2578 :
2579 : MDefinition* def;
2580 0 : if (!f.builtinCall(callee, call, operandType, &def))
2581 0 : return false;
2582 :
2583 0 : f.iter().setResult(def);
2584 0 : return true;
2585 : }
2586 :
2587 : static bool
2588 0 : EmitAtomicsLoad(FunctionCompiler& f)
2589 : {
2590 0 : LinearMemoryAddress<MDefinition*> addr;
2591 : Scalar::Type viewType;
2592 0 : if (!f.iter().readAtomicLoad(&addr, &viewType))
2593 0 : return false;
2594 :
2595 0 : MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(f.bytecodeOffset()), 0,
2596 0 : MembarBeforeLoad, MembarAfterLoad);
2597 :
2598 0 : auto* ins = f.load(addr.base, &access, ValType::I32);
2599 0 : if (!f.inDeadCode() && !ins)
2600 0 : return false;
2601 :
2602 0 : f.iter().setResult(ins);
2603 0 : return true;
2604 : }
2605 :
2606 : static bool
2607 0 : EmitAtomicsStore(FunctionCompiler& f)
2608 : {
2609 0 : LinearMemoryAddress<MDefinition*> addr;
2610 : Scalar::Type viewType;
2611 : MDefinition* value;
2612 0 : if (!f.iter().readAtomicStore(&addr, &viewType, &value))
2613 0 : return false;
2614 :
2615 0 : MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(f.bytecodeOffset()), 0,
2616 0 : MembarBeforeStore, MembarAfterStore);
2617 :
2618 0 : if (!f.store(addr.base, &access, value))
2619 0 : return false;
2620 :
2621 0 : f.iter().setResult(value);
2622 0 : return true;
2623 : }
2624 :
2625 : static bool
2626 0 : EmitAtomicsBinOp(FunctionCompiler& f)
2627 : {
2628 0 : LinearMemoryAddress<MDefinition*> addr;
2629 : Scalar::Type viewType;
2630 : jit::AtomicOp op;
2631 : MDefinition* value;
2632 0 : if (!f.iter().readAtomicBinOp(&addr, &viewType, &op, &value))
2633 0 : return false;
2634 :
2635 0 : MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(f.bytecodeOffset()));
2636 :
2637 0 : auto* ins = f.atomicBinopHeap(op, addr.base, &access, value);
2638 0 : if (!f.inDeadCode() && !ins)
2639 0 : return false;
2640 :
2641 0 : f.iter().setResult(ins);
2642 0 : return true;
2643 : }
2644 :
2645 : static bool
2646 0 : EmitAtomicsCompareExchange(FunctionCompiler& f)
2647 : {
2648 0 : LinearMemoryAddress<MDefinition*> addr;
2649 : Scalar::Type viewType;
2650 : MDefinition* oldValue;
2651 : MDefinition* newValue;
2652 0 : if (!f.iter().readAtomicCompareExchange(&addr, &viewType, &oldValue, &newValue))
2653 0 : return false;
2654 :
2655 0 : MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(f.bytecodeOffset()));
2656 :
2657 0 : auto* ins = f.atomicCompareExchangeHeap(addr.base, &access, oldValue, newValue);
2658 0 : if (!f.inDeadCode() && !ins)
2659 0 : return false;
2660 :
2661 0 : f.iter().setResult(ins);
2662 0 : return true;
2663 : }
2664 :
2665 : static bool
2666 0 : EmitAtomicsExchange(FunctionCompiler& f)
2667 : {
2668 0 : LinearMemoryAddress<MDefinition*> addr;
2669 : Scalar::Type viewType;
2670 : MDefinition* value;
2671 0 : if (!f.iter().readAtomicExchange(&addr, &viewType, &value))
2672 0 : return false;
2673 :
2674 0 : MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(f.bytecodeOffset()));
2675 :
2676 0 : auto* ins = f.atomicExchangeHeap(addr.base, &access, value);
2677 0 : if (!f.inDeadCode() && !ins)
2678 0 : return false;
2679 :
2680 0 : f.iter().setResult(ins);
2681 0 : return true;
2682 : }
2683 :
2684 : static bool
2685 0 : EmitSimdUnary(FunctionCompiler& f, ValType type, SimdOperation simdOp)
2686 : {
2687 : MSimdUnaryArith::Operation op;
2688 0 : switch (simdOp) {
2689 : case SimdOperation::Fn_abs:
2690 0 : op = MSimdUnaryArith::abs;
2691 0 : break;
2692 : case SimdOperation::Fn_neg:
2693 0 : op = MSimdUnaryArith::neg;
2694 0 : break;
2695 : case SimdOperation::Fn_not:
2696 0 : op = MSimdUnaryArith::not_;
2697 0 : break;
2698 : case SimdOperation::Fn_sqrt:
2699 0 : op = MSimdUnaryArith::sqrt;
2700 0 : break;
2701 : case SimdOperation::Fn_reciprocalApproximation:
2702 0 : op = MSimdUnaryArith::reciprocalApproximation;
2703 0 : break;
2704 : case SimdOperation::Fn_reciprocalSqrtApproximation:
2705 0 : op = MSimdUnaryArith::reciprocalSqrtApproximation;
2706 0 : break;
2707 : default:
2708 0 : MOZ_CRASH("not a simd unary arithmetic operation");
2709 : }
2710 :
2711 : MDefinition* input;
2712 0 : if (!f.iter().readUnary(type, &input))
2713 0 : return false;
2714 :
2715 0 : f.iter().setResult(f.unarySimd(input, op, ToMIRType(type)));
2716 0 : return true;
2717 : }
2718 :
2719 : template<class OpKind>
2720 : inline bool
2721 0 : EmitSimdBinary(FunctionCompiler& f, ValType type, OpKind op)
2722 : {
2723 : MDefinition* lhs;
2724 : MDefinition* rhs;
2725 0 : if (!f.iter().readBinary(type, &lhs, &rhs))
2726 0 : return false;
2727 :
2728 0 : f.iter().setResult(f.binarySimd(lhs, rhs, op, ToMIRType(type)));
2729 0 : return true;
2730 : }
2731 :
2732 : static bool
2733 0 : EmitSimdBinaryComp(FunctionCompiler& f, ValType operandType, MSimdBinaryComp::Operation op,
2734 : SimdSign sign)
2735 : {
2736 : MDefinition* lhs;
2737 : MDefinition* rhs;
2738 0 : if (!f.iter().readSimdComparison(operandType, &lhs, &rhs))
2739 0 : return false;
2740 :
2741 0 : f.iter().setResult(f.binarySimdComp(lhs, rhs, op, sign));
2742 0 : return true;
2743 : }
2744 :
2745 : static bool
2746 0 : EmitSimdBinarySaturating(FunctionCompiler& f, ValType type, MSimdBinarySaturating::Operation op,
2747 : SimdSign sign)
2748 : {
2749 : MDefinition* lhs;
2750 : MDefinition* rhs;
2751 0 : if (!f.iter().readBinary(type, &lhs, &rhs))
2752 0 : return false;
2753 :
2754 0 : f.iter().setResult(f.binarySimdSaturating(lhs, rhs, op, sign));
2755 0 : return true;
2756 : }
2757 :
2758 : static bool
2759 0 : EmitSimdShift(FunctionCompiler& f, ValType operandType, MSimdShift::Operation op)
2760 : {
2761 : MDefinition* lhs;
2762 : MDefinition* rhs;
2763 0 : if (!f.iter().readSimdShiftByScalar(operandType, &lhs, &rhs))
2764 0 : return false;
2765 :
2766 0 : f.iter().setResult(f.binarySimdShift(lhs, rhs, op));
2767 0 : return true;
2768 : }
2769 :
2770 : static ValType
2771 0 : SimdToLaneType(ValType type)
2772 : {
2773 0 : switch (type) {
2774 : case ValType::I8x16:
2775 : case ValType::I16x8:
2776 0 : case ValType::I32x4: return ValType::I32;
2777 0 : case ValType::F32x4: return ValType::F32;
2778 : case ValType::B8x16:
2779 : case ValType::B16x8:
2780 0 : case ValType::B32x4: return ValType::I32; // Boolean lanes are Int32 in asm.
2781 : case ValType::I32:
2782 : case ValType::I64:
2783 : case ValType::F32:
2784 : case ValType::F64:
2785 0 : break;
2786 : }
2787 0 : MOZ_CRASH("bad simd type");
2788 : }
2789 :
2790 : static bool
2791 0 : EmitExtractLane(FunctionCompiler& f, ValType operandType, SimdSign sign)
2792 : {
2793 : uint8_t lane;
2794 : MDefinition* vector;
2795 0 : if (!f.iter().readExtractLane(operandType, &lane, &vector))
2796 0 : return false;
2797 :
2798 0 : f.iter().setResult(f.extractSimdElement(lane, vector,
2799 0 : ToMIRType(SimdToLaneType(operandType)), sign));
2800 0 : return true;
2801 : }
2802 :
2803 : // Emit an I32 expression and then convert it to a boolean SIMD lane value, i.e. -1 or 0.
2804 : static MDefinition*
2805 0 : EmitSimdBooleanLaneExpr(FunctionCompiler& f, MDefinition* i32)
2806 : {
2807 : // Compute !i32 - 1 to force the value range into {0, -1}.
2808 0 : MDefinition* noti32 = f.unary<MNot>(i32);
2809 0 : return f.binary<MSub>(noti32, f.constant(Int32Value(1), MIRType::Int32), MIRType::Int32);
2810 : }
2811 :
2812 : static bool
2813 0 : EmitSimdReplaceLane(FunctionCompiler& f, ValType simdType)
2814 : {
2815 0 : if (IsSimdBoolType(simdType))
2816 0 : f.iter().setResult(EmitSimdBooleanLaneExpr(f, f.iter().getResult()));
2817 :
2818 : uint8_t lane;
2819 : MDefinition* vector;
2820 : MDefinition* scalar;
2821 0 : if (!f.iter().readReplaceLane(simdType, &lane, &vector, &scalar))
2822 0 : return false;
2823 :
2824 0 : f.iter().setResult(f.insertElementSimd(vector, scalar, lane, ToMIRType(simdType)));
2825 0 : return true;
2826 : }
2827 :
2828 : inline bool
2829 0 : EmitSimdBitcast(FunctionCompiler& f, ValType fromType, ValType toType)
2830 : {
2831 : MDefinition* input;
2832 0 : if (!f.iter().readConversion(fromType, toType, &input))
2833 0 : return false;
2834 :
2835 0 : f.iter().setResult(f.bitcastSimd(input, ToMIRType(fromType), ToMIRType(toType)));
2836 0 : return true;
2837 : }
2838 :
2839 : inline bool
2840 0 : EmitSimdConvert(FunctionCompiler& f, ValType fromType, ValType toType, SimdSign sign)
2841 : {
2842 : MDefinition* input;
2843 0 : if (!f.iter().readConversion(fromType, toType, &input))
2844 0 : return false;
2845 :
2846 0 : f.iter().setResult(f.convertSimd(input, ToMIRType(fromType), ToMIRType(toType), sign));
2847 0 : return true;
2848 : }
2849 :
2850 : static bool
2851 0 : EmitSimdSwizzle(FunctionCompiler& f, ValType simdType)
2852 : {
2853 : uint8_t lanes[16];
2854 : MDefinition* vector;
2855 0 : if (!f.iter().readSwizzle(simdType, &lanes, &vector))
2856 0 : return false;
2857 :
2858 0 : f.iter().setResult(f.swizzleSimd(vector, lanes, ToMIRType(simdType)));
2859 0 : return true;
2860 : }
2861 :
2862 : static bool
2863 0 : EmitSimdShuffle(FunctionCompiler& f, ValType simdType)
2864 : {
2865 : uint8_t lanes[16];
2866 : MDefinition* lhs;
2867 : MDefinition* rhs;
2868 0 : if (!f.iter().readShuffle(simdType, &lanes, &lhs, &rhs))
2869 0 : return false;
2870 :
2871 0 : f.iter().setResult(f.shuffleSimd(lhs, rhs, lanes, ToMIRType(simdType)));
2872 0 : return true;
2873 : }
2874 :
2875 : static inline Scalar::Type
2876 0 : SimdExprTypeToViewType(ValType type, unsigned* defaultNumElems)
2877 : {
2878 0 : switch (type) {
2879 0 : case ValType::I8x16: *defaultNumElems = 16; return Scalar::Int8x16;
2880 0 : case ValType::I16x8: *defaultNumElems = 8; return Scalar::Int16x8;
2881 0 : case ValType::I32x4: *defaultNumElems = 4; return Scalar::Int32x4;
2882 0 : case ValType::F32x4: *defaultNumElems = 4; return Scalar::Float32x4;
2883 0 : default: break;
2884 : }
2885 0 : MOZ_CRASH("type not handled in SimdExprTypeToViewType");
2886 : }
2887 :
2888 : static bool
2889 0 : EmitSimdLoad(FunctionCompiler& f, ValType resultType, unsigned numElems)
2890 : {
2891 : unsigned defaultNumElems;
2892 0 : Scalar::Type viewType = SimdExprTypeToViewType(resultType, &defaultNumElems);
2893 :
2894 0 : if (!numElems)
2895 0 : numElems = defaultNumElems;
2896 :
2897 0 : LinearMemoryAddress<MDefinition*> addr;
2898 0 : if (!f.iter().readLoad(resultType, Scalar::byteSize(viewType), &addr))
2899 0 : return false;
2900 :
2901 0 : MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(f.bytecodeOffset()), numElems);
2902 :
2903 0 : auto* ins = f.load(addr.base, &access, resultType);
2904 0 : if (!f.inDeadCode() && !ins)
2905 0 : return false;
2906 :
2907 0 : f.iter().setResult(ins);
2908 0 : return true;
2909 : }
2910 :
2911 : static bool
2912 0 : EmitSimdStore(FunctionCompiler& f, ValType resultType, unsigned numElems)
2913 : {
2914 : unsigned defaultNumElems;
2915 0 : Scalar::Type viewType = SimdExprTypeToViewType(resultType, &defaultNumElems);
2916 :
2917 0 : if (!numElems)
2918 0 : numElems = defaultNumElems;
2919 :
2920 0 : LinearMemoryAddress<MDefinition*> addr;
2921 : MDefinition* value;
2922 0 : if (!f.iter().readTeeStore(resultType, Scalar::byteSize(viewType), &addr, &value))
2923 0 : return false;
2924 :
2925 0 : MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(f.bytecodeOffset()), numElems);
2926 :
2927 0 : return f.store(addr.base, &access, value);
2928 : }
2929 :
2930 : static bool
2931 0 : EmitSimdSelect(FunctionCompiler& f, ValType simdType)
2932 : {
2933 : MDefinition* trueValue;
2934 : MDefinition* falseValue;
2935 : MDefinition* condition;
2936 0 : if (!f.iter().readSimdSelect(simdType, &trueValue, &falseValue, &condition))
2937 0 : return false;
2938 :
2939 0 : f.iter().setResult(f.selectSimd(condition, trueValue, falseValue,
2940 0 : ToMIRType(simdType)));
2941 0 : return true;
2942 : }
2943 :
2944 : static bool
2945 0 : EmitSimdAllTrue(FunctionCompiler& f, ValType operandType)
2946 : {
2947 : MDefinition* input;
2948 0 : if (!f.iter().readSimdBooleanReduction(operandType, &input))
2949 0 : return false;
2950 :
2951 0 : f.iter().setResult(f.simdAllTrue(input));
2952 0 : return true;
2953 : }
2954 :
2955 : static bool
2956 0 : EmitSimdAnyTrue(FunctionCompiler& f, ValType operandType)
2957 : {
2958 : MDefinition* input;
2959 0 : if (!f.iter().readSimdBooleanReduction(operandType, &input))
2960 0 : return false;
2961 :
2962 0 : f.iter().setResult(f.simdAnyTrue(input));
2963 0 : return true;
2964 : }
2965 :
2966 : static bool
2967 0 : EmitSimdSplat(FunctionCompiler& f, ValType simdType)
2968 : {
2969 0 : if (IsSimdBoolType(simdType))
2970 0 : f.iter().setResult(EmitSimdBooleanLaneExpr(f, f.iter().getResult()));
2971 :
2972 : MDefinition* input;
2973 0 : if (!f.iter().readSplat(simdType, &input))
2974 0 : return false;
2975 :
2976 0 : f.iter().setResult(f.splatSimd(input, ToMIRType(simdType)));
2977 0 : return true;
2978 : }
2979 :
2980 : // Build a SIMD vector by inserting lanes one at a time into an initial constant.
2981 : static bool
2982 0 : EmitSimdChainedCtor(FunctionCompiler& f, ValType valType, MIRType type, const SimdConstant& init)
2983 : {
2984 0 : const unsigned length = SimdTypeToLength(type);
2985 :
2986 0 : DefVector args;
2987 0 : if (!f.iter().readSimdCtor(ValType::I32, length, valType, &args))
2988 0 : return false;
2989 :
2990 0 : MDefinition* val = f.constant(init, type);
2991 0 : for (unsigned i = 0; i < length; i++)
2992 0 : val = f.insertElementSimd(val, args[i], i, type);
2993 :
2994 0 : f.iter().setResult(val);
2995 0 : return true;
2996 : }
2997 :
2998 : // Build a boolean SIMD vector by inserting lanes one at a time into an initial constant.
2999 : static bool
3000 0 : EmitSimdBooleanChainedCtor(FunctionCompiler& f, ValType valType, MIRType type,
3001 : const SimdConstant& init)
3002 : {
3003 0 : const unsigned length = SimdTypeToLength(type);
3004 :
3005 0 : DefVector args;
3006 0 : if (!f.iter().readSimdCtor(ValType::I32, length, valType, &args))
3007 0 : return false;
3008 :
3009 0 : MDefinition* val = f.constant(init, type);
3010 0 : for (unsigned i = 0; i < length; i++)
3011 0 : val = f.insertElementSimd(val, EmitSimdBooleanLaneExpr(f, args[i]), i, type);
3012 :
3013 0 : f.iter().setResult(val);
3014 0 : return true;
3015 : }
3016 :
3017 : static bool
3018 0 : EmitSimdCtor(FunctionCompiler& f, ValType type)
3019 : {
3020 0 : switch (type) {
3021 : case ValType::I8x16:
3022 0 : return EmitSimdChainedCtor(f, type, MIRType::Int8x16, SimdConstant::SplatX16(0));
3023 : case ValType::I16x8:
3024 0 : return EmitSimdChainedCtor(f, type, MIRType::Int16x8, SimdConstant::SplatX8(0));
3025 : case ValType::I32x4: {
3026 0 : DefVector args;
3027 0 : if (!f.iter().readSimdCtor(ValType::I32, 4, type, &args))
3028 0 : return false;
3029 :
3030 0 : f.iter().setResult(f.constructSimd<MSimdValueX4>(args[0], args[1], args[2], args[3],
3031 0 : MIRType::Int32x4));
3032 0 : return true;
3033 : }
3034 : case ValType::F32x4: {
3035 0 : DefVector args;
3036 0 : if (!f.iter().readSimdCtor(ValType::F32, 4, type, &args))
3037 0 : return false;
3038 :
3039 0 : f.iter().setResult(f.constructSimd<MSimdValueX4>(args[0], args[1], args[2], args[3],
3040 0 : MIRType::Float32x4));
3041 0 : return true;
3042 : }
3043 : case ValType::B8x16:
3044 0 : return EmitSimdBooleanChainedCtor(f, type, MIRType::Bool8x16, SimdConstant::SplatX16(0));
3045 : case ValType::B16x8:
3046 0 : return EmitSimdBooleanChainedCtor(f, type, MIRType::Bool16x8, SimdConstant::SplatX8(0));
3047 : case ValType::B32x4: {
3048 0 : DefVector args;
3049 0 : if (!f.iter().readSimdCtor(ValType::I32, 4, type, &args))
3050 0 : return false;
3051 :
3052 0 : MOZ_ASSERT(args.length() == 4);
3053 0 : for (unsigned i = 0; i < 4; i++)
3054 0 : args[i] = EmitSimdBooleanLaneExpr(f, args[i]);
3055 :
3056 0 : f.iter().setResult(f.constructSimd<MSimdValueX4>(args[0], args[1], args[2], args[3],
3057 0 : MIRType::Bool32x4));
3058 0 : return true;
3059 : }
3060 : case ValType::I32:
3061 : case ValType::I64:
3062 : case ValType::F32:
3063 : case ValType::F64:
3064 0 : break;
3065 : }
3066 0 : MOZ_CRASH("unexpected SIMD type");
3067 : }
3068 :
3069 : static bool
3070 0 : EmitSimdOp(FunctionCompiler& f, ValType type, SimdOperation op, SimdSign sign)
3071 : {
3072 0 : switch (op) {
3073 : case SimdOperation::Constructor:
3074 0 : return EmitSimdCtor(f, type);
3075 : case SimdOperation::Fn_extractLane:
3076 0 : return EmitExtractLane(f, type, sign);
3077 : case SimdOperation::Fn_replaceLane:
3078 0 : return EmitSimdReplaceLane(f, type);
3079 : case SimdOperation::Fn_check:
3080 0 : MOZ_CRASH("only used in asm.js' type system");
3081 : case SimdOperation::Fn_splat:
3082 0 : return EmitSimdSplat(f, type);
3083 : case SimdOperation::Fn_select:
3084 0 : return EmitSimdSelect(f, type);
3085 : case SimdOperation::Fn_swizzle:
3086 0 : return EmitSimdSwizzle(f, type);
3087 : case SimdOperation::Fn_shuffle:
3088 0 : return EmitSimdShuffle(f, type);
3089 : case SimdOperation::Fn_load:
3090 0 : return EmitSimdLoad(f, type, 0);
3091 : case SimdOperation::Fn_load1:
3092 0 : return EmitSimdLoad(f, type, 1);
3093 : case SimdOperation::Fn_load2:
3094 0 : return EmitSimdLoad(f, type, 2);
3095 : case SimdOperation::Fn_store:
3096 0 : return EmitSimdStore(f, type, 0);
3097 : case SimdOperation::Fn_store1:
3098 0 : return EmitSimdStore(f, type, 1);
3099 : case SimdOperation::Fn_store2:
3100 0 : return EmitSimdStore(f, type, 2);
3101 : case SimdOperation::Fn_allTrue:
3102 0 : return EmitSimdAllTrue(f, type);
3103 : case SimdOperation::Fn_anyTrue:
3104 0 : return EmitSimdAnyTrue(f, type);
3105 : case SimdOperation::Fn_abs:
3106 : case SimdOperation::Fn_neg:
3107 : case SimdOperation::Fn_not:
3108 : case SimdOperation::Fn_sqrt:
3109 : case SimdOperation::Fn_reciprocalApproximation:
3110 : case SimdOperation::Fn_reciprocalSqrtApproximation:
3111 0 : return EmitSimdUnary(f, type, op);
3112 : case SimdOperation::Fn_shiftLeftByScalar:
3113 0 : return EmitSimdShift(f, type, MSimdShift::lsh);
3114 : case SimdOperation::Fn_shiftRightByScalar:
3115 0 : return EmitSimdShift(f, type, MSimdShift::rshForSign(sign));
3116 : #define _CASE(OP) \
3117 : case SimdOperation::Fn_##OP: \
3118 : return EmitSimdBinaryComp(f, type, MSimdBinaryComp::OP, sign);
3119 0 : FOREACH_COMP_SIMD_OP(_CASE)
3120 : #undef _CASE
3121 : case SimdOperation::Fn_and:
3122 0 : return EmitSimdBinary(f, type, MSimdBinaryBitwise::and_);
3123 : case SimdOperation::Fn_or:
3124 0 : return EmitSimdBinary(f, type, MSimdBinaryBitwise::or_);
3125 : case SimdOperation::Fn_xor:
3126 0 : return EmitSimdBinary(f, type, MSimdBinaryBitwise::xor_);
3127 : #define _CASE(OP) \
3128 : case SimdOperation::Fn_##OP: \
3129 : return EmitSimdBinary(f, type, MSimdBinaryArith::Op_##OP);
3130 0 : FOREACH_NUMERIC_SIMD_BINOP(_CASE)
3131 0 : FOREACH_FLOAT_SIMD_BINOP(_CASE)
3132 : #undef _CASE
3133 : case SimdOperation::Fn_addSaturate:
3134 0 : return EmitSimdBinarySaturating(f, type, MSimdBinarySaturating::add, sign);
3135 : case SimdOperation::Fn_subSaturate:
3136 0 : return EmitSimdBinarySaturating(f, type, MSimdBinarySaturating::sub, sign);
3137 : case SimdOperation::Fn_fromFloat32x4:
3138 0 : return EmitSimdConvert(f, ValType::F32x4, type, sign);
3139 : case SimdOperation::Fn_fromInt32x4:
3140 0 : return EmitSimdConvert(f, ValType::I32x4, type, SimdSign::Signed);
3141 : case SimdOperation::Fn_fromUint32x4:
3142 0 : return EmitSimdConvert(f, ValType::I32x4, type, SimdSign::Unsigned);
3143 : case SimdOperation::Fn_fromInt8x16Bits:
3144 : case SimdOperation::Fn_fromUint8x16Bits:
3145 0 : return EmitSimdBitcast(f, ValType::I8x16, type);
3146 : case SimdOperation::Fn_fromUint16x8Bits:
3147 : case SimdOperation::Fn_fromInt16x8Bits:
3148 0 : return EmitSimdBitcast(f, ValType::I16x8, type);
3149 : case SimdOperation::Fn_fromInt32x4Bits:
3150 : case SimdOperation::Fn_fromUint32x4Bits:
3151 0 : return EmitSimdBitcast(f, ValType::I32x4, type);
3152 : case SimdOperation::Fn_fromFloat32x4Bits:
3153 0 : return EmitSimdBitcast(f, ValType::F32x4, type);
3154 : case SimdOperation::Fn_load3:
3155 : case SimdOperation::Fn_store3:
3156 : case SimdOperation::Fn_fromFloat64x2Bits:
3157 0 : MOZ_CRASH("NYI");
3158 : }
3159 0 : MOZ_CRASH("unexpected opcode");
3160 : }
3161 :
3162 : static bool
3163 0 : EmitGrowMemory(FunctionCompiler& f)
3164 : {
3165 0 : uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode();
3166 :
3167 0 : CallCompileState args(f, lineOrBytecode);
3168 0 : if (!f.startCall(&args))
3169 0 : return false;
3170 :
3171 0 : if (!f.passInstance(&args))
3172 0 : return false;
3173 :
3174 : MDefinition* delta;
3175 0 : if (!f.iter().readGrowMemory(&delta))
3176 0 : return false;
3177 :
3178 0 : if (!f.passArg(delta, ValType::I32, &args))
3179 0 : return false;
3180 :
3181 0 : f.finishCall(&args);
3182 :
3183 : MDefinition* ret;
3184 0 : if (!f.builtinInstanceMethodCall(SymbolicAddress::GrowMemory, args, ValType::I32, &ret))
3185 0 : return false;
3186 :
3187 0 : f.iter().setResult(ret);
3188 0 : return true;
3189 : }
3190 :
3191 : static bool
3192 0 : EmitCurrentMemory(FunctionCompiler& f)
3193 : {
3194 0 : uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode();
3195 :
3196 0 : CallCompileState args(f, lineOrBytecode);
3197 :
3198 0 : if (!f.iter().readCurrentMemory())
3199 0 : return false;
3200 :
3201 0 : if (!f.startCall(&args))
3202 0 : return false;
3203 :
3204 0 : if (!f.passInstance(&args))
3205 0 : return false;
3206 :
3207 0 : f.finishCall(&args);
3208 :
3209 : MDefinition* ret;
3210 0 : if (!f.builtinInstanceMethodCall(SymbolicAddress::CurrentMemory, args, ValType::I32, &ret))
3211 0 : return false;
3212 :
3213 0 : f.iter().setResult(ret);
3214 0 : return true;
3215 : }
3216 :
3217 : static bool
3218 0 : EmitBodyExprs(FunctionCompiler& f)
3219 : {
3220 0 : if (!f.iter().readFunctionStart(f.sig().ret()))
3221 0 : return false;
3222 :
3223 : #define CHECK(c) \
3224 : if (!(c)) \
3225 : return false; \
3226 : break
3227 :
3228 : #define CHECK_ASMJS(c) \
3229 : if (!f.env().isAsmJS()) \
3230 : return f.iter().unrecognizedOpcode(&op); \
3231 : if (!(c)) \
3232 : return false; \
3233 : break
3234 :
3235 : while (true) {
3236 0 : if (!f.mirGen().ensureBallast())
3237 0 : return false;
3238 :
3239 0 : OpBytes op;
3240 0 : if (!f.iter().readOp(&op))
3241 0 : return false;
3242 :
3243 0 : switch (op.b0) {
3244 : case uint16_t(Op::End):
3245 0 : if (!EmitEnd(f))
3246 0 : return false;
3247 :
3248 0 : if (f.iter().controlStackEmpty()) {
3249 0 : if (f.inDeadCode() || IsVoid(f.sig().ret()))
3250 0 : f.returnVoid();
3251 : else
3252 0 : f.returnExpr(f.iter().getResult());
3253 0 : return f.iter().readFunctionEnd(f.iter().end());
3254 : }
3255 0 : break;
3256 :
3257 : // Control opcodes
3258 : case uint16_t(Op::Unreachable):
3259 0 : CHECK(EmitUnreachable(f));
3260 : case uint16_t(Op::Nop):
3261 0 : CHECK(f.iter().readNop());
3262 : case uint16_t(Op::Block):
3263 0 : CHECK(EmitBlock(f));
3264 : case uint16_t(Op::Loop):
3265 0 : CHECK(EmitLoop(f));
3266 : case uint16_t(Op::If):
3267 0 : CHECK(EmitIf(f));
3268 : case uint16_t(Op::Else):
3269 0 : CHECK(EmitElse(f));
3270 : case uint16_t(Op::Br):
3271 0 : CHECK(EmitBr(f));
3272 : case uint16_t(Op::BrIf):
3273 0 : CHECK(EmitBrIf(f));
3274 : case uint16_t(Op::BrTable):
3275 0 : CHECK(EmitBrTable(f));
3276 : case uint16_t(Op::Return):
3277 0 : CHECK(EmitReturn(f));
3278 :
3279 : // Calls
3280 : case uint16_t(Op::Call):
3281 0 : CHECK(EmitCall(f));
3282 : case uint16_t(Op::CallIndirect):
3283 0 : CHECK(EmitCallIndirect(f, /* oldStyle = */ false));
3284 :
3285 : // Parametric operators
3286 : case uint16_t(Op::Drop):
3287 0 : CHECK(f.iter().readDrop());
3288 : case uint16_t(Op::Select):
3289 0 : CHECK(EmitSelect(f));
3290 :
3291 : // Locals and globals
3292 : case uint16_t(Op::GetLocal):
3293 0 : CHECK(EmitGetLocal(f));
3294 : case uint16_t(Op::SetLocal):
3295 0 : CHECK(EmitSetLocal(f));
3296 : case uint16_t(Op::TeeLocal):
3297 0 : CHECK(EmitTeeLocal(f));
3298 : case uint16_t(Op::GetGlobal):
3299 0 : CHECK(EmitGetGlobal(f));
3300 : case uint16_t(Op::SetGlobal):
3301 0 : CHECK(EmitSetGlobal(f));
3302 :
3303 : // Memory-related operators
3304 : case uint16_t(Op::I32Load):
3305 0 : CHECK(EmitLoad(f, ValType::I32, Scalar::Int32));
3306 : case uint16_t(Op::I64Load):
3307 0 : CHECK(EmitLoad(f, ValType::I64, Scalar::Int64));
3308 : case uint16_t(Op::F32Load):
3309 0 : CHECK(EmitLoad(f, ValType::F32, Scalar::Float32));
3310 : case uint16_t(Op::F64Load):
3311 0 : CHECK(EmitLoad(f, ValType::F64, Scalar::Float64));
3312 : case uint16_t(Op::I32Load8S):
3313 0 : CHECK(EmitLoad(f, ValType::I32, Scalar::Int8));
3314 : case uint16_t(Op::I32Load8U):
3315 0 : CHECK(EmitLoad(f, ValType::I32, Scalar::Uint8));
3316 : case uint16_t(Op::I32Load16S):
3317 0 : CHECK(EmitLoad(f, ValType::I32, Scalar::Int16));
3318 : case uint16_t(Op::I32Load16U):
3319 0 : CHECK(EmitLoad(f, ValType::I32, Scalar::Uint16));
3320 : case uint16_t(Op::I64Load8S):
3321 0 : CHECK(EmitLoad(f, ValType::I64, Scalar::Int8));
3322 : case uint16_t(Op::I64Load8U):
3323 0 : CHECK(EmitLoad(f, ValType::I64, Scalar::Uint8));
3324 : case uint16_t(Op::I64Load16S):
3325 0 : CHECK(EmitLoad(f, ValType::I64, Scalar::Int16));
3326 : case uint16_t(Op::I64Load16U):
3327 0 : CHECK(EmitLoad(f, ValType::I64, Scalar::Uint16));
3328 : case uint16_t(Op::I64Load32S):
3329 0 : CHECK(EmitLoad(f, ValType::I64, Scalar::Int32));
3330 : case uint16_t(Op::I64Load32U):
3331 0 : CHECK(EmitLoad(f, ValType::I64, Scalar::Uint32));
3332 : case uint16_t(Op::I32Store):
3333 0 : CHECK(EmitStore(f, ValType::I32, Scalar::Int32));
3334 : case uint16_t(Op::I64Store):
3335 0 : CHECK(EmitStore(f, ValType::I64, Scalar::Int64));
3336 : case uint16_t(Op::F32Store):
3337 0 : CHECK(EmitStore(f, ValType::F32, Scalar::Float32));
3338 : case uint16_t(Op::F64Store):
3339 0 : CHECK(EmitStore(f, ValType::F64, Scalar::Float64));
3340 : case uint16_t(Op::I32Store8):
3341 0 : CHECK(EmitStore(f, ValType::I32, Scalar::Int8));
3342 : case uint16_t(Op::I32Store16):
3343 0 : CHECK(EmitStore(f, ValType::I32, Scalar::Int16));
3344 : case uint16_t(Op::I64Store8):
3345 0 : CHECK(EmitStore(f, ValType::I64, Scalar::Int8));
3346 : case uint16_t(Op::I64Store16):
3347 0 : CHECK(EmitStore(f, ValType::I64, Scalar::Int16));
3348 : case uint16_t(Op::I64Store32):
3349 0 : CHECK(EmitStore(f, ValType::I64, Scalar::Int32));
3350 : case uint16_t(Op::CurrentMemory):
3351 0 : CHECK(EmitCurrentMemory(f));
3352 : case uint16_t(Op::GrowMemory):
3353 0 : CHECK(EmitGrowMemory(f));
3354 :
3355 : // Constants
3356 : case uint16_t(Op::I32Const):
3357 0 : CHECK(EmitI32Const(f));
3358 : case uint16_t(Op::I64Const):
3359 0 : CHECK(EmitI64Const(f));
3360 : case uint16_t(Op::F32Const):
3361 0 : CHECK(EmitF32Const(f));
3362 : case uint16_t(Op::F64Const):
3363 0 : CHECK(EmitF64Const(f));
3364 :
3365 : // Comparison operators
3366 : case uint16_t(Op::I32Eqz):
3367 0 : CHECK(EmitConversion<MNot>(f, ValType::I32, ValType::I32));
3368 : case uint16_t(Op::I32Eq):
3369 0 : CHECK(EmitComparison(f, ValType::I32, JSOP_EQ, MCompare::Compare_Int32));
3370 : case uint16_t(Op::I32Ne):
3371 0 : CHECK(EmitComparison(f, ValType::I32, JSOP_NE, MCompare::Compare_Int32));
3372 : case uint16_t(Op::I32LtS):
3373 0 : CHECK(EmitComparison(f, ValType::I32, JSOP_LT, MCompare::Compare_Int32));
3374 : case uint16_t(Op::I32LtU):
3375 0 : CHECK(EmitComparison(f, ValType::I32, JSOP_LT, MCompare::Compare_UInt32));
3376 : case uint16_t(Op::I32GtS):
3377 0 : CHECK(EmitComparison(f, ValType::I32, JSOP_GT, MCompare::Compare_Int32));
3378 : case uint16_t(Op::I32GtU):
3379 0 : CHECK(EmitComparison(f, ValType::I32, JSOP_GT, MCompare::Compare_UInt32));
3380 : case uint16_t(Op::I32LeS):
3381 0 : CHECK(EmitComparison(f, ValType::I32, JSOP_LE, MCompare::Compare_Int32));
3382 : case uint16_t(Op::I32LeU):
3383 0 : CHECK(EmitComparison(f, ValType::I32, JSOP_LE, MCompare::Compare_UInt32));
3384 : case uint16_t(Op::I32GeS):
3385 0 : CHECK(EmitComparison(f, ValType::I32, JSOP_GE, MCompare::Compare_Int32));
3386 : case uint16_t(Op::I32GeU):
3387 0 : CHECK(EmitComparison(f, ValType::I32, JSOP_GE, MCompare::Compare_UInt32));
3388 : case uint16_t(Op::I64Eqz):
3389 0 : CHECK(EmitConversion<MNot>(f, ValType::I64, ValType::I32));
3390 : case uint16_t(Op::I64Eq):
3391 0 : CHECK(EmitComparison(f, ValType::I64, JSOP_EQ, MCompare::Compare_Int64));
3392 : case uint16_t(Op::I64Ne):
3393 0 : CHECK(EmitComparison(f, ValType::I64, JSOP_NE, MCompare::Compare_Int64));
3394 : case uint16_t(Op::I64LtS):
3395 0 : CHECK(EmitComparison(f, ValType::I64, JSOP_LT, MCompare::Compare_Int64));
3396 : case uint16_t(Op::I64LtU):
3397 0 : CHECK(EmitComparison(f, ValType::I64, JSOP_LT, MCompare::Compare_UInt64));
3398 : case uint16_t(Op::I64GtS):
3399 0 : CHECK(EmitComparison(f, ValType::I64, JSOP_GT, MCompare::Compare_Int64));
3400 : case uint16_t(Op::I64GtU):
3401 0 : CHECK(EmitComparison(f, ValType::I64, JSOP_GT, MCompare::Compare_UInt64));
3402 : case uint16_t(Op::I64LeS):
3403 0 : CHECK(EmitComparison(f, ValType::I64, JSOP_LE, MCompare::Compare_Int64));
3404 : case uint16_t(Op::I64LeU):
3405 0 : CHECK(EmitComparison(f, ValType::I64, JSOP_LE, MCompare::Compare_UInt64));
3406 : case uint16_t(Op::I64GeS):
3407 0 : CHECK(EmitComparison(f, ValType::I64, JSOP_GE, MCompare::Compare_Int64));
3408 : case uint16_t(Op::I64GeU):
3409 0 : CHECK(EmitComparison(f, ValType::I64, JSOP_GE, MCompare::Compare_UInt64));
3410 : case uint16_t(Op::F32Eq):
3411 0 : CHECK(EmitComparison(f, ValType::F32, JSOP_EQ, MCompare::Compare_Float32));
3412 : case uint16_t(Op::F32Ne):
3413 0 : CHECK(EmitComparison(f, ValType::F32, JSOP_NE, MCompare::Compare_Float32));
3414 : case uint16_t(Op::F32Lt):
3415 0 : CHECK(EmitComparison(f, ValType::F32, JSOP_LT, MCompare::Compare_Float32));
3416 : case uint16_t(Op::F32Gt):
3417 0 : CHECK(EmitComparison(f, ValType::F32, JSOP_GT, MCompare::Compare_Float32));
3418 : case uint16_t(Op::F32Le):
3419 0 : CHECK(EmitComparison(f, ValType::F32, JSOP_LE, MCompare::Compare_Float32));
3420 : case uint16_t(Op::F32Ge):
3421 0 : CHECK(EmitComparison(f, ValType::F32, JSOP_GE, MCompare::Compare_Float32));
3422 : case uint16_t(Op::F64Eq):
3423 0 : CHECK(EmitComparison(f, ValType::F64, JSOP_EQ, MCompare::Compare_Double));
3424 : case uint16_t(Op::F64Ne):
3425 0 : CHECK(EmitComparison(f, ValType::F64, JSOP_NE, MCompare::Compare_Double));
3426 : case uint16_t(Op::F64Lt):
3427 0 : CHECK(EmitComparison(f, ValType::F64, JSOP_LT, MCompare::Compare_Double));
3428 : case uint16_t(Op::F64Gt):
3429 0 : CHECK(EmitComparison(f, ValType::F64, JSOP_GT, MCompare::Compare_Double));
3430 : case uint16_t(Op::F64Le):
3431 0 : CHECK(EmitComparison(f, ValType::F64, JSOP_LE, MCompare::Compare_Double));
3432 : case uint16_t(Op::F64Ge):
3433 0 : CHECK(EmitComparison(f, ValType::F64, JSOP_GE, MCompare::Compare_Double));
3434 :
3435 : // Numeric operators
3436 : case uint16_t(Op::I32Clz):
3437 0 : CHECK(EmitUnaryWithType<MClz>(f, ValType::I32, MIRType::Int32));
3438 : case uint16_t(Op::I32Ctz):
3439 0 : CHECK(EmitUnaryWithType<MCtz>(f, ValType::I32, MIRType::Int32));
3440 : case uint16_t(Op::I32Popcnt):
3441 0 : CHECK(EmitUnaryWithType<MPopcnt>(f, ValType::I32, MIRType::Int32));
3442 : case uint16_t(Op::I32Add):
3443 0 : CHECK(EmitAdd(f, ValType::I32, MIRType::Int32));
3444 : case uint16_t(Op::I32Sub):
3445 0 : CHECK(EmitSub(f, ValType::I32, MIRType::Int32));
3446 : case uint16_t(Op::I32Mul):
3447 0 : CHECK(EmitMul(f, ValType::I32, MIRType::Int32));
3448 : case uint16_t(Op::I32DivS):
3449 : case uint16_t(Op::I32DivU):
3450 0 : CHECK(EmitDiv(f, ValType::I32, MIRType::Int32, Op(op.b0) == Op::I32DivU));
3451 : case uint16_t(Op::I32RemS):
3452 : case uint16_t(Op::I32RemU):
3453 0 : CHECK(EmitRem(f, ValType::I32, MIRType::Int32, Op(op.b0) == Op::I32RemU));
3454 : case uint16_t(Op::I32And):
3455 0 : CHECK(EmitBitwise<MBitAnd>(f, ValType::I32, MIRType::Int32));
3456 : case uint16_t(Op::I32Or):
3457 0 : CHECK(EmitBitwise<MBitOr>(f, ValType::I32, MIRType::Int32));
3458 : case uint16_t(Op::I32Xor):
3459 0 : CHECK(EmitBitwise<MBitXor>(f, ValType::I32, MIRType::Int32));
3460 : case uint16_t(Op::I32Shl):
3461 0 : CHECK(EmitBitwise<MLsh>(f, ValType::I32, MIRType::Int32));
3462 : case uint16_t(Op::I32ShrS):
3463 0 : CHECK(EmitBitwise<MRsh>(f, ValType::I32, MIRType::Int32));
3464 : case uint16_t(Op::I32ShrU):
3465 0 : CHECK(EmitBitwise<MUrsh>(f, ValType::I32, MIRType::Int32));
3466 : case uint16_t(Op::I32Rotl):
3467 : case uint16_t(Op::I32Rotr):
3468 0 : CHECK(EmitRotate(f, ValType::I32, Op(op.b0) == Op::I32Rotl));
3469 : case uint16_t(Op::I64Clz):
3470 0 : CHECK(EmitUnaryWithType<MClz>(f, ValType::I64, MIRType::Int64));
3471 : case uint16_t(Op::I64Ctz):
3472 0 : CHECK(EmitUnaryWithType<MCtz>(f, ValType::I64, MIRType::Int64));
3473 : case uint16_t(Op::I64Popcnt):
3474 0 : CHECK(EmitUnaryWithType<MPopcnt>(f, ValType::I64, MIRType::Int64));
3475 : case uint16_t(Op::I64Add):
3476 0 : CHECK(EmitAdd(f, ValType::I64, MIRType::Int64));
3477 : case uint16_t(Op::I64Sub):
3478 0 : CHECK(EmitSub(f, ValType::I64, MIRType::Int64));
3479 : case uint16_t(Op::I64Mul):
3480 0 : CHECK(EmitMul(f, ValType::I64, MIRType::Int64));
3481 : case uint16_t(Op::I64DivS):
3482 : case uint16_t(Op::I64DivU):
3483 0 : CHECK(EmitDiv(f, ValType::I64, MIRType::Int64, Op(op.b0) == Op::I64DivU));
3484 : case uint16_t(Op::I64RemS):
3485 : case uint16_t(Op::I64RemU):
3486 0 : CHECK(EmitRem(f, ValType::I64, MIRType::Int64, Op(op.b0) == Op::I64RemU));
3487 : case uint16_t(Op::I64And):
3488 0 : CHECK(EmitBitwise<MBitAnd>(f, ValType::I64, MIRType::Int64));
3489 : case uint16_t(Op::I64Or):
3490 0 : CHECK(EmitBitwise<MBitOr>(f, ValType::I64, MIRType::Int64));
3491 : case uint16_t(Op::I64Xor):
3492 0 : CHECK(EmitBitwise<MBitXor>(f, ValType::I64, MIRType::Int64));
3493 : case uint16_t(Op::I64Shl):
3494 0 : CHECK(EmitBitwise<MLsh>(f, ValType::I64, MIRType::Int64));
3495 : case uint16_t(Op::I64ShrS):
3496 0 : CHECK(EmitBitwise<MRsh>(f, ValType::I64, MIRType::Int64));
3497 : case uint16_t(Op::I64ShrU):
3498 0 : CHECK(EmitBitwise<MUrsh>(f, ValType::I64, MIRType::Int64));
3499 : case uint16_t(Op::I64Rotl):
3500 : case uint16_t(Op::I64Rotr):
3501 0 : CHECK(EmitRotate(f, ValType::I64, Op(op.b0) == Op::I64Rotl));
3502 : case uint16_t(Op::F32Abs):
3503 0 : CHECK(EmitUnaryWithType<MAbs>(f, ValType::F32, MIRType::Float32));
3504 : case uint16_t(Op::F32Neg):
3505 0 : CHECK(EmitUnaryWithType<MWasmNeg>(f, ValType::F32, MIRType::Float32));
3506 : case uint16_t(Op::F32Ceil):
3507 0 : CHECK(EmitUnaryMathBuiltinCall(f, SymbolicAddress::CeilF, ValType::F32));
3508 : case uint16_t(Op::F32Floor):
3509 0 : CHECK(EmitUnaryMathBuiltinCall(f, SymbolicAddress::FloorF, ValType::F32));
3510 : case uint16_t(Op::F32Trunc):
3511 0 : CHECK(EmitUnaryMathBuiltinCall(f, SymbolicAddress::TruncF, ValType::F32));
3512 : case uint16_t(Op::F32Nearest):
3513 0 : CHECK(EmitUnaryMathBuiltinCall(f, SymbolicAddress::NearbyIntF, ValType::F32));
3514 : case uint16_t(Op::F32Sqrt):
3515 0 : CHECK(EmitUnaryWithType<MSqrt>(f, ValType::F32, MIRType::Float32));
3516 : case uint16_t(Op::F32Add):
3517 0 : CHECK(EmitAdd(f, ValType::F32, MIRType::Float32));
3518 : case uint16_t(Op::F32Sub):
3519 0 : CHECK(EmitSub(f, ValType::F32, MIRType::Float32));
3520 : case uint16_t(Op::F32Mul):
3521 0 : CHECK(EmitMul(f, ValType::F32, MIRType::Float32));
3522 : case uint16_t(Op::F32Div):
3523 0 : CHECK(EmitDiv(f, ValType::F32, MIRType::Float32, /* isUnsigned = */ false));
3524 : case uint16_t(Op::F32Min):
3525 : case uint16_t(Op::F32Max):
3526 0 : CHECK(EmitMinMax(f, ValType::F32, MIRType::Float32, Op(op.b0) == Op::F32Max));
3527 : case uint16_t(Op::F32CopySign):
3528 0 : CHECK(EmitCopySign(f, ValType::F32));
3529 : case uint16_t(Op::F64Abs):
3530 0 : CHECK(EmitUnaryWithType<MAbs>(f, ValType::F64, MIRType::Double));
3531 : case uint16_t(Op::F64Neg):
3532 0 : CHECK(EmitUnaryWithType<MWasmNeg>(f, ValType::F64, MIRType::Double));
3533 : case uint16_t(Op::F64Ceil):
3534 0 : CHECK(EmitUnaryMathBuiltinCall(f, SymbolicAddress::CeilD, ValType::F64));
3535 : case uint16_t(Op::F64Floor):
3536 0 : CHECK(EmitUnaryMathBuiltinCall(f, SymbolicAddress::FloorD, ValType::F64));
3537 : case uint16_t(Op::F64Trunc):
3538 0 : CHECK(EmitUnaryMathBuiltinCall(f, SymbolicAddress::TruncD, ValType::F64));
3539 : case uint16_t(Op::F64Nearest):
3540 0 : CHECK(EmitUnaryMathBuiltinCall(f, SymbolicAddress::NearbyIntD, ValType::F64));
3541 : case uint16_t(Op::F64Sqrt):
3542 0 : CHECK(EmitUnaryWithType<MSqrt>(f, ValType::F64, MIRType::Double));
3543 : case uint16_t(Op::F64Add):
3544 0 : CHECK(EmitAdd(f, ValType::F64, MIRType::Double));
3545 : case uint16_t(Op::F64Sub):
3546 0 : CHECK(EmitSub(f, ValType::F64, MIRType::Double));
3547 : case uint16_t(Op::F64Mul):
3548 0 : CHECK(EmitMul(f, ValType::F64, MIRType::Double));
3549 : case uint16_t(Op::F64Div):
3550 0 : CHECK(EmitDiv(f, ValType::F64, MIRType::Double, /* isUnsigned = */ false));
3551 : case uint16_t(Op::F64Min):
3552 : case uint16_t(Op::F64Max):
3553 0 : CHECK(EmitMinMax(f, ValType::F64, MIRType::Double, Op(op.b0) == Op::F64Max));
3554 : case uint16_t(Op::F64CopySign):
3555 0 : CHECK(EmitCopySign(f, ValType::F64));
3556 :
3557 : // Conversions
3558 : case uint16_t(Op::I32WrapI64):
3559 0 : CHECK(EmitConversion<MWrapInt64ToInt32>(f, ValType::I64, ValType::I32));
3560 : case uint16_t(Op::I32TruncSF32):
3561 : case uint16_t(Op::I32TruncUF32):
3562 0 : CHECK(EmitTruncate(f, ValType::F32, ValType::I32, Op(op.b0) == Op::I32TruncUF32));
3563 : case uint16_t(Op::I32TruncSF64):
3564 : case uint16_t(Op::I32TruncUF64):
3565 0 : CHECK(EmitTruncate(f, ValType::F64, ValType::I32, Op(op.b0) == Op::I32TruncUF64));
3566 : case uint16_t(Op::I64ExtendSI32):
3567 : case uint16_t(Op::I64ExtendUI32):
3568 0 : CHECK(EmitExtendI32(f, Op(op.b0) == Op::I64ExtendUI32));
3569 : case uint16_t(Op::I64TruncSF32):
3570 : case uint16_t(Op::I64TruncUF32):
3571 0 : CHECK(EmitTruncate(f, ValType::F32, ValType::I64, Op(op.b0) == Op::I64TruncUF32));
3572 : case uint16_t(Op::I64TruncSF64):
3573 : case uint16_t(Op::I64TruncUF64):
3574 0 : CHECK(EmitTruncate(f, ValType::F64, ValType::I64, Op(op.b0) == Op::I64TruncUF64));
3575 : case uint16_t(Op::F32ConvertSI32):
3576 0 : CHECK(EmitConversion<MToFloat32>(f, ValType::I32, ValType::F32));
3577 : case uint16_t(Op::F32ConvertUI32):
3578 0 : CHECK(EmitConversion<MWasmUnsignedToFloat32>(f, ValType::I32, ValType::F32));
3579 : case uint16_t(Op::F32ConvertSI64):
3580 : case uint16_t(Op::F32ConvertUI64):
3581 0 : CHECK(EmitConvertI64ToFloatingPoint(f, ValType::F32, MIRType::Float32, Op(op.b0) == Op::F32ConvertUI64));
3582 : case uint16_t(Op::F32DemoteF64):
3583 0 : CHECK(EmitConversion<MToFloat32>(f, ValType::F64, ValType::F32));
3584 : case uint16_t(Op::F64ConvertSI32):
3585 0 : CHECK(EmitConversion<MToDouble>(f, ValType::I32, ValType::F64));
3586 : case uint16_t(Op::F64ConvertUI32):
3587 0 : CHECK(EmitConversion<MWasmUnsignedToDouble>(f, ValType::I32, ValType::F64));
3588 : case uint16_t(Op::F64ConvertSI64):
3589 : case uint16_t(Op::F64ConvertUI64):
3590 0 : CHECK(EmitConvertI64ToFloatingPoint(f, ValType::F64, MIRType::Double, Op(op.b0) == Op::F64ConvertUI64));
3591 : case uint16_t(Op::F64PromoteF32):
3592 0 : CHECK(EmitConversion<MToDouble>(f, ValType::F32, ValType::F64));
3593 :
3594 : // Reinterpretations
3595 : case uint16_t(Op::I32ReinterpretF32):
3596 0 : CHECK(EmitReinterpret(f, ValType::I32, ValType::F32, MIRType::Int32));
3597 : case uint16_t(Op::I64ReinterpretF64):
3598 0 : CHECK(EmitReinterpret(f, ValType::I64, ValType::F64, MIRType::Int64));
3599 : case uint16_t(Op::F32ReinterpretI32):
3600 0 : CHECK(EmitReinterpret(f, ValType::F32, ValType::I32, MIRType::Float32));
3601 : case uint16_t(Op::F64ReinterpretI64):
3602 0 : CHECK(EmitReinterpret(f, ValType::F64, ValType::I64, MIRType::Double));
3603 :
3604 : // asm.js-specific operators
3605 :
3606 : case uint16_t(Op::MozPrefix): {
3607 0 : switch (op.b1) {
3608 : case uint16_t(MozOp::TeeGlobal):
3609 0 : CHECK_ASMJS(EmitTeeGlobal(f));
3610 : case uint16_t(MozOp::I32Min):
3611 : case uint16_t(MozOp::I32Max):
3612 0 : CHECK_ASMJS(EmitMinMax(f, ValType::I32, MIRType::Int32, MozOp(op.b1) == MozOp::I32Max));
3613 : case uint16_t(MozOp::I32Neg):
3614 0 : CHECK_ASMJS(EmitUnaryWithType<MWasmNeg>(f, ValType::I32, MIRType::Int32));
3615 : case uint16_t(MozOp::I32BitNot):
3616 0 : CHECK_ASMJS(EmitBitNot(f, ValType::I32));
3617 : case uint16_t(MozOp::I32Abs):
3618 0 : CHECK_ASMJS(EmitUnaryWithType<MAbs>(f, ValType::I32, MIRType::Int32));
3619 : case uint16_t(MozOp::F32TeeStoreF64):
3620 0 : CHECK_ASMJS(EmitTeeStoreWithCoercion(f, ValType::F32, Scalar::Float64));
3621 : case uint16_t(MozOp::F64TeeStoreF32):
3622 0 : CHECK_ASMJS(EmitTeeStoreWithCoercion(f, ValType::F64, Scalar::Float32));
3623 : case uint16_t(MozOp::I32TeeStore8):
3624 0 : CHECK_ASMJS(EmitTeeStore(f, ValType::I32, Scalar::Int8));
3625 : case uint16_t(MozOp::I32TeeStore16):
3626 0 : CHECK_ASMJS(EmitTeeStore(f, ValType::I32, Scalar::Int16));
3627 : case uint16_t(MozOp::I64TeeStore8):
3628 0 : CHECK_ASMJS(EmitTeeStore(f, ValType::I64, Scalar::Int8));
3629 : case uint16_t(MozOp::I64TeeStore16):
3630 0 : CHECK_ASMJS(EmitTeeStore(f, ValType::I64, Scalar::Int16));
3631 : case uint16_t(MozOp::I64TeeStore32):
3632 0 : CHECK_ASMJS(EmitTeeStore(f, ValType::I64, Scalar::Int32));
3633 : case uint16_t(MozOp::I32TeeStore):
3634 0 : CHECK_ASMJS(EmitTeeStore(f, ValType::I32, Scalar::Int32));
3635 : case uint16_t(MozOp::I64TeeStore):
3636 0 : CHECK_ASMJS(EmitTeeStore(f, ValType::I64, Scalar::Int64));
3637 : case uint16_t(MozOp::F32TeeStore):
3638 0 : CHECK_ASMJS(EmitTeeStore(f, ValType::F32, Scalar::Float32));
3639 : case uint16_t(MozOp::F64TeeStore):
3640 0 : CHECK_ASMJS(EmitTeeStore(f, ValType::F64, Scalar::Float64));
3641 : case uint16_t(MozOp::F64Mod):
3642 0 : CHECK_ASMJS(EmitRem(f, ValType::F64, MIRType::Double, /* isUnsigned = */ false));
3643 : case uint16_t(MozOp::F64Sin):
3644 0 : CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::SinD, ValType::F64));
3645 : case uint16_t(MozOp::F64Cos):
3646 0 : CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::CosD, ValType::F64));
3647 : case uint16_t(MozOp::F64Tan):
3648 0 : CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::TanD, ValType::F64));
3649 : case uint16_t(MozOp::F64Asin):
3650 0 : CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::ASinD, ValType::F64));
3651 : case uint16_t(MozOp::F64Acos):
3652 0 : CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::ACosD, ValType::F64));
3653 : case uint16_t(MozOp::F64Atan):
3654 0 : CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::ATanD, ValType::F64));
3655 : case uint16_t(MozOp::F64Exp):
3656 0 : CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::ExpD, ValType::F64));
3657 : case uint16_t(MozOp::F64Log):
3658 0 : CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::LogD, ValType::F64));
3659 : case uint16_t(MozOp::F64Pow):
3660 0 : CHECK_ASMJS(EmitBinaryMathBuiltinCall(f, SymbolicAddress::PowD, ValType::F64));
3661 : case uint16_t(MozOp::F64Atan2):
3662 0 : CHECK_ASMJS(EmitBinaryMathBuiltinCall(f, SymbolicAddress::ATan2D, ValType::F64));
3663 : case uint16_t(MozOp::OldCallIndirect):
3664 0 : CHECK_ASMJS(EmitCallIndirect(f, /* oldStyle = */ true));
3665 :
3666 : // Atomics
3667 : case uint16_t(MozOp::I32AtomicsLoad):
3668 0 : CHECK_ASMJS(EmitAtomicsLoad(f));
3669 : case uint16_t(MozOp::I32AtomicsStore):
3670 0 : CHECK_ASMJS(EmitAtomicsStore(f));
3671 : case uint16_t(MozOp::I32AtomicsBinOp):
3672 0 : CHECK_ASMJS(EmitAtomicsBinOp(f));
3673 : case uint16_t(MozOp::I32AtomicsCompareExchange):
3674 0 : CHECK_ASMJS(EmitAtomicsCompareExchange(f));
3675 : case uint16_t(MozOp::I32AtomicsExchange):
3676 0 : CHECK_ASMJS(EmitAtomicsExchange(f));
3677 :
3678 : // SIMD
3679 : #define CASE(TYPE, OP, SIGN) \
3680 : case uint16_t(MozOp::TYPE##OP): \
3681 : CHECK_ASMJS(EmitSimdOp(f, ValType::TYPE, SimdOperation::Fn_##OP, SIGN));
3682 : #define I8x16CASE(OP) CASE(I8x16, OP, SimdSign::Signed)
3683 : #define I16x8CASE(OP) CASE(I16x8, OP, SimdSign::Signed)
3684 : #define I32x4CASE(OP) CASE(I32x4, OP, SimdSign::Signed)
3685 : #define F32x4CASE(OP) CASE(F32x4, OP, SimdSign::NotApplicable)
3686 : #define B8x16CASE(OP) CASE(B8x16, OP, SimdSign::NotApplicable)
3687 : #define B16x8CASE(OP) CASE(B16x8, OP, SimdSign::NotApplicable)
3688 : #define B32x4CASE(OP) CASE(B32x4, OP, SimdSign::NotApplicable)
3689 : #define ENUMERATE(TYPE, FORALL, DO) \
3690 : case uint16_t(MozOp::TYPE##Constructor): \
3691 : CHECK_ASMJS(EmitSimdOp(f, ValType::TYPE, SimdOperation::Constructor, SimdSign::NotApplicable)); \
3692 : FORALL(DO)
3693 :
3694 0 : ENUMERATE(I8x16, FORALL_INT8X16_ASMJS_OP, I8x16CASE)
3695 0 : ENUMERATE(I16x8, FORALL_INT16X8_ASMJS_OP, I16x8CASE)
3696 0 : ENUMERATE(I32x4, FORALL_INT32X4_ASMJS_OP, I32x4CASE)
3697 0 : ENUMERATE(F32x4, FORALL_FLOAT32X4_ASMJS_OP, F32x4CASE)
3698 0 : ENUMERATE(B8x16, FORALL_BOOL_SIMD_OP, B8x16CASE)
3699 0 : ENUMERATE(B16x8, FORALL_BOOL_SIMD_OP, B16x8CASE)
3700 0 : ENUMERATE(B32x4, FORALL_BOOL_SIMD_OP, B32x4CASE)
3701 :
3702 : #undef CASE
3703 : #undef I8x16CASE
3704 : #undef I16x8CASE
3705 : #undef I32x4CASE
3706 : #undef F32x4CASE
3707 : #undef B8x16CASE
3708 : #undef B16x8CASE
3709 : #undef B32x4CASE
3710 : #undef ENUMERATE
3711 :
3712 : case uint16_t(MozOp::I8x16Const):
3713 0 : CHECK_ASMJS(EmitI8x16Const(f));
3714 : case uint16_t(MozOp::I16x8Const):
3715 0 : CHECK_ASMJS(EmitI16x8Const(f));
3716 : case uint16_t(MozOp::I32x4Const):
3717 0 : CHECK_ASMJS(EmitI32x4Const(f));
3718 : case uint16_t(MozOp::F32x4Const):
3719 0 : CHECK_ASMJS(EmitF32x4Const(f));
3720 : case uint16_t(MozOp::B8x16Const):
3721 0 : CHECK_ASMJS(EmitB8x16Const(f));
3722 : case uint16_t(MozOp::B16x8Const):
3723 0 : CHECK_ASMJS(EmitB16x8Const(f));
3724 : case uint16_t(MozOp::B32x4Const):
3725 0 : CHECK_ASMJS(EmitB32x4Const(f));
3726 :
3727 : case uint16_t(MozOp::I8x16addSaturateU):
3728 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_addSaturate, SimdSign::Unsigned));
3729 : case uint16_t(MozOp::I8x16subSaturateU):
3730 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_subSaturate, SimdSign::Unsigned));
3731 : case uint16_t(MozOp::I8x16shiftRightByScalarU):
3732 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_shiftRightByScalar, SimdSign::Unsigned));
3733 : case uint16_t(MozOp::I8x16lessThanU):
3734 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_lessThan, SimdSign::Unsigned));
3735 : case uint16_t(MozOp::I8x16lessThanOrEqualU):
3736 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_lessThanOrEqual, SimdSign::Unsigned));
3737 : case uint16_t(MozOp::I8x16greaterThanU):
3738 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_greaterThan, SimdSign::Unsigned));
3739 : case uint16_t(MozOp::I8x16greaterThanOrEqualU):
3740 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_greaterThanOrEqual, SimdSign::Unsigned));
3741 : case uint16_t(MozOp::I8x16extractLaneU):
3742 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_extractLane, SimdSign::Unsigned));
3743 :
3744 : case uint16_t(MozOp::I16x8addSaturateU):
3745 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_addSaturate, SimdSign::Unsigned));
3746 : case uint16_t(MozOp::I16x8subSaturateU):
3747 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_subSaturate, SimdSign::Unsigned));
3748 : case uint16_t(MozOp::I16x8shiftRightByScalarU):
3749 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_shiftRightByScalar, SimdSign::Unsigned));
3750 : case uint16_t(MozOp::I16x8lessThanU):
3751 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_lessThan, SimdSign::Unsigned));
3752 : case uint16_t(MozOp::I16x8lessThanOrEqualU):
3753 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_lessThanOrEqual, SimdSign::Unsigned));
3754 : case uint16_t(MozOp::I16x8greaterThanU):
3755 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_greaterThan, SimdSign::Unsigned));
3756 : case uint16_t(MozOp::I16x8greaterThanOrEqualU):
3757 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_greaterThanOrEqual, SimdSign::Unsigned));
3758 : case uint16_t(MozOp::I16x8extractLaneU):
3759 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_extractLane, SimdSign::Unsigned));
3760 :
3761 : case uint16_t(MozOp::I32x4shiftRightByScalarU):
3762 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_shiftRightByScalar, SimdSign::Unsigned));
3763 : case uint16_t(MozOp::I32x4lessThanU):
3764 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_lessThan, SimdSign::Unsigned));
3765 : case uint16_t(MozOp::I32x4lessThanOrEqualU):
3766 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_lessThanOrEqual, SimdSign::Unsigned));
3767 : case uint16_t(MozOp::I32x4greaterThanU):
3768 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_greaterThan, SimdSign::Unsigned));
3769 : case uint16_t(MozOp::I32x4greaterThanOrEqualU):
3770 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_greaterThanOrEqual, SimdSign::Unsigned));
3771 : case uint16_t(MozOp::I32x4fromFloat32x4U):
3772 0 : CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_fromFloat32x4, SimdSign::Unsigned));
3773 :
3774 : default:
3775 0 : return f.iter().unrecognizedOpcode(&op);
3776 : }
3777 0 : break;
3778 : }
3779 :
3780 : default:
3781 0 : return f.iter().unrecognizedOpcode(&op);
3782 : }
3783 0 : }
3784 :
3785 : MOZ_CRASH("unreachable");
3786 :
3787 : #undef CHECK
3788 : #undef CHECK_ASMJS
3789 : }
3790 :
3791 : bool
3792 0 : wasm::IonCompileFunction(CompileTask* task, FuncCompileUnit* unit, UniqueChars* error)
3793 : {
3794 0 : MOZ_ASSERT(task->tier() == Tier::Ion);
3795 :
3796 0 : const FuncBytes& func = unit->func();
3797 0 : const ModuleEnvironment& env = task->env();
3798 :
3799 0 : Decoder d(func.bytes().begin(), func.bytes().end(), func.lineOrBytecode(), error);
3800 :
3801 : // Build the local types vector.
3802 :
3803 0 : ValTypeVector locals;
3804 0 : if (!locals.appendAll(func.sig().args()))
3805 0 : return false;
3806 0 : if (!DecodeLocalEntries(d, env.kind, &locals))
3807 0 : return false;
3808 :
3809 : // Set up for Ion compilation.
3810 :
3811 0 : JitContext jitContext(&task->alloc());
3812 0 : const JitCompileOptions options;
3813 0 : MIRGraph graph(&task->alloc());
3814 0 : CompileInfo compileInfo(locals.length());
3815 0 : MIRGenerator mir(nullptr, options, &task->alloc(), &graph, &compileInfo,
3816 0 : IonOptimizations.get(OptimizationLevel::Wasm));
3817 0 : mir.initMinWasmHeapLength(env.minMemoryLength);
3818 :
3819 : // Build MIR graph
3820 : {
3821 0 : FunctionCompiler f(env, d, func, locals, mir);
3822 0 : if (!f.init())
3823 0 : return false;
3824 :
3825 0 : if (!f.startBlock())
3826 0 : return false;
3827 :
3828 0 : if (!EmitBodyExprs(f))
3829 0 : return false;
3830 :
3831 0 : f.finish();
3832 : }
3833 :
3834 : // Compile MIR graph
3835 : {
3836 0 : jit::SpewBeginFunction(&mir, nullptr);
3837 0 : jit::AutoSpewEndFunction spewEndFunction(&mir);
3838 :
3839 0 : if (!OptimizeMIR(&mir))
3840 0 : return false;
3841 :
3842 0 : LIRGraph* lir = GenerateLIR(&mir);
3843 0 : if (!lir)
3844 0 : return false;
3845 :
3846 0 : SigIdDesc sigId = env.funcSigs[func.index()]->id;
3847 :
3848 0 : CodeGenerator codegen(&mir, lir, &task->masm());
3849 :
3850 0 : BytecodeOffset prologueTrapOffset(func.lineOrBytecode());
3851 0 : FuncOffsets offsets;
3852 0 : if (!codegen.generateWasm(sigId, prologueTrapOffset, &offsets))
3853 0 : return false;
3854 :
3855 0 : unit->finish(offsets);
3856 : }
3857 :
3858 0 : return true;
3859 : }
|